mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
FileTransferActivity: sort files with <B>
This commit is contained in:
@@ -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`
|
||||||
|
|||||||
@@ -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 |
|
||||||
|
|||||||
@@ -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
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user