From 08b855e7793e6017c9f74093394db57943bc80bd Mon Sep 17 00:00:00 2001 From: veeso Date: Thu, 25 Mar 2021 22:59:42 +0100 Subject: [PATCH] Find dialog in view --- CHANGELOG.md | 1 + src/fs/explorer/mod.rs | 24 +++ .../filetransfer_activity/actions.rs | 120 +++++++++++- .../activities/filetransfer_activity/misc.rs | 13 ++ .../activities/filetransfer_activity/mod.rs | 20 +- .../filetransfer_activity/update.rs | 173 +++++++++++++++++- .../activities/filetransfer_activity/view.rs | 68 ++++++- src/ui/activities/keymap.rs | 2 - 8 files changed, 404 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2973a8a..d6c406a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Released on FIXME: date - Fixed a bug causing termscp to show two equal bookmarks when overwriting one. - Dependencies: - Removed `unicode-width` + - Added `wildmatch 1.0.13` - For developers: - Activity refactoring - Developed an internal library used to create components, components are then nested inside a View diff --git a/src/fs/explorer/mod.rs b/src/fs/explorer/mod.rs index 5ab0b74..32bdfb3 100644 --- a/src/fs/explorer/mod.rs +++ b/src/fs/explorer/mod.rs @@ -127,6 +127,13 @@ impl FileExplorer { self.sort(); } + /// ### del_entry + /// + /// Delete file at provided index + pub fn del_entry(&mut self, idx: usize) { + self.files.remove(idx); + } + /* /// ### count /// @@ -627,6 +634,23 @@ mod tests { assert!(GroupDirs::from_str("omar").is_err()); } + #[test] + fn test_fs_explorer_del_entry() { + let mut explorer: FileExplorer = FileExplorer::default(); + // Create files (files are then sorted by name) + explorer.set_files(vec![ + make_fs_entry("CONTRIBUTING.md", false), + make_fs_entry("docs/", true), + make_fs_entry("src/", true), + make_fs_entry("README.md", false), + ]); + explorer.del_entry(0); + assert_eq!(explorer.files.len(), 3); + assert_eq!(explorer.files[0].get_name(), "docs/"); + explorer.del_entry(5); + assert_eq!(explorer.files.len(), 3); + } + fn make_fs_entry(name: &str, is_dir: bool) -> FsEntry { let t_now: SystemTime = SystemTime::now(); match is_dir { diff --git a/src/ui/activities/filetransfer_activity/actions.rs b/src/ui/activities/filetransfer_activity/actions.rs index 3a620d8..13d3017 100644 --- a/src/ui/activities/filetransfer_activity/actions.rs +++ b/src/ui/activities/filetransfer_activity/actions.rs @@ -24,7 +24,7 @@ */ // locals -use super::{FileTransferActivity, FsEntry, LogLevel}; +use super::{FileExplorerTab, FileTransferActivity, FsEntry, LogLevel}; use crate::ui::layout::Payload; // externals use std::path::PathBuf; @@ -485,6 +485,124 @@ impl FileTransferActivity { } } + pub(super) fn action_local_find(&mut self, input: String) -> Result, String> { + match self.context.as_mut().unwrap().local.find(input.as_str()) { + Ok(entries) => Ok(entries), + Err(err) => Err(format!("Could not search for files: {}", err)), + } + } + + pub(super) fn action_remote_find(&mut self, input: String) -> Result, String> { + match self.client.as_mut().find(input.as_str()) { + Ok(entries) => Ok(entries), + Err(err) => Err(format!("Could not search for files: {}", err)), + } + } + + pub(super) fn action_find_changedir(&mut self, idx: usize) { + // Match entry + if let Some(entry) = self.found.as_ref().unwrap().get(idx) { + // Get path: if a directory, use directory path; if it is a File, get parent path + let path: PathBuf = match entry { + FsEntry::Directory(dir) => dir.abs_path.clone(), + FsEntry::File(file) => match file.abs_path.parent() { + None => PathBuf::from("."), + Some(p) => p.to_path_buf(), + }, + }; + // Change directory + match self.tab { + FileExplorerTab::FindLocal | FileExplorerTab::Local => { + self.local_changedir(path.as_path(), true) + } + FileExplorerTab::FindRemote | FileExplorerTab::Remote => { + self.remote_changedir(path.as_path(), true) + } + } + } + } + + pub(super) fn action_find_transfer(&mut self, idx: usize, name: Option) { + let entry: Option = match self.found.as_ref().unwrap().get(idx) { + None => None, + Some(e) => Some(e.clone()), + }; + if let Some(entry) = entry { + // Download file + match self.tab { + FileExplorerTab::FindLocal | FileExplorerTab::Local => { + let wrkdir: PathBuf = self.remote.wrkdir.clone(); + self.filetransfer_send(&entry.get_realfile(), wrkdir.as_path(), name); + } + FileExplorerTab::FindRemote | FileExplorerTab::Remote => { + let wrkdir: PathBuf = self.local.wrkdir.clone(); + self.filetransfer_recv(&entry.get_realfile(), wrkdir.as_path(), name); + } + } + } + } + + pub(super) fn action_find_delete(&mut self, idx: usize) { + let entry: Option = match self.found.as_ref().unwrap().get(idx) { + None => None, + Some(e) => Some(e.clone()), + }; + if let Some(entry) = entry { + // Download file + match self.tab { + FileExplorerTab::FindLocal | FileExplorerTab::Local => { + let full_path: PathBuf = entry.get_abs_path(); + // Delete file or directory and report status as popup + match self.context.as_mut().unwrap().local.remove(&entry) { + Ok(_) => { + // Reload files + let p: PathBuf = self.local.wrkdir.clone(); + self.local_scan(p.as_path()); + // Log + self.log( + LogLevel::Info, + format!("Removed file \"{}\"", full_path.display()).as_ref(), + ); + } + Err(err) => { + self.log_and_alert( + LogLevel::Error, + format!( + "Could not delete file \"{}\": {}", + full_path.display(), + err + ), + ); + } + } + } + FileExplorerTab::FindRemote | FileExplorerTab::Remote => { + let full_path: PathBuf = entry.get_abs_path(); + // Delete file + match self.client.remove(&entry) { + Ok(_) => { + self.reload_remote_dir(); + self.log( + LogLevel::Info, + format!("Removed file \"{}\"", full_path.display()).as_ref(), + ); + } + Err(err) => { + self.log_and_alert( + LogLevel::Error, + format!( + "Could not delete file \"{}\": {}", + full_path.display(), + err + ), + ); + } + } + } + } + } + } + /// ### get_local_file_entry /// /// Get local file entry diff --git a/src/ui/activities/filetransfer_activity/misc.rs b/src/ui/activities/filetransfer_activity/misc.rs index 6712ffa..d23efce 100644 --- a/src/ui/activities/filetransfer_activity/misc.rs +++ b/src/ui/activities/filetransfer_activity/misc.rs @@ -111,6 +111,19 @@ impl FileTransferActivity { } } + /// ### build_found_explorer + /// + /// Build explorer reading from `ConfigClient`, for found result (has some differences) + pub(super) fn build_found_explorer() -> FileExplorer { + FileExplorerBuilder::new() + .with_file_sorting(FileSorting::ByName) + .with_group_dirs(Some(GroupDirs::First)) + .with_hidden_files(true) + .with_stack_size(0) + .with_formatter(Some("{NAME} {SYMLINK}")) + .build() + } + /// ### setup_text_editor /// /// Set text editor to use diff --git a/src/ui/activities/filetransfer_activity/mod.rs b/src/ui/activities/filetransfer_activity/mod.rs index 724ae58..c2e6af2 100644 --- a/src/ui/activities/filetransfer_activity/mod.rs +++ b/src/ui/activities/filetransfer_activity/mod.rs @@ -63,23 +63,25 @@ const STORAGE_LOGBOX_WIDTH: &str = "LOGBOX_WIDTH"; const COMPONENT_EXPLORER_LOCAL: &str = "EXPLORER_LOCAL"; const COMPONENT_EXPLORER_REMOTE: &str = "EXPLORER_REMOTE"; +const COMPONENT_EXPLORER_FIND: &str = "EXPLORER_FIND"; const COMPONENT_LOG_BOX: &str = "LOG_BOX"; const COMPONENT_PROGRESS_BAR: &str = "PROGRESS_BAR"; -const COMPONENT_TEXT_HELP: &str = "TEXT_HELP"; const COMPONENT_TEXT_ERROR: &str = "TEXT_ERROR"; -const COMPONENT_TEXT_WAIT: &str = "TEXT_WAIT"; const COMPONENT_TEXT_FATAL: &str = "TEXT_FATAL"; +const COMPONENT_TEXT_HELP: &str = "TEXT_HELP"; +const COMPONENT_TEXT_WAIT: &str = "TEXT_WAIT"; const COMPONENT_INPUT_COPY: &str = "INPUT_COPY"; const COMPONENT_INPUT_EXEC: &str = "INPUT_EXEC"; -const COMPONENT_INPUT_MKDIR: &str = "INPUT_MKDIR"; +const COMPONENT_INPUT_FIND: &str = "INPUT_FIND"; const COMPONENT_INPUT_GOTO: &str = "INPUT_GOTO"; -const COMPONENT_INPUT_SAVEAS: &str = "INPUT_SAVEAS"; +const COMPONENT_INPUT_MKDIR: &str = "INPUT_MKDIR"; const COMPONENT_INPUT_NEWFILE: &str = "INPUT_NEWFILE"; const COMPONENT_INPUT_RENAME: &str = "INPUT_RENAME"; -const COMPONENT_RADIO_QUIT: &str = "RADIO_QUIT"; -const COMPONENT_RADIO_DISCONNECT: &str = "RADIO_DISCONNECT"; -const COMPONENT_RADIO_SORTING: &str = "RADIO_SORTING"; +const COMPONENT_INPUT_SAVEAS: &str = "INPUT_SAVEAS"; const COMPONENT_RADIO_DELETE: &str = "RADIO_DELETE"; +const COMPONENT_RADIO_DISCONNECT: &str = "RADIO_DISCONNECT"; +const COMPONENT_RADIO_QUIT: &str = "RADIO_QUIT"; +const COMPONENT_RADIO_SORTING: &str = "RADIO_SORTING"; const COMPONENT_LIST_FILEINFO: &str = "LIST_FILEINFO"; /// ## FileExplorerTab @@ -88,6 +90,8 @@ const COMPONENT_LIST_FILEINFO: &str = "LIST_FILEINFO"; enum FileExplorerTab { Local, Remote, + FindLocal, // Find result tab + FindRemote, // Find result tab } /// ## LogLevel @@ -206,6 +210,7 @@ pub struct FileTransferActivity { client: Box, // File transfer client local: FileExplorer, // Local File explorer state remote: FileExplorer, // Remote File explorer state + found: Option, // File explorer for find result tab: FileExplorerTab, // Current selected tab log_index: usize, // Current log index entry selected log_records: VecDeque, // Log records @@ -235,6 +240,7 @@ impl FileTransferActivity { }, local: Self::build_explorer(config_client.as_ref()), remote: Self::build_explorer(config_client.as_ref()), + found: None, tab: FileExplorerTab::Local, log_index: 0, log_records: VecDeque::with_capacity(256), // 256 events is enough I guess diff --git a/src/ui/activities/filetransfer_activity/update.rs b/src/ui/activities/filetransfer_activity/update.rs index 1d99172..869feb7 100644 --- a/src/ui/activities/filetransfer_activity/update.rs +++ b/src/ui/activities/filetransfer_activity/update.rs @@ -27,9 +27,10 @@ extern crate bytesize; // locals use super::{ - FileExplorerTab, FileTransferActivity, LogLevel, COMPONENT_EXPLORER_LOCAL, - COMPONENT_EXPLORER_REMOTE, COMPONENT_INPUT_COPY, COMPONENT_INPUT_EXEC, COMPONENT_INPUT_GOTO, - COMPONENT_INPUT_MKDIR, COMPONENT_INPUT_NEWFILE, COMPONENT_INPUT_RENAME, COMPONENT_INPUT_SAVEAS, + FileExplorerTab, FileTransferActivity, LogLevel, COMPONENT_EXPLORER_FIND, + COMPONENT_EXPLORER_LOCAL, COMPONENT_EXPLORER_REMOTE, COMPONENT_INPUT_COPY, + COMPONENT_INPUT_EXEC, COMPONENT_INPUT_FIND, COMPONENT_INPUT_GOTO, COMPONENT_INPUT_MKDIR, + COMPONENT_INPUT_NEWFILE, COMPONENT_INPUT_RENAME, COMPONENT_INPUT_SAVEAS, COMPONENT_LIST_FILEINFO, COMPONENT_LOG_BOX, COMPONENT_PROGRESS_BAR, COMPONENT_RADIO_DELETE, COMPONENT_RADIO_DISCONNECT, COMPONENT_RADIO_QUIT, COMPONENT_RADIO_SORTING, COMPONENT_TEXT_ERROR, COMPONENT_TEXT_FATAL, COMPONENT_TEXT_HELP, @@ -37,7 +38,9 @@ use super::{ use crate::fs::explorer::FileSorting; use crate::fs::FsEntry; use crate::ui::activities::keymap::*; -use crate::ui::layout::props::{PropValue, TableBuilder, TextParts, TextSpan, TextSpanBuilder}; +use crate::ui::layout::props::{ + PropValue, PropsBuilder, TableBuilder, TextParts, TextSpan, TextSpanBuilder, +}; use crate::ui::layout::{Msg, Payload}; // externals use bytesize::ByteSize; @@ -314,6 +317,11 @@ impl FileTransferActivity { self.mount_mkdir(); None } + (COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_F) + | (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_F) => { + self.mount_find_input(); + None + } (COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_G) | (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_G) => { self.mount_goto(); @@ -342,7 +350,8 @@ impl FileTransferActivity { None } (COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_S) - | (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_S) => { + | (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_S) + | (COMPONENT_EXPLORER_FIND, &MSG_KEY_CHAR_S) => { // Mount save as self.mount_saveas(); None @@ -362,10 +371,50 @@ impl FileTransferActivity { (COMPONENT_EXPLORER_LOCAL, &MSG_KEY_DEL) | (COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_E) | (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_DEL) - | (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_E) => { + | (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_E) + | (COMPONENT_EXPLORER_FIND, &MSG_KEY_DEL) + | (COMPONENT_EXPLORER_FIND, &MSG_KEY_CHAR_E) => { self.mount_radio_delete(); None } + // -- find result explorer + (COMPONENT_EXPLORER_FIND, &MSG_KEY_ESC) => { + // Umount find + self.umount_find(); + // Finalize find + self.finalize_find(); + None + } + (COMPONENT_EXPLORER_FIND, Msg::OnSubmit(Payload::Unsigned(idx))) => { + // Find changedir + self.action_find_changedir(*idx); + // Umount find + self.umount_find(); + // Finalize find + self.finalize_find(); + // Reload files + match self.tab { + FileExplorerTab::Local => self.update_local_filelist(), + FileExplorerTab::Remote => self.update_remote_filelist(), + _ => None, + } + } + (COMPONENT_EXPLORER_FIND, &MSG_KEY_SPACE) => { + // Get entry + match self.view.get_value(COMPONENT_EXPLORER_FIND) { + Some(Payload::Unsigned(idx)) => { + self.action_find_transfer(idx, None); + // Reload files + match self.tab { + // NOTE: swapped by purpose + FileExplorerTab::FindLocal => self.update_remote_filelist(), + FileExplorerTab::FindRemote => self.update_local_filelist(), + _ => None, + } + } + _ => None, + } + } // -- switch to log (COMPONENT_EXPLORER_LOCAL, &MSG_KEY_TAB) | (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_TAB) => { @@ -387,12 +436,14 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => self.action_local_copy(input.to_string()), FileExplorerTab::Remote => self.action_remote_copy(input.to_string()), + _ => panic!("Found tab doesn't support COPY"), } self.umount_copy(); // Reload files match self.tab { FileExplorerTab::Local => self.update_local_filelist(), FileExplorerTab::Remote => self.update_remote_filelist(), + _ => None, } } // -- exec popup @@ -405,14 +456,53 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => self.action_local_exec(input.to_string()), FileExplorerTab::Remote => self.action_remote_exec(input.to_string()), + _ => panic!("Found tab doesn't support EXEC"), } self.umount_exec(); // Reload files match self.tab { FileExplorerTab::Local => self.update_local_filelist(), FileExplorerTab::Remote => self.update_remote_filelist(), + _ => None, } } + // -- find popup + (COMPONENT_INPUT_FIND, &MSG_KEY_ESC) => { + self.umount_find_input(); + None + } + (COMPONENT_INPUT_FIND, Msg::OnSubmit(Payload::Text(input))) => { + self.umount_find_input(); + // Find + let res: Result, String> = match self.tab { + FileExplorerTab::Local => self.action_local_find(input.to_string()), + FileExplorerTab::Remote => self.action_remote_find(input.to_string()), + _ => panic!("Trying to search for files, while already in a find result"), + }; + // Match result + match res { + Err(err) => { + // Mount error + self.mount_error(err.as_str()); + } + Ok(files) => { + // Create explorer and load files + let mut explorer = Self::build_found_explorer(); + explorer.set_files(files); + self.found = Some(explorer); + // Mount result widget + self.mount_find(input); + self.update_find_list(); + // Initialize tab + self.tab = match self.tab { + FileExplorerTab::Local => FileExplorerTab::FindLocal, + FileExplorerTab::Remote => FileExplorerTab::FindRemote, + _ => FileExplorerTab::FindLocal, + }; + } + } + None + } // -- goto popup (COMPONENT_INPUT_GOTO, &MSG_KEY_ESC) => { self.umount_goto(); @@ -422,6 +512,7 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => self.action_change_local_dir(input.to_string()), FileExplorerTab::Remote => self.action_change_remote_dir(input.to_string()), + _ => panic!("Found tab doesn't support GOTO"), } // Umount self.umount_goto(); @@ -429,6 +520,7 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => self.update_local_filelist(), FileExplorerTab::Remote => self.update_remote_filelist(), + _ => None, } } // -- make directory @@ -440,12 +532,14 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => self.action_local_mkdir(input.to_string()), FileExplorerTab::Remote => self.action_remote_mkdir(input.to_string()), + _ => panic!("Found tab doesn't support MKDIR"), } self.umount_mkdir(); // Reload files match self.tab { FileExplorerTab::Local => self.update_local_filelist(), FileExplorerTab::Remote => self.update_remote_filelist(), + _ => None, } } // -- new file @@ -457,12 +551,14 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => self.action_local_newfile(input.to_string()), FileExplorerTab::Remote => self.action_remote_newfile(input.to_string()), + _ => panic!("Found tab doesn't support NEWFILE"), } self.umount_newfile(); // Reload files match self.tab { FileExplorerTab::Local => self.update_local_filelist(), FileExplorerTab::Remote => self.update_remote_filelist(), + _ => None, } } // -- rename @@ -474,12 +570,14 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => self.action_local_rename(input.to_string()), FileExplorerTab::Remote => self.action_remote_rename(input.to_string()), + _ => panic!("Found tab doesn't support RENAME"), } self.umount_rename(); // Reload files match self.tab { FileExplorerTab::Local => self.update_local_filelist(), FileExplorerTab::Remote => self.update_remote_filelist(), + _ => None, } } // -- save as @@ -491,6 +589,14 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => self.action_local_saveas(input.to_string()), FileExplorerTab::Remote => self.action_remote_saveas(input.to_string()), + FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => { + // Get entry + if let Some(Payload::Unsigned(idx)) = + self.view.get_value(COMPONENT_EXPLORER_FIND) + { + self.action_find_transfer(idx, Some(input.to_string())); + } + } } self.umount_saveas(); // Reload files @@ -498,6 +604,8 @@ impl FileTransferActivity { // NOTE: Swapped is intentional FileExplorerTab::Local => self.update_remote_filelist(), FileExplorerTab::Remote => self.update_local_filelist(), + FileExplorerTab::FindLocal => self.update_remote_filelist(), + FileExplorerTab::FindRemote => self.update_local_filelist(), } } // -- fileinfo @@ -517,12 +625,25 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => self.action_local_delete(), FileExplorerTab::Remote => self.action_remote_delete(), + FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => { + // Get entry + if let Some(Payload::Unsigned(idx)) = + self.view.get_value(COMPONENT_EXPLORER_FIND) + { + self.action_find_delete(idx); + // Reload entries + self.found.as_mut().unwrap().del_entry(idx); + self.update_find_list(); + } + } } self.umount_radio_delete(); // Reload files match self.tab { FileExplorerTab::Local => self.update_local_filelist(), FileExplorerTab::Remote => self.update_remote_filelist(), + FileExplorerTab::FindLocal => self.update_local_filelist(), + FileExplorerTab::FindRemote => self.update_remote_filelist(), } } // -- disconnect @@ -547,6 +668,7 @@ impl FileTransferActivity { self.umount_quit(); None } + // -- sorting (COMPONENT_RADIO_SORTING, &MSG_KEY_ESC) => { self.umount_file_sorting(); None @@ -562,12 +684,14 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => self.local.sort_by(sorting), FileExplorerTab::Remote => self.remote.sort_by(sorting), + _ => panic!("Found result doesn't support SORTING"), } self.umount_file_sorting(); // Reload files match self.tab { FileExplorerTab::Local => self.update_local_filelist(), FileExplorerTab::Remote => self.update_remote_filelist(), + _ => None, } } // -- error @@ -809,6 +933,43 @@ impl FileTransferActivity { } } + /// ### finalize_find + /// + /// Finalize find process + fn finalize_find(&mut self) { + // Set found to none + self.found = None; + // Restore tab + self.tab = match self.tab { + FileExplorerTab::FindLocal => FileExplorerTab::Local, + FileExplorerTab::FindRemote => FileExplorerTab::Remote, + _ => FileExplorerTab::Local, + }; + } + + fn update_find_list(&mut self) -> Option<(String, Msg)> { + match self.view.get_props(COMPONENT_EXPLORER_FIND).as_mut() { + None => None, + Some(props) => { + let props = props.build(); + let title: String = props.texts.title.clone().unwrap_or(String::new()); + let mut props = PropsBuilder::from(props.clone()); + // Prepare files + let file_texts: Vec = self + .found + .as_ref() + .unwrap() + .iter_files() + .map(|x: &FsEntry| TextSpan::from(self.found.as_ref().unwrap().fmt_file(x))) + .collect(); + let props = props + .with_texts(TextParts::new(Some(title), Some(file_texts))) + .build(); + self.view.update(COMPONENT_EXPLORER_FIND, props) + } + } + } + /// ### elide_wrkdir_path /// /// Elide working directory path if longer than width + host.len diff --git a/src/ui/activities/filetransfer_activity/view.rs b/src/ui/activities/filetransfer_activity/view.rs index bced2e7..07ffe2d 100644 --- a/src/ui/activities/filetransfer_activity/view.rs +++ b/src/ui/activities/filetransfer_activity/view.rs @@ -33,7 +33,7 @@ use super::{Context, FileExplorerTab, FileTransferActivity}; use crate::fs::explorer::FileSorting; use crate::fs::FsEntry; use crate::ui::layout::components::{ - msgbox::MsgBox, file_list::FileList, input::Input, logbox::LogBox, progress_bar::ProgressBar, + file_list::FileList, input::Input, logbox::LogBox, msgbox::MsgBox, progress_bar::ProgressBar, radio_group::RadioGroup, table::Table, }; use crate::ui::layout::props::{ @@ -138,6 +138,14 @@ impl FileTransferActivity { // Draw log box self.view.render(super::COMPONENT_LOG_BOX, f, chunks[1]); // Draw popups + if let Some(mut props) = self.view.get_props(super::COMPONENT_EXPLORER_FIND) { + if props.build().visible { + let popup = draw_area_in(f.size(), 60, 80); + f.render_widget(Clear, popup); + // make popup + self.view.render(super::COMPONENT_EXPLORER_FIND, f, popup); + } + } if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_COPY) { if props.build().visible { let popup = draw_area_in(f.size(), 40, 10); @@ -146,6 +154,14 @@ impl FileTransferActivity { self.view.render(super::COMPONENT_INPUT_COPY, f, popup); } } + if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_FIND) { + if props.build().visible { + let popup = draw_area_in(f.size(), 40, 10); + f.render_widget(Clear, popup); + // make popup + self.view.render(super::COMPONENT_INPUT_FIND, f, popup); + } + } if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_GOTO) { if props.build().visible { let popup = draw_area_in(f.size(), 40, 10); @@ -435,6 +451,55 @@ impl FileTransferActivity { self.view.umount(super::COMPONENT_INPUT_EXEC); } + pub(super) fn mount_find(&mut self, search: &str) { + // Get color + let color: Color = match self.tab { + FileExplorerTab::Local | FileExplorerTab::FindLocal => Color::Yellow, + FileExplorerTab::Remote | FileExplorerTab::FindRemote => Color::LightBlue, + }; + // Mount component + self.view.mount( + super::COMPONENT_EXPLORER_FIND, + Box::new(FileList::new( + PropsBuilder::default() + .with_texts(TextParts::new( + Some(format!("Search results for \"{}\"", search)), + Some(vec![]), + )) + .with_background(color) + .with_foreground(color) + .build(), + )), + ); + // Give focus to explorer findd + self.view.active(super::COMPONENT_EXPLORER_FIND); + } + + pub(super) fn umount_find(&mut self) { + self.view.umount(super::COMPONENT_EXPLORER_FIND); + } + + pub(super) fn mount_find_input(&mut self) { + self.view.mount( + super::COMPONENT_INPUT_FIND, + Box::new(Input::new( + PropsBuilder::default() + .with_texts(TextParts::new( + Some(String::from("Search files by name")), + None, + )) + .build(), + )), + ); + // Give focus to input find + self.view.active(super::COMPONENT_INPUT_FIND); + } + + pub(super) fn umount_find_input(&mut self) { + // Umount input find + self.view.umount(super::COMPONENT_INPUT_FIND); + } + pub(super) fn mount_goto(&mut self) { self.view.mount( super::COMPONENT_INPUT_GOTO, @@ -543,6 +608,7 @@ impl FileTransferActivity { let sorting: FileSorting = match self.tab { FileExplorerTab::Local => self.local.get_file_sorting(), FileExplorerTab::Remote => self.remote.get_file_sorting(), + _ => panic!("You can't mount file sorting when in found result"), }; let index: usize = match sorting { FileSorting::ByCreationTime => 2, diff --git a/src/ui/activities/keymap.rs b/src/ui/activities/keymap.rs index 6b5d938..b7dd5dc 100644 --- a/src/ui/activities/keymap.rs +++ b/src/ui/activities/keymap.rs @@ -91,12 +91,10 @@ pub const MSG_KEY_CHAR_E: Msg = Msg::OnKey(KeyEvent { code: KeyCode::Char('e'), modifiers: KeyModifiers::NONE, }); -/* pub const MSG_KEY_CHAR_F: Msg = Msg::OnKey(KeyEvent { code: KeyCode::Char('f'), modifiers: KeyModifiers::NONE, }); -*/ pub const MSG_KEY_CHAR_G: Msg = Msg::OnKey(KeyEvent { code: KeyCode::Char('g'), modifiers: KeyModifiers::NONE,