diff --git a/CHANGELOG.md b/CHANGELOG.md index da3837c..089393c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,9 @@ Released on FIXME: ?? - **Status bar improvements** - "Show hidden files" in status bar - Status bar has now been splitted into two, one for each explorer tab + - **Error message if terminal window is too small** + - If the terminal window has less than 24 lines, then an error message is displayed in the auth activity + - Changed auth layout to absolute sizes - Bugfix: - Fixed broken input cursor when typing UTF8 characters (tui-realm 0.3.2) - Fixed [Issue 44](https://github.com/veeso/termscp/issues/44): Could not move files to other paths in FTP diff --git a/src/host/mod.rs b/src/host/mod.rs index 77d6bf6..c2a6821 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -831,7 +831,9 @@ mod tests { use crate::utils::test_helpers::{make_dir_at, make_file_at}; use pretty_assertions::assert_eq; + #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] use std::fs::File; + #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] use std::io::Write; #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] diff --git a/src/ui/activities/auth/misc.rs b/src/ui/activities/auth/misc.rs index acda009..1145ddc 100644 --- a/src/ui/activities/auth/misc.rs +++ b/src/ui/activities/auth/misc.rs @@ -68,4 +68,16 @@ impl AuthActivity { pub(super) fn is_port_standard(port: u16) -> bool { port < 1024 } + + /// ### check_minimum_window_size + /// + /// Check minimum window size window + pub(super) fn check_minimum_window_size(&mut self, height: u16) { + if height < 24 { + // Mount window error + self.mount_size_err(); + } else { + self.umount_size_err(); + } + } } diff --git a/src/ui/activities/auth/mod.rs b/src/ui/activities/auth/mod.rs index cf400af..76be0e0 100644 --- a/src/ui/activities/auth/mod.rs +++ b/src/ui/activities/auth/mod.rs @@ -43,6 +43,7 @@ use crate::ui::context::FileTransferParams; use crate::utils::git; // Includes +use crossterm::event::Event; use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; use tuirealm::{Update, View}; @@ -53,6 +54,7 @@ const COMPONENT_TEXT_NEW_VERSION: &str = "TEXT_NEW_VERSION"; const COMPONENT_TEXT_FOOTER: &str = "TEXT_FOOTER"; const COMPONENT_TEXT_HELP: &str = "TEXT_HELP"; const COMPONENT_TEXT_ERROR: &str = "TEXT_ERROR"; +const COMPONENT_TEXT_SIZE_ERR: &str = "TEXT_SIZE_ERR"; const COMPONENT_INPUT_ADDR: &str = "INPUT_ADDRESS"; const COMPONENT_INPUT_PORT: &str = "INPUT_PORT"; const COMPONENT_INPUT_USERNAME: &str = "INPUT_USERNAME"; @@ -199,6 +201,10 @@ impl Activity for AuthActivity { if let Ok(Some(event)) = self.context.as_ref().unwrap().input_hnd.read_event() { // Set redraw to true self.redraw = true; + // Handle on resize + if let Event::Resize(_, h) = event { + self.check_minimum_window_size(h); + } // Handle event on view and update let msg = self.view.on(event); self.update(msg); diff --git a/src/ui/activities/auth/update.rs b/src/ui/activities/auth/update.rs index dd8c1f2..23971bb 100644 --- a/src/ui/activities/auth/update.rs +++ b/src/ui/activities/auth/update.rs @@ -32,7 +32,7 @@ use super::{ COMPONENT_INPUT_PORT, COMPONENT_INPUT_USERNAME, COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK, COMPONENT_RADIO_BOOKMARK_DEL_RECENT, COMPONENT_RADIO_BOOKMARK_SAVE_PWD, COMPONENT_RADIO_PROTOCOL, COMPONENT_RADIO_QUIT, COMPONENT_RECENTS_LIST, COMPONENT_TEXT_ERROR, - COMPONENT_TEXT_HELP, + COMPONENT_TEXT_HELP, COMPONENT_TEXT_SIZE_ERR, }; use crate::ui::keymap::*; use tuirealm::components::InputPropsBuilder; @@ -306,6 +306,8 @@ impl Update for AuthActivity { self.umount_quit(); None } + // -- text size error; block everything + (COMPONENT_TEXT_SIZE_ERR, _) => None, // On submit on any unhandled (connect) (_, Msg::OnSubmit(_)) | (_, &MSG_KEY_ENTER) => { // Match key for all other components diff --git a/src/ui/activities/auth/view.rs b/src/ui/activities/auth/view.rs index af13594..eb55543 100644 --- a/src/ui/activities/auth/view.rs +++ b/src/ui/activities/auth/view.rs @@ -234,14 +234,17 @@ impl AuthActivity { pub(super) fn view(&mut self) { let mut ctx: Context = self.context.take().unwrap(); let _ = ctx.terminal.draw(|f| { + // Check window size + let height: u16 = f.size().height; + self.check_minimum_window_size(height); // Prepare chunks let chunks = Layout::default() .direction(Direction::Vertical) .margin(1) .constraints( [ - Constraint::Percentage(70), // Auth Form - Constraint::Percentage(30), // Bookmarks + Constraint::Length(21), // Auth Form + Constraint::Min(3), // Bookmarks ] .as_ref(), ) @@ -303,6 +306,14 @@ impl AuthActivity { self.view.render(super::COMPONENT_TEXT_ERROR, f, popup); } } + if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_SIZE_ERR) { + if props.visible { + let popup = draw_area_in(f.size(), 80, 20); + f.render_widget(Clear, popup); + // make popup + self.view.render(super::COMPONENT_TEXT_SIZE_ERR, f, popup); + } + } if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_QUIT) { if props.visible { // make popup @@ -478,6 +489,38 @@ impl AuthActivity { self.view.umount(super::COMPONENT_TEXT_ERROR); } + /// ### mount_size_err + /// + /// Mount size error + pub(super) fn mount_size_err(&mut self) { + // Mount + self.view.mount( + super::COMPONENT_TEXT_SIZE_ERR, + Box::new(MsgBox::new( + MsgBoxPropsBuilder::default() + .with_foreground(Color::Red) + .with_borders(Borders::ALL, BorderType::Thick, Color::Red) + .bold() + .with_texts( + None, + vec![TextSpan::from( + "termscp requires at least 24 lines of height to run", + )], + ) + .build(), + )), + ); + // Give focus to error + self.view.active(super::COMPONENT_TEXT_SIZE_ERR); + } + + /// ### umount_size_err + /// + /// Umount error size error + pub(super) fn umount_size_err(&mut self) { + self.view.umount(super::COMPONENT_TEXT_SIZE_ERR); + } + /// ### mount_quit /// /// Mount quit popup