diff --git a/src/activity_manager.rs b/src/activity_manager.rs index 4fc21e5..99cac71 100644 --- a/src/activity_manager.rs +++ b/src/activity_manager.rs @@ -97,14 +97,17 @@ impl ActivityManager { entry_directory: Option, ) { // Put params into the context - self.context.as_mut().unwrap().ft_params = Some(FileTransferParams { - address, - port, - protocol, - username, - password, - entry_directory, - }); + self.context + .as_mut() + .unwrap() + .set_ftparams(FileTransferParams { + address, + port, + protocol, + username, + password, + entry_directory, + }); } /// ### run @@ -202,7 +205,7 @@ impl ActivityManager { } }; // If ft params is None, return None - let ft_params: &FileTransferParams = match ctx.ft_params.as_ref() { + let ft_params: &FileTransferParams = match ctx.ft_params() { Some(ft_params) => &ft_params, None => { error!("Failed to start FileTransferActivity: file transfer params is None"); diff --git a/src/ui/activities/auth/mod.rs b/src/ui/activities/auth/mod.rs index e71d997..72121e2 100644 --- a/src/ui/activities/auth/mod.rs +++ b/src/ui/activities/auth/mod.rs @@ -111,23 +111,24 @@ impl AuthActivity { fn check_for_updates(&mut self) { debug!("Check for updates..."); // Check version only if unset in the store - let ctx: &mut Context = self.context.as_mut().unwrap(); - if !ctx.store.isset(STORE_KEY_LATEST_VERSION) { + let ctx: &mut Context = self.context_mut(); + if !ctx.store().isset(STORE_KEY_LATEST_VERSION) { debug!("Version is not set in storage"); - if ctx.config_client.get_check_for_updates() { + if ctx.config().get_check_for_updates() { debug!("Check for updates is enabled"); // Send request match git::check_for_updates(env!("CARGO_PKG_VERSION")) { Ok(Some(git::GithubTag { tag_name, body })) => { // If some, store version and release notes info!("Latest version is: {}", tag_name); - ctx.store.set_string(STORE_KEY_LATEST_VERSION, tag_name); - ctx.store.set_string(STORE_KEY_RELEASE_NOTES, body); + ctx.store_mut() + .set_string(STORE_KEY_LATEST_VERSION, tag_name); + ctx.store_mut().set_string(STORE_KEY_RELEASE_NOTES, body); } Ok(None) => { info!("Latest version is: {} (current)", env!("CARGO_PKG_VERSION")); // Just set flag as check - ctx.store.set(STORE_KEY_LATEST_VERSION); + ctx.store_mut().set(STORE_KEY_LATEST_VERSION); } Err(err) => { // Report error @@ -140,30 +141,28 @@ impl AuthActivity { } else { info!("Check for updates is disabled"); } - /* - let ctx: &mut Context = self.context.as_mut().unwrap(); - // Set version into the store (or just a flag) - match github_tag.take() { - Some(git::GithubTag { tag_name, body }) => { - // If some store version and release notes - info!("Latest version is: {}", tag_name); - ctx.store.set_string(STORE_KEY_LATEST_VERSION, tag_name); - ctx.store.set_string(STORE_KEY_RELEASE_NOTES, body); - } - None => { - info!("Latest version is: {} (current)", env!("CARGO_PKG_VERSION")); - // Just set flag as check - ctx.store.set(STORE_KEY_LATEST_VERSION); - } - }*/ } } + /// ### context + /// + /// Returns a reference to context + fn context(&self) -> &Context { + self.context.as_ref().unwrap() + } + + /// ### context_mut + /// + /// Returns a mutable reference to context + fn context_mut(&mut self) -> &mut Context { + self.context.as_mut().unwrap() + } + /// ### theme /// /// Returns a reference to theme fn theme(&self) -> &Theme { - self.context.as_ref().unwrap().theme_provider.theme() + self.context().theme_provider().theme() } } @@ -176,11 +175,11 @@ impl Activity for AuthActivity { fn on_create(&mut self, mut context: Context) { debug!("Initializing activity"); // Initialize file transfer params - context.ft_params = Some(FileTransferParams::default()); + context.set_ftparams(FileTransferParams::default()); // Set context self.context = Some(context); // Clear terminal - self.context.as_mut().unwrap().clear_screen(); + self.context_mut().clear_screen(); // Put raw mode on enabled if let Err(err) = enable_raw_mode() { error!("Failed to enter raw mode: {}", err); @@ -197,7 +196,7 @@ impl Activity for AuthActivity { self.view_recent_connections(); } // Verify error state from context - if let Some(err) = self.context.as_mut().unwrap().error() { + if let Some(err) = self.context_mut().error() { self.mount_error(err.as_str()); } info!("Activity initialized"); @@ -213,7 +212,7 @@ impl Activity for AuthActivity { return; } // Read one event - if let Ok(Some(event)) = self.context.as_ref().unwrap().input_hnd.read_event() { + if let Ok(Some(event)) = self.context().input_hnd().read_event() { // Set redraw to true self.redraw = true; // Handle on resize diff --git a/src/ui/activities/auth/update.rs b/src/ui/activities/auth/update.rs index be6ad54..9b0bbd8 100644 --- a/src/ui/activities/auth/update.rs +++ b/src/ui/activities/auth/update.rs @@ -331,19 +331,21 @@ impl Update for AuthActivity { self.save_recent(); let (address, port, protocol, username, password) = self.get_input(); // Set file transfer params to context - let mut ft_params: &mut FileTransferParams = - &mut self.context.as_mut().unwrap().ft_params.as_mut().unwrap(); - ft_params.address = address; - ft_params.port = port; - ft_params.protocol = protocol; - ft_params.username = match username.is_empty() { - true => None, - false => Some(username), - }; - ft_params.password = match password.is_empty() { - true => None, - false => Some(password), + let params: FileTransferParams = FileTransferParams { + address, + port, + protocol, + username: match username.is_empty() { + true => None, + false => Some(username), + }, + password: match password.is_empty() { + true => None, + false => Some(password), + }, + entry_directory: None, }; + self.context_mut().set_ftparams(params); // Set exit reason self.exit_reason = Some(super::ExitReason::Connect); // Return None diff --git a/src/ui/activities/auth/view.rs b/src/ui/activities/auth/view.rs index e196d58..88839e6 100644 --- a/src/ui/activities/auth/view.rs +++ b/src/ui/activities/auth/view.rs @@ -109,12 +109,7 @@ impl AuthActivity { )), ); // Get default protocol - let default_protocol: FileTransferProtocol = self - .context - .as_ref() - .unwrap() - .config_client - .get_default_protocol(); + let default_protocol: FileTransferProtocol = self.context().config().get_default_protocol(); // Protocol self.view.mount( super::COMPONENT_RADIO_PROTOCOL, @@ -186,12 +181,11 @@ impl AuthActivity { ); // Version notice if let Some(version) = self - .context - .as_ref() - .unwrap() - .store + .context() + .store() .get_string(super::STORE_KEY_LATEST_VERSION) { + let version: String = version.to_string(); self.view.mount( super::COMPONENT_TEXT_NEW_VERSION, Box::new(Span::new( @@ -199,7 +193,7 @@ impl AuthActivity { .with_foreground(Color::Yellow) .with_spans(vec![ TextSpan::from("termscp "), - TextSpanBuilder::new(version).underlined().bold().build(), + TextSpanBuilder::new(version.as_str()).underlined().bold().build(), TextSpan::from(" is NOW available! Get it from ; view release notes with "), ]) .build(), @@ -242,7 +236,7 @@ impl AuthActivity { /// Display view on canvas pub(super) fn view(&mut self) { let mut ctx: Context = self.context.take().unwrap(); - let _ = ctx.terminal.draw(|f| { + let _ = ctx.terminal().draw(|f| { // Check window size let height: u16 = f.size().height; self.check_minimum_window_size(height); @@ -784,7 +778,7 @@ impl AuthActivity { /// mount release notes text area pub(super) fn mount_release_notes(&mut self) { if let Some(ctx) = self.context.as_ref() { - if let Some(release_notes) = ctx.store.get_string(super::STORE_KEY_RELEASE_NOTES) { + if let Some(release_notes) = ctx.store().get_string(super::STORE_KEY_RELEASE_NOTES) { // make spans let spans: Vec = release_notes.lines().map(TextSpan::from).collect(); self.view.mount( diff --git a/src/ui/activities/filetransfer/misc.rs b/src/ui/activities/filetransfer/misc.rs index a238a7e..5838fc2 100644 --- a/src/ui/activities/filetransfer/misc.rs +++ b/src/ui/activities/filetransfer/misc.rs @@ -111,7 +111,7 @@ impl FileTransferActivity { /// Read one event. /// Returns whether at least one event has been handled pub(super) fn read_input_event(&mut self) -> bool { - if let Ok(Some(event)) = self.context.as_ref().unwrap().input_hnd.read_event() { + if let Ok(Some(event)) = self.context().input_hnd().read_event() { // Handle event let msg = self.view.on(event); self.update(msg); diff --git a/src/ui/activities/filetransfer/mod.rs b/src/ui/activities/filetransfer/mod.rs index fd97ca7..2cb4e18 100644 --- a/src/ui/activities/filetransfer/mod.rs +++ b/src/ui/activities/filetransfer/mod.rs @@ -210,18 +210,32 @@ impl FileTransferActivity { }) } + /// ### context + /// + /// Returns a reference to context + fn context(&self) -> &Context { + self.context.as_ref().unwrap() + } + + /// ### context_mut + /// + /// Returns a mutable reference to context + fn context_mut(&mut self) -> &mut Context { + self.context.as_mut().unwrap() + } + /// ### config /// /// Returns config client reference fn config(&self) -> &ConfigClient { - &self.context.as_ref().unwrap().config_client + &self.context().config() } /// ### theme /// /// Get a reference to `Theme` fn theme(&self) -> &Theme { - self.context.as_ref().unwrap().theme_provider.theme() + self.context().theme_provider().theme() } } @@ -241,7 +255,7 @@ impl Activity for FileTransferActivity { // Set context self.context = Some(context); // Clear terminal - self.context.as_mut().unwrap().clear_screen(); + self.context_mut().clear_screen(); // Put raw mode on enabled if let Err(err) = enable_raw_mode() { error!("Failed to enter raw mode: {}", err); @@ -276,7 +290,7 @@ impl Activity for FileTransferActivity { } // Check if connected (popup must be None, otherwise would try reconnecting in loop in case of error) if !self.client.is_connected() && self.view.get_props(COMPONENT_TEXT_FATAL).is_none() { - let params = self.context.as_ref().unwrap().ft_params.as_ref().unwrap(); + let params = self.context().ft_params().unwrap(); info!( "Client is not connected to remote; connecting to {}:{}", params.address, params.port diff --git a/src/ui/activities/filetransfer/session.rs b/src/ui/activities/filetransfer/session.rs index 6607a06..5180ef7 100644 --- a/src/ui/activities/filetransfer/session.rs +++ b/src/ui/activities/filetransfer/session.rs @@ -76,15 +76,15 @@ impl FileTransferActivity { /// /// Connect to remote pub(super) fn connect(&mut self) { - let params = self.context.as_ref().unwrap().ft_params.as_ref().unwrap(); + let params = self.context().ft_params().unwrap().clone(); let addr: String = params.address.clone(); let entry_dir: Option = params.entry_directory.clone(); // Connect to remote match self.client.connect( - params.address.clone(), + params.address, params.port, - params.username.clone(), - params.password.clone(), + params.username, + params.password, ) { Ok(welcome) => { if let Some(banner) = welcome { @@ -121,7 +121,7 @@ impl FileTransferActivity { /// /// disconnect from remote pub(super) fn disconnect(&mut self) { - let params = self.context.as_ref().unwrap().ft_params.as_ref().unwrap(); + let params = self.context().ft_params().unwrap(); let msg: String = format!("Disconnecting from {}...", params.address); // Show popup disconnecting self.mount_wait(msg.as_str()); diff --git a/src/ui/activities/filetransfer/update.rs b/src/ui/activities/filetransfer/update.rs index 0443bd5..0ce5ac6 100644 --- a/src/ui/activities/filetransfer/update.rs +++ b/src/ui/activities/filetransfer/update.rs @@ -720,10 +720,8 @@ impl FileTransferActivity { Some(props) => { // Get width let width: usize = self - .context - .as_ref() - .unwrap() - .store + .context() + .store() .get_unsigned(super::STORAGE_EXPLORER_WIDTH) .unwrap_or(256); let hostname: String = match hostname::get() { @@ -768,13 +766,11 @@ impl FileTransferActivity { Some(props) => { // Get width let width: usize = self - .context - .as_ref() - .unwrap() - .store + .context() + .store() .get_unsigned(super::STORAGE_EXPLORER_WIDTH) .unwrap_or(256); - let params = self.context.as_ref().unwrap().ft_params.as_ref().unwrap(); + let params = self.context().ft_params().unwrap(); let hostname: String = format!( "{}:{} ", params.address, diff --git a/src/ui/activities/setup/config.rs b/src/ui/activities/setup/config.rs index 5e27dfd..1a2e5cd 100644 --- a/src/ui/activities/setup/config.rs +++ b/src/ui/activities/setup/config.rs @@ -92,7 +92,7 @@ impl SetupActivity { None => Ok(()), Some(ctx) => { // Set editor if config client exists - env::set_var("EDITOR", ctx.config_client.get_text_editor()); + env::set_var("EDITOR", ctx.config().get_text_editor()); // Prepare terminal if let Err(err) = disable_raw_mode() { error!("Failed to disable raw mode: {}", err); @@ -101,10 +101,10 @@ impl SetupActivity { #[cfg(not(target_os = "windows"))] ctx.leave_alternate_screen(); // Get result - let result: Result<(), String> = match ctx.config_client.iter_ssh_keys().nth(idx) { + let result: Result<(), String> = match ctx.config().iter_ssh_keys().nth(idx) { Some(key) => { // Get key path - match ctx.config_client.get_ssh_key(key) { + match ctx.config().get_ssh_key(key) { Ok(ssh_key) => match ssh_key { None => Ok(()), Some((_, _, key_path)) => { diff --git a/src/ui/activities/setup/mod.rs b/src/ui/activities/setup/mod.rs index 21299f2..f93cf75 100644 --- a/src/ui/activities/setup/mod.rs +++ b/src/ui/activities/setup/mod.rs @@ -134,24 +134,38 @@ impl Default for SetupActivity { } impl SetupActivity { + /// ### context + /// + /// Returns a reference to context + fn context(&self) -> &Context { + self.context.as_ref().unwrap() + } + + /// ### context_mut + /// + /// Returns a mutable reference to context + fn context_mut(&mut self) -> &mut Context { + self.context.as_mut().unwrap() + } + fn config(&self) -> &ConfigClient { - &self.context.as_ref().unwrap().config_client + &self.context().config() } fn config_mut(&mut self) -> &mut ConfigClient { - &mut self.context.as_mut().unwrap().config_client + self.context_mut().config_mut() } fn theme(&self) -> &Theme { - self.context.as_ref().unwrap().theme_provider.theme() + self.context().theme_provider().theme() } fn theme_mut(&mut self) -> &mut Theme { - self.context.as_mut().unwrap().theme_provider.theme_mut() + self.context_mut().theme_provider_mut().theme_mut() } fn theme_provider(&mut self) -> &mut ThemeProvider { - &mut self.context.as_mut().unwrap().theme_provider + self.context_mut().theme_provider_mut() } } @@ -188,7 +202,7 @@ impl Activity for SetupActivity { return; } // Read one event - if let Ok(Some(event)) = self.context.as_ref().unwrap().input_hnd.read_event() { + if let Ok(Some(event)) = self.context().input_hnd().read_event() { // Set redraw to true self.redraw = true; // Handle event diff --git a/src/ui/activities/setup/view/setup.rs b/src/ui/activities/setup/view/setup.rs index 98aa239..9a8c316 100644 --- a/src/ui/activities/setup/view/setup.rs +++ b/src/ui/activities/setup/view/setup.rs @@ -197,7 +197,7 @@ impl SetupActivity { pub(super) fn view_setup(&mut self) { let mut ctx: Context = self.context.take().unwrap(); - let _ = ctx.terminal.draw(|f| { + let _ = ctx.terminal().draw(|f| { // Prepare main chunks let chunks = Layout::default() .direction(Direction::Vertical) diff --git a/src/ui/activities/setup/view/ssh_keys.rs b/src/ui/activities/setup/view/ssh_keys.rs index 499fff8..3517178 100644 --- a/src/ui/activities/setup/view/ssh_keys.rs +++ b/src/ui/activities/setup/view/ssh_keys.rs @@ -111,7 +111,7 @@ impl SetupActivity { pub(crate) fn view_ssh_keys(&mut self) { let mut ctx: Context = self.context.take().unwrap(); - let _ = ctx.terminal.draw(|f| { + let _ = ctx.terminal().draw(|f| { // Prepare main chunks let chunks = Layout::default() .direction(Direction::Vertical) diff --git a/src/ui/activities/setup/view/theme.rs b/src/ui/activities/setup/view/theme.rs index b3c0853..58c2aa7 100644 --- a/src/ui/activities/setup/view/theme.rs +++ b/src/ui/activities/setup/view/theme.rs @@ -175,7 +175,7 @@ impl SetupActivity { pub(super) fn view_theme(&mut self) { let mut ctx: Context = self.context.take().unwrap(); - let _ = ctx.terminal.draw(|f| { + let _ = ctx.terminal().draw(|f| { // Prepare main chunks let chunks = Layout::default() .direction(Direction::Vertical) diff --git a/src/ui/context.rs b/src/ui/context.rs index 0364435..9cb001c 100644 --- a/src/ui/context.rs +++ b/src/ui/context.rs @@ -41,22 +41,25 @@ use std::path::PathBuf; use tuirealm::tui::backend::CrosstermBackend; use tuirealm::tui::Terminal; +type TuiTerminal = Terminal>; + /// ## Context /// /// Context holds data structures used by the ui pub struct Context { - pub ft_params: Option, - pub(crate) config_client: ConfigClient, + ft_params: Option, + config_client: ConfigClient, pub(crate) store: Store, - pub(crate) input_hnd: InputHandler, - pub(crate) terminal: Terminal>, - pub(crate) theme_provider: ThemeProvider, + input_hnd: InputHandler, + pub(crate) terminal: TuiTerminal, + theme_provider: ThemeProvider, error: Option, } /// ### FileTransferParams /// /// Holds connection parameters for file transfers +#[derive(Clone)] pub struct FileTransferParams { pub address: String, pub port: u16, @@ -89,6 +92,52 @@ impl Context { } } + // -- getters + + pub fn ft_params(&self) -> Option<&FileTransferParams> { + self.ft_params.as_ref() + } + + pub fn config(&self) -> &ConfigClient { + &self.config_client + } + + pub fn config_mut(&mut self) -> &mut ConfigClient { + &mut self.config_client + } + + pub(crate) fn input_hnd(&self) -> &InputHandler { + &self.input_hnd + } + + pub(crate) fn store(&self) -> &Store { + &self.store + } + + pub(crate) fn store_mut(&mut self) -> &mut Store { + &mut self.store + } + + pub fn theme_provider(&self) -> &ThemeProvider { + &self.theme_provider + } + + pub fn theme_provider_mut(&mut self) -> &mut ThemeProvider { + &mut self.theme_provider + } + + pub fn terminal(&mut self) -> &mut TuiTerminal { + &mut self.terminal + } + + // -- setter + + pub fn set_ftparams(&mut self, params: FileTransferParams) { + self.ft_params = Some(params); + } + + // -- error + /// ### set_error /// /// Set context error