FileTransferActivity: sort files with <B>

This commit is contained in:
ChristianVisintin
2020-12-26 21:47:48 +01:00
parent 740d906eb3
commit 99fd0b199d
6 changed files with 256 additions and 63 deletions

View File

@@ -39,6 +39,7 @@ FIXME: Released on
- Hidden files are now not shown by default; use `A` to show hidden files. - Hidden files are now not shown by default; use `A` to show hidden files.
- Keybindings: - Keybindings:
- `A`: Toggle hidden files - `A`: Toggle hidden files
- `B`: Sort files by (name, size, creation time, modify time)
- `N`: New file - `N`: New file
- Dependencies: - Dependencies:
- added `bitflags 1.2.1` - added `bitflags 1.2.1`

View File

@@ -278,7 +278,7 @@ You can access the SSH key storage, from configuration moving to the `SSH Keys`
## Keybindings ⌨ ## Keybindings ⌨
| Key | Command | Reminder | | Key | Command | Reminder |
|---------------|-------------------------------------------------------|-----------| |---------------|-------------------------------------------------------|-------------|
| `<ESC>` | Disconnect from remote; return to authentication page | | | `<ESC>` | Disconnect from remote; return to authentication page | |
| `<TAB>` | Switch between log tab and explorer | | | `<TAB>` | Switch between log tab and explorer | |
| `<BACKSPACE>` | Go to previous directory in stack | | | `<BACKSPACE>` | Go to previous directory in stack | |
@@ -291,6 +291,7 @@ You can access the SSH key storage, from configuration moving to the `SSH Keys`
| `<ENTER>` | Enter directory | | | `<ENTER>` | Enter directory | |
| `<SPACE>` | Upload / download selected file | | | `<SPACE>` | Upload / download selected file | |
| `<A>` | Toggle hidden files | All | | `<A>` | Toggle hidden files | All |
| `<B>` | Sort files by | Bubblesort? |
| `<C>` | Copy file/directory | Copy | | `<C>` | Copy file/directory | Copy |
| `<D>` | Make directory | Directory | | `<D>` | Make directory | Directory |
| `<E>` | Delete file (Same as `DEL`) | Erase | | `<E>` | Delete file (Same as `DEL`) | Erase |

View File

@@ -52,6 +52,7 @@ pub enum FileSorting {
ByName, ByName,
ByModifyTime, ByModifyTime,
ByCreationTime, ByCreationTime,
BySize,
} }
/// ## GroupDirs /// ## GroupDirs
@@ -204,6 +205,7 @@ impl FileExplorer {
FileSorting::ByName => self.sort_files_by_name(), FileSorting::ByName => self.sort_files_by_name(),
FileSorting::ByCreationTime => self.sort_files_by_creation_time(), FileSorting::ByCreationTime => self.sort_files_by_creation_time(),
FileSorting::ByModifyTime => self.sort_files_by_mtime(), FileSorting::ByModifyTime => self.sort_files_by_mtime(),
FileSorting::BySize => self.sort_files_by_size(),
} }
// Directories first (NOTE: MUST COME AFTER OTHER SORTING) // Directories first (NOTE: MUST COME AFTER OTHER SORTING)
// Group directories if necessary // Group directories if necessary
@@ -240,6 +242,14 @@ impl FileExplorer {
.sort_by(|a: &FsEntry, b: &FsEntry| b.get_creation_time().cmp(&a.get_creation_time())); .sort_by(|a: &FsEntry, b: &FsEntry| b.get_creation_time().cmp(&a.get_creation_time()));
} }
/// ### sort_files_by_size
///
/// Sort files by size
fn sort_files_by_size(&mut self) {
self.files
.sort_by(|a: &FsEntry, b: &FsEntry| b.get_size().cmp(&a.get_size()));
}
/// ### sort_files_directories_first /// ### sort_files_directories_first
/// ///
/// Sort files; directories come first /// Sort files; directories come first
@@ -442,6 +452,7 @@ impl ToString for FileSorting {
FileSorting::ByCreationTime => "by_creation_time", FileSorting::ByCreationTime => "by_creation_time",
FileSorting::ByModifyTime => "by_mtime", FileSorting::ByModifyTime => "by_mtime",
FileSorting::ByName => "by_name", FileSorting::ByName => "by_name",
FileSorting::BySize => "by_size",
}) })
} }
} }
@@ -453,6 +464,7 @@ impl FromStr for FileSorting {
"by_creation_time" => Ok(FileSorting::ByCreationTime), "by_creation_time" => Ok(FileSorting::ByCreationTime),
"by_mtime" => Ok(FileSorting::ByModifyTime), "by_mtime" => Ok(FileSorting::ByModifyTime),
"by_name" => Ok(FileSorting::ByName), "by_name" => Ok(FileSorting::ByName),
"by_size" => Ok(FileSorting::BySize),
_ => Err(()), _ => Err(()),
} }
} }
@@ -733,6 +745,22 @@ mod tests {
assert_eq!(explorer.files.get(1).unwrap().get_name(), "README.md"); assert_eq!(explorer.files.get(1).unwrap().get_name(), "README.md");
} }
#[test]
fn test_fs_explorer_sort_by_size() {
let mut explorer: FileExplorer = FileExplorer::default();
// Create files (files are then sorted by name)
explorer.set_files(vec![
make_fs_entry_with_size("README.md", false, 1024),
make_fs_entry("src/", true),
make_fs_entry_with_size("CONTRIBUTING.md", false, 256),
]);
explorer.sort_by(FileSorting::BySize);
// Directory has size 4096
assert_eq!(explorer.files.get(0).unwrap().get_name(), "src/");
assert_eq!(explorer.files.get(1).unwrap().get_name(), "README.md");
assert_eq!(explorer.files.get(2).unwrap().get_name(), "CONTRIBUTING.md");
}
#[test] #[test]
fn test_fs_explorer_sort_by_name_and_dirs_first() { fn test_fs_explorer_sort_by_name_and_dirs_first() {
let mut explorer: FileExplorer = FileExplorer::default(); let mut explorer: FileExplorer = FileExplorer::default();
@@ -793,6 +821,7 @@ mod tests {
assert_eq!(FileSorting::ByCreationTime.to_string(), "by_creation_time"); assert_eq!(FileSorting::ByCreationTime.to_string(), "by_creation_time");
assert_eq!(FileSorting::ByModifyTime.to_string(), "by_mtime"); assert_eq!(FileSorting::ByModifyTime.to_string(), "by_mtime");
assert_eq!(FileSorting::ByName.to_string(), "by_name"); assert_eq!(FileSorting::ByName.to_string(), "by_name");
assert_eq!(FileSorting::BySize.to_string(), "by_size");
assert_eq!( assert_eq!(
FileSorting::from_str("by_creation_time").ok().unwrap(), FileSorting::from_str("by_creation_time").ok().unwrap(),
FileSorting::ByCreationTime FileSorting::ByCreationTime
@@ -805,6 +834,10 @@ mod tests {
FileSorting::from_str("by_name").ok().unwrap(), FileSorting::from_str("by_name").ok().unwrap(),
FileSorting::ByName FileSorting::ByName
); );
assert_eq!(
FileSorting::from_str("by_size").ok().unwrap(),
FileSorting::BySize
);
assert!(FileSorting::from_str("omar").is_err()); assert!(FileSorting::from_str("omar").is_err());
// Group dirs // Group dirs
assert_eq!(GroupDirs::First.to_string(), "first"); assert_eq!(GroupDirs::First.to_string(), "first");
@@ -845,4 +878,36 @@ mod tests {
}), }),
} }
} }
fn make_fs_entry_with_size(name: &str, is_dir: bool, size: usize) -> FsEntry {
let t_now: SystemTime = SystemTime::now();
match is_dir {
false => FsEntry::File(FsFile {
name: name.to_string(),
abs_path: PathBuf::from(name),
last_change_time: t_now,
last_access_time: t_now,
creation_time: t_now,
size: size,
ftype: None, // File type
readonly: false,
symlink: None, // UNIX only
user: Some(0), // UNIX only
group: Some(0), // UNIX only
unix_pex: Some((6, 4, 4)), // UNIX only
}),
true => FsEntry::Directory(FsDirectory {
name: name.to_string(),
abs_path: PathBuf::from(name),
last_change_time: t_now,
last_access_time: t_now,
creation_time: t_now,
readonly: false,
symlink: None, // UNIX only
user: Some(0), // UNIX only
group: Some(0), // UNIX only
unix_pex: Some((7, 5, 5)), // UNIX only
}),
}
}
} }

View File

@@ -23,13 +23,15 @@
* *
*/ */
// Deps
extern crate tempfile; extern crate tempfile;
// Local
use super::{ use super::{
DialogCallback, DialogYesNoOption, FileExplorerTab, FileTransferActivity, FsEntry, InputEvent, DialogCallback, DialogYesNoOption, FileExplorerTab, FileTransferActivity, FsEntry, InputEvent,
InputField, InputMode, LogLevel, OnInputSubmitCallback, PopupType, InputField, InputMode, LogLevel, OnInputSubmitCallback, PopupType,
}; };
use crate::fs::explorer::{FileExplorer, FileSorting};
// Ext
use crossterm::event::{KeyCode, KeyModifiers}; use crossterm::event::{KeyCode, KeyModifiers};
use std::path::PathBuf; use std::path::PathBuf;
@@ -59,7 +61,7 @@ impl FileTransferActivity {
/// ### handle_input_event /// ### handle_input_event
/// ///
/// Handle input event based on current input mode /// Handle input event based on current input mode
pub(super) fn handle_input_event(&mut self, ev: &InputEvent) { fn handle_input_event(&mut self, ev: &InputEvent) {
// NOTE: this is necessary due to this <https://github.com/rust-lang/rust/issues/59159> // NOTE: this is necessary due to this <https://github.com/rust-lang/rust/issues/59159>
// NOTE: Do you want my opinion about that issue? It's a bs and doesn't make any sense. // NOTE: Do you want my opinion about that issue? It's a bs and doesn't make any sense.
let popup: Option<PopupType> = match &self.input_mode { let popup: Option<PopupType> = match &self.input_mode {
@@ -79,7 +81,7 @@ impl FileTransferActivity {
/// ### handle_input_event_mode_explorer /// ### handle_input_event_mode_explorer
/// ///
/// Input event handler for explorer mode /// Input event handler for explorer mode
pub(super) fn handle_input_event_mode_explorer(&mut self, ev: &InputEvent) { fn handle_input_event_mode_explorer(&mut self, ev: &InputEvent) {
// Match input field // Match input field
match self.input_field { match self.input_field {
InputField::Explorer => match self.tab { InputField::Explorer => match self.tab {
@@ -94,7 +96,7 @@ impl FileTransferActivity {
/// ### handle_input_event_mode_explorer_tab_local /// ### handle_input_event_mode_explorer_tab_local
/// ///
/// Input event handler for explorer mode when localhost tab is selected /// Input event handler for explorer mode when localhost tab is selected
pub(super) fn handle_input_event_mode_explorer_tab_local(&mut self, ev: &InputEvent) { fn handle_input_event_mode_explorer_tab_local(&mut self, ev: &InputEvent) {
// Match events // Match events
if let InputEvent::Key(key) = ev { if let InputEvent::Key(key) = ev {
match key.code { match key.code {
@@ -172,6 +174,10 @@ impl FileTransferActivity {
// Toggle hidden files // Toggle hidden files
self.local.toggle_hidden_files(); self.local.toggle_hidden_files();
} }
'b' | 'B' => {
// Choose file sorting type
self.input_mode = InputMode::Popup(PopupType::FileSortingDialog);
}
'c' | 'C' => { 'c' | 'C' => {
// Copy // Copy
self.input_mode = InputMode::Popup(PopupType::Input( self.input_mode = InputMode::Popup(PopupType::Input(
@@ -309,7 +315,7 @@ impl FileTransferActivity {
/// ### handle_input_event_mode_explorer_tab_local /// ### handle_input_event_mode_explorer_tab_local
/// ///
/// Input event handler for explorer mode when remote tab is selected /// Input event handler for explorer mode when remote tab is selected
pub(super) fn handle_input_event_mode_explorer_tab_remote(&mut self, ev: &InputEvent) { fn handle_input_event_mode_explorer_tab_remote(&mut self, ev: &InputEvent) {
// Match events // Match events
if let InputEvent::Key(key) = ev { if let InputEvent::Key(key) = ev {
match key.code { match key.code {
@@ -387,6 +393,10 @@ impl FileTransferActivity {
// Toggle hidden files // Toggle hidden files
self.remote.toggle_hidden_files(); self.remote.toggle_hidden_files();
} }
'b' | 'B' => {
// Choose file sorting type
self.input_mode = InputMode::Popup(PopupType::FileSortingDialog);
}
'c' | 'C' => { 'c' | 'C' => {
// Copy // Copy
self.input_mode = InputMode::Popup(PopupType::Input( self.input_mode = InputMode::Popup(PopupType::Input(
@@ -521,7 +531,7 @@ impl FileTransferActivity {
/// ### handle_input_event_mode_explorer_log /// ### handle_input_event_mode_explorer_log
/// ///
/// Input even handler for explorer mode when log tab is selected /// Input even handler for explorer mode when log tab is selected
pub(super) fn handle_input_event_mode_explorer_log(&mut self, ev: &InputEvent) { fn handle_input_event_mode_explorer_log(&mut self, ev: &InputEvent) {
// Match event // Match event
let records_block: usize = 16; let records_block: usize = 16;
if let InputEvent::Key(key) = ev { if let InputEvent::Key(key) = ev {
@@ -580,12 +590,13 @@ impl FileTransferActivity {
/// ### handle_input_event_mode_explorer /// ### handle_input_event_mode_explorer
/// ///
/// Input event handler for popup mode. Handler is then based on Popup type /// Input event handler for popup mode. Handler is then based on Popup type
pub(super) fn handle_input_event_mode_popup(&mut self, ev: &InputEvent, popup: PopupType) { fn handle_input_event_mode_popup(&mut self, ev: &InputEvent, popup: PopupType) {
match popup { match popup {
PopupType::Alert(_, _) => self.handle_input_event_mode_popup_alert(ev), PopupType::Alert(_, _) => self.handle_input_event_mode_popup_alert(ev),
PopupType::FileInfo => self.handle_input_event_mode_popup_fileinfo(ev), PopupType::FileInfo => self.handle_input_event_mode_popup_fileinfo(ev),
PopupType::Help => self.handle_input_event_mode_popup_help(ev),
PopupType::Fatal(_) => self.handle_input_event_mode_popup_fatal(ev), PopupType::Fatal(_) => self.handle_input_event_mode_popup_fatal(ev),
PopupType::FileSortingDialog => self.handle_input_event_mode_popup_file_sorting(ev),
PopupType::Help => self.handle_input_event_mode_popup_help(ev),
PopupType::Input(_, cb) => self.handle_input_event_mode_popup_input(ev, cb), PopupType::Input(_, cb) => self.handle_input_event_mode_popup_input(ev, cb),
PopupType::Progress(_) => self.handle_input_event_mode_popup_progress(ev), PopupType::Progress(_) => self.handle_input_event_mode_popup_progress(ev),
PopupType::Wait(_) => self.handle_input_event_mode_popup_wait(ev), PopupType::Wait(_) => self.handle_input_event_mode_popup_wait(ev),
@@ -598,7 +609,7 @@ impl FileTransferActivity {
/// ### handle_input_event_mode_popup_alert /// ### handle_input_event_mode_popup_alert
/// ///
/// Input event handler for popup alert /// Input event handler for popup alert
pub(super) fn handle_input_event_mode_popup_alert(&mut self, ev: &InputEvent) { fn handle_input_event_mode_popup_alert(&mut self, ev: &InputEvent) {
// If enter, close popup // If enter, close popup
if let InputEvent::Key(key) = ev { if let InputEvent::Key(key) = ev {
if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) {
@@ -611,20 +622,7 @@ impl FileTransferActivity {
/// ### handle_input_event_mode_popup_fileinfo /// ### handle_input_event_mode_popup_fileinfo
/// ///
/// Input event handler for popup fileinfo /// Input event handler for popup fileinfo
pub(super) fn handle_input_event_mode_popup_fileinfo(&mut self, ev: &InputEvent) { fn handle_input_event_mode_popup_fileinfo(&mut self, ev: &InputEvent) {
// If enter, close popup
if let InputEvent::Key(key) = ev {
if matches!(key.code, KeyCode::Esc | KeyCode::Enter) {
// Set input mode back to explorer
self.input_mode = InputMode::Explorer;
}
}
}
/// ### handle_input_event_mode_popup_help
///
/// Input event handler for popup help
pub(super) fn handle_input_event_mode_popup_help(&mut self, ev: &InputEvent) {
// If enter, close popup // If enter, close popup
if let InputEvent::Key(key) = ev { if let InputEvent::Key(key) = ev {
if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) {
@@ -637,7 +635,7 @@ impl FileTransferActivity {
/// ### handle_input_event_mode_popup_fatal /// ### handle_input_event_mode_popup_fatal
/// ///
/// Input event handler for popup alert /// Input event handler for popup alert
pub(super) fn handle_input_event_mode_popup_fatal(&mut self, ev: &InputEvent) { fn handle_input_event_mode_popup_fatal(&mut self, ev: &InputEvent) {
// If enter, close popup // If enter, close popup
if let InputEvent::Key(key) = ev { if let InputEvent::Key(key) = ev {
if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) {
@@ -647,14 +645,61 @@ impl FileTransferActivity {
} }
} }
/// ### handle_input_event_mode_popup_file_sorting
///
/// Handle input event for file sorting dialog popup
fn handle_input_event_mode_popup_file_sorting(&mut self, ev: &InputEvent) {
// Match key code
if let InputEvent::Key(key) = ev {
match key.code {
KeyCode::Esc | KeyCode::Enter => {
// Exit
self.input_mode = InputMode::Explorer;
}
KeyCode::Right => {
// Update sorting mode
match self.tab {
FileExplorerTab::Local => {
Self::move_sorting_mode_opt_right(&mut self.local);
}
FileExplorerTab::Remote => {
Self::move_sorting_mode_opt_right(&mut self.remote);
}
}
}
KeyCode::Left => {
// Update sorting mode
match self.tab {
FileExplorerTab::Local => {
Self::move_sorting_mode_opt_left(&mut self.local);
}
FileExplorerTab::Remote => {
Self::move_sorting_mode_opt_left(&mut self.remote);
}
}
}
_ => { /* Nothing to do */ }
}
}
}
/// ### handle_input_event_mode_popup_help
///
/// Input event handler for popup help
fn handle_input_event_mode_popup_help(&mut self, ev: &InputEvent) {
// If enter, close popup
if let InputEvent::Key(key) = ev {
if matches!(key.code, KeyCode::Esc | KeyCode::Enter) {
// Set input mode back to explorer
self.input_mode = InputMode::Explorer;
}
}
}
/// ### handle_input_event_mode_popup_input /// ### handle_input_event_mode_popup_input
/// ///
/// Input event handler for input popup /// Input event handler for input popup
pub(super) fn handle_input_event_mode_popup_input( fn handle_input_event_mode_popup_input(&mut self, ev: &InputEvent, cb: OnInputSubmitCallback) {
&mut self,
ev: &InputEvent,
cb: OnInputSubmitCallback,
) {
// If enter, close popup, otherwise push chars to input // If enter, close popup, otherwise push chars to input
if let InputEvent::Key(key) = ev { if let InputEvent::Key(key) = ev {
match key.code { match key.code {
@@ -687,7 +732,7 @@ impl FileTransferActivity {
/// ### handle_input_event_mode_popup_progress /// ### handle_input_event_mode_popup_progress
/// ///
/// Input event handler for popup alert /// Input event handler for popup alert
pub(super) fn handle_input_event_mode_popup_progress(&mut self, ev: &InputEvent) { fn handle_input_event_mode_popup_progress(&mut self, ev: &InputEvent) {
if let InputEvent::Key(key) = ev { if let InputEvent::Key(key) = ev {
if let KeyCode::Char(ch) = key.code { if let KeyCode::Char(ch) = key.code {
// If is 'C' and CTRL // If is 'C' and CTRL
@@ -702,14 +747,14 @@ impl FileTransferActivity {
/// ### handle_input_event_mode_popup_wait /// ### handle_input_event_mode_popup_wait
/// ///
/// Input event handler for popup alert /// Input event handler for popup alert
pub(super) fn handle_input_event_mode_popup_wait(&mut self, _ev: &InputEvent) { fn handle_input_event_mode_popup_wait(&mut self, _ev: &InputEvent) {
// There's nothing you can do here I guess... maybe ctrl+c in the future idk // There's nothing you can do here I guess... maybe ctrl+c in the future idk
} }
/// ### handle_input_event_mode_popup_yesno /// ### handle_input_event_mode_popup_yesno
/// ///
/// Input event handler for popup alert /// Input event handler for popup alert
pub(super) fn handle_input_event_mode_popup_yesno( fn handle_input_event_mode_popup_yesno(
&mut self, &mut self,
ev: &InputEvent, ev: &InputEvent,
yes_cb: DialogCallback, yes_cb: DialogCallback,
@@ -735,4 +780,30 @@ impl FileTransferActivity {
} }
} }
} }
/// ### move_sorting_mode_opt_left
///
/// Perform <LEFT> on file sorting dialog
fn move_sorting_mode_opt_left(explorer: &mut FileExplorer) {
let curr_sorting: FileSorting = explorer.get_file_sorting();
explorer.sort_by(match curr_sorting {
FileSorting::BySize => FileSorting::ByCreationTime,
FileSorting::ByCreationTime => FileSorting::ByModifyTime,
FileSorting::ByModifyTime => FileSorting::ByName,
FileSorting::ByName => FileSorting::BySize, // Wrap
});
}
/// ### move_sorting_mode_opt_left
///
/// Perform <RIGHT> on file sorting dialog
fn move_sorting_mode_opt_right(explorer: &mut FileExplorer) {
let curr_sorting: FileSorting = explorer.get_file_sorting();
explorer.sort_by(match curr_sorting {
FileSorting::ByName => FileSorting::ByModifyTime,
FileSorting::ByModifyTime => FileSorting::ByCreationTime,
FileSorting::ByCreationTime => FileSorting::BySize,
FileSorting::BySize => FileSorting::ByName, // Wrap
});
}
} }

View File

@@ -23,17 +23,19 @@
* *
*/ */
// Deps
extern crate bytesize; extern crate bytesize;
extern crate hostname; extern crate hostname;
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
extern crate users; extern crate users;
// Local
use super::{ use super::{
Context, DialogYesNoOption, FileExplorerTab, FileTransferActivity, FsEntry, InputField, Context, DialogYesNoOption, FileExplorerTab, FileTransferActivity, FsEntry, InputField,
InputMode, LogLevel, LogRecord, PopupType, InputMode, LogLevel, LogRecord, PopupType,
}; };
use crate::fs::explorer::{FileExplorer, FileSorting};
use crate::utils::fmt::{align_text_center, fmt_time}; use crate::utils::fmt::{align_text_center, fmt_time};
// Ext
use bytesize::ByteSize; use bytesize::ByteSize;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use tui::{ use tui::{
@@ -105,6 +107,7 @@ impl FileTransferActivity {
PopupType::Alert(_, _) => (50, 10), PopupType::Alert(_, _) => (50, 10),
PopupType::Fatal(_) => (50, 10), PopupType::Fatal(_) => (50, 10),
PopupType::FileInfo => (50, 50), PopupType::FileInfo => (50, 50),
PopupType::FileSortingDialog => (50, 10),
PopupType::Help => (50, 80), PopupType::Help => (50, 80),
PopupType::Input(_, _) => (40, 10), PopupType::Input(_, _) => (40, 10),
PopupType::Progress(_) => (40, 10), PopupType::Progress(_) => (40, 10),
@@ -123,6 +126,9 @@ impl FileTransferActivity {
popup_area, popup_area,
), ),
PopupType::FileInfo => f.render_widget(self.draw_popup_fileinfo(), popup_area), PopupType::FileInfo => f.render_widget(self.draw_popup_fileinfo(), popup_area),
PopupType::FileSortingDialog => {
f.render_widget(self.draw_popup_file_sorting_dialog(), popup_area)
}
PopupType::Help => f.render_widget(self.draw_popup_help(), popup_area), PopupType::Help => f.render_widget(self.draw_popup_help(), popup_area),
PopupType::Input(txt, _) => { PopupType::Input(txt, _) => {
f.render_widget(self.draw_popup_input(txt.clone()), popup_area); f.render_widget(self.draw_popup_input(txt.clone()), popup_area);
@@ -367,6 +373,44 @@ impl FileTransferActivity {
.start_corner(Corner::TopLeft) .start_corner(Corner::TopLeft)
.style(Style::default().fg(Color::Red)) .style(Style::default().fg(Color::Red))
} }
/// ### draw_popup_file_sorting_dialog
///
/// Draw FileSorting mode select popup
pub(super) fn draw_popup_file_sorting_dialog(&self) -> Tabs {
let choices: Vec<Spans> = vec![
Spans::from("Name"),
Spans::from("Modify time"),
Spans::from("Creation time"),
Spans::from("Size"),
];
let explorer: &FileExplorer = match self.tab {
FileExplorerTab::Local => &self.local,
FileExplorerTab::Remote => &self.remote,
};
let index: usize = match explorer.get_file_sorting() {
FileSorting::ByCreationTime => 2,
FileSorting::ByModifyTime => 1,
FileSorting::ByName => 0,
FileSorting::BySize => 3,
};
Tabs::new(choices)
.block(
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.title("Sort files by"),
)
.select(index)
.style(Style::default())
.highlight_style(
Style::default()
.add_modifier(Modifier::BOLD)
.bg(Color::LightMagenta)
.fg(Color::DarkGray),
)
}
/// ### draw_popup_input /// ### draw_popup_input
/// ///
/// Draw input popup /// Draw input popup
@@ -727,6 +771,16 @@ impl FileTransferActivity {
Span::raw(" "), Span::raw(" "),
Span::raw("Toggle hidden files"), Span::raw("Toggle hidden files"),
])), ])),
ListItem::new(Spans::from(vec![
Span::styled(
"<B>",
Style::default()
.fg(Color::Cyan)
.add_modifier(Modifier::BOLD),
),
Span::raw(" "),
Span::raw("Change file sorting mode"),
])),
ListItem::new(Spans::from(vec![ ListItem::new(Spans::from(vec![
Span::styled( Span::styled(
"<C>", "<C>",

View File

@@ -97,6 +97,7 @@ enum PopupType {
Alert(Color, String), // Block color; Block text Alert(Color, String), // Block color; Block text
Fatal(String), // Must quit after being hidden Fatal(String), // Must quit after being hidden
FileInfo, // Show info about current file FileInfo, // Show info about current file
FileSortingDialog, // Dialog for choosing file sorting type
Help, // Show Help Help, // Show Help
Input(String, OnInputSubmitCallback), // Input description; Callback for submit Input(String, OnInputSubmitCallback), // Input description; Callback for submit
Progress(String), // Progress block text Progress(String), // Progress block text