FileTransferActivity::Explorer refactoring; toggle hidden files with <A>
This commit is contained in:
parent
5b042e86ef
commit
e0d9ac2ed8
|
@ -35,7 +35,10 @@ FIXME: Released on
|
|||
- Enhancements:
|
||||
- Replaced `sha256` sum with last modification time check, to verify if a file has been changed in the text editor
|
||||
- Default protocol changed to default protocol in configuration when providing address as CLI argument
|
||||
- Explorers:
|
||||
- Hidden files are now not shown by default; use `A` to show hidden files.
|
||||
- Keybindings:
|
||||
- `A`: Toggle hidden files
|
||||
- `N`: New file
|
||||
- Dependencies:
|
||||
- removed `data-encoding`
|
||||
|
|
|
@ -290,9 +290,10 @@ You can access the SSH key storage, from configuration moving to the `SSH Keys`
|
|||
| `<PGDOWN>` | Move down in selected list by 8 rows | |
|
||||
| `<ENTER>` | Enter directory | |
|
||||
| `<SPACE>` | Upload / download selected file | |
|
||||
| `<A>` | Toggle hidden files | All |
|
||||
| `<C>` | Copy file/directory | Copy |
|
||||
| `<D>` | Make directory | Directory |
|
||||
| `<E>` | Delete file (Same as `CANC`) | Erase |
|
||||
| `<E>` | Delete file (Same as `DEL`) | Erase |
|
||||
| `<G>` | Go to supplied path | Go to |
|
||||
| `<H>` | Show help | Help |
|
||||
| `<I>` | Show info about selected file or directory | Info |
|
||||
|
|
|
@ -212,7 +212,7 @@ impl FsEntry {
|
|||
///
|
||||
/// Returns whether FsEntry is hidden
|
||||
pub fn is_hidden(&self) -> bool {
|
||||
self.get_name().starts_with(".")
|
||||
self.get_name().starts_with('.')
|
||||
}
|
||||
|
||||
/// ### get_realfile
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
//! ## FileTransferActivity
|
||||
//!
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
|
||||
|
@ -71,8 +75,8 @@ impl FileTransferActivity {
|
|||
match self.tab {
|
||||
FileExplorerTab::Local => {
|
||||
// Get selected entry
|
||||
if self.local.files.get(self.local.index).is_some() {
|
||||
let entry: FsEntry = self.local.files.get(self.local.index).unwrap().clone();
|
||||
if self.local.get_current_file().is_some() {
|
||||
let entry: FsEntry = self.local.get_current_file().unwrap().clone();
|
||||
if let Some(ctx) = self.context.as_mut() {
|
||||
match ctx.local.copy(&entry, dest_path.as_path()) {
|
||||
Ok(_) => {
|
||||
|
@ -104,8 +108,8 @@ impl FileTransferActivity {
|
|||
}
|
||||
FileExplorerTab::Remote => {
|
||||
// Get selected entry
|
||||
if self.remote.files.get(self.remote.index).is_some() {
|
||||
let entry: FsEntry = self.remote.files.get(self.remote.index).unwrap().clone();
|
||||
if self.remote.get_current_file().is_some() {
|
||||
let entry: FsEntry = self.remote.get_current_file().unwrap().clone();
|
||||
match self.client.as_mut().copy(&entry, dest_path.as_path()) {
|
||||
Ok(_) => {
|
||||
self.log(
|
||||
|
@ -205,7 +209,7 @@ impl FileTransferActivity {
|
|||
dst_path = wrkdir;
|
||||
}
|
||||
// Check if file entry exists
|
||||
if let Some(entry) = self.local.files.get(self.local.index) {
|
||||
if let Some(entry) = self.local.get_current_file() {
|
||||
let full_path: PathBuf = entry.get_abs_path();
|
||||
// Rename file or directory and report status as popup
|
||||
match self
|
||||
|
@ -245,7 +249,7 @@ impl FileTransferActivity {
|
|||
}
|
||||
FileExplorerTab::Remote => {
|
||||
// Check if file entry exists
|
||||
if let Some(entry) = self.remote.files.get(self.remote.index) {
|
||||
if let Some(entry) = self.remote.get_current_file() {
|
||||
let full_path: PathBuf = entry.get_abs_path();
|
||||
// Rename file or directory and report status as popup
|
||||
let dst_path: PathBuf = PathBuf::from(input);
|
||||
|
@ -289,7 +293,7 @@ impl FileTransferActivity {
|
|||
match self.tab {
|
||||
FileExplorerTab::Local => {
|
||||
// Check if file entry exists
|
||||
if let Some(entry) = self.local.files.get(self.local.index) {
|
||||
if let Some(entry) = self.local.get_current_file() {
|
||||
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) {
|
||||
|
@ -318,7 +322,7 @@ impl FileTransferActivity {
|
|||
}
|
||||
FileExplorerTab::Remote => {
|
||||
// Check if file entry exists
|
||||
if let Some(entry) = self.remote.files.get(self.remote.index) {
|
||||
if let Some(entry) = self.remote.get_current_file() {
|
||||
let full_path: PathBuf = entry.get_abs_path();
|
||||
// Delete file
|
||||
match self.client.remove(entry) {
|
||||
|
@ -355,16 +359,16 @@ impl FileTransferActivity {
|
|||
// Get pwd
|
||||
let wrkdir: PathBuf = self.remote.wrkdir.clone();
|
||||
// Get file and clone (due to mutable / immutable stuff...)
|
||||
if self.local.files.get(self.local.index).is_some() {
|
||||
let file: FsEntry = self.local.files.get(self.local.index).unwrap().clone();
|
||||
if self.local.get_current_file().is_some() {
|
||||
let file: FsEntry = self.local.get_current_file().unwrap().clone();
|
||||
// Call upload; pass realfile, keep link name
|
||||
self.filetransfer_send(&file.get_realfile(), wrkdir.as_path(), Some(input));
|
||||
}
|
||||
}
|
||||
FileExplorerTab::Remote => {
|
||||
// Get file and clone (due to mutable / immutable stuff...)
|
||||
if self.remote.files.get(self.remote.index).is_some() {
|
||||
let file: FsEntry = self.remote.files.get(self.remote.index).unwrap().clone();
|
||||
if self.remote.get_current_file().is_some() {
|
||||
let file: FsEntry = self.remote.get_current_file().unwrap().clone();
|
||||
// Call upload; pass realfile, keep link name
|
||||
let wrkdir: PathBuf = self.local.wrkdir.clone();
|
||||
self.filetransfer_recv(&file.get_realfile(), wrkdir.as_path(), Some(input));
|
||||
|
@ -380,15 +384,19 @@ impl FileTransferActivity {
|
|||
match self.tab {
|
||||
FileExplorerTab::Local => {
|
||||
// Check if file exists
|
||||
for file in self.local.files.iter() {
|
||||
let mut file_exists: bool = false;
|
||||
for file in self.local.iter_files_all() {
|
||||
if input == file.get_name() {
|
||||
self.log_and_alert(
|
||||
LogLevel::Warn,
|
||||
format!("File \"{}\" already exists", input,),
|
||||
);
|
||||
return;
|
||||
file_exists = true;
|
||||
}
|
||||
}
|
||||
if file_exists {
|
||||
self.log_and_alert(
|
||||
LogLevel::Warn,
|
||||
format!("File \"{}\" already exists", input,),
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Create file
|
||||
let file_path: PathBuf = PathBuf::from(input.as_str());
|
||||
if let Some(ctx) = self.context.as_mut() {
|
||||
|
@ -409,15 +417,19 @@ impl FileTransferActivity {
|
|||
}
|
||||
FileExplorerTab::Remote => {
|
||||
// Check if file exists
|
||||
for file in self.remote.files.iter() {
|
||||
let mut file_exists: bool = false;
|
||||
for file in self.remote.iter_files_all() {
|
||||
if input == file.get_name() {
|
||||
self.log_and_alert(
|
||||
LogLevel::Warn,
|
||||
format!("File \"{}\" already exists", input,),
|
||||
);
|
||||
return;
|
||||
file_exists = true;
|
||||
}
|
||||
}
|
||||
if file_exists {
|
||||
self.log_and_alert(
|
||||
LogLevel::Warn,
|
||||
format!("File \"{}\" already exists", input,),
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Get path on remote
|
||||
let file_path: PathBuf = PathBuf::from(input.as_str());
|
||||
// Create file (on local)
|
||||
|
|
532
src/ui/activities/filetransfer_activity/explorer.rs
Normal file
532
src/ui/activities/filetransfer_activity/explorer.rs
Normal file
|
@ -0,0 +1,532 @@
|
|||
//! ## FileTransferActivity
|
||||
//!
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
|
||||
*
|
||||
* This file is part of "TermSCP"
|
||||
*
|
||||
* TermSCP is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* TermSCP is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with TermSCP. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Locals
|
||||
use super::FsEntry;
|
||||
// Ext
|
||||
use std::collections::VecDeque;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// ## FileExplorer
|
||||
///
|
||||
/// File explorer states
|
||||
pub struct FileExplorer {
|
||||
pub wrkdir: PathBuf, // Current directory
|
||||
index: usize, // Selected file
|
||||
files: Vec<FsEntry>, // Files in directory
|
||||
dirstack: VecDeque<PathBuf>, // Stack of visited directory (max 16)
|
||||
stack_size: usize, // Directory stack size
|
||||
hidden_files: bool, // Should hidden files be shown or not; hidden if false
|
||||
}
|
||||
|
||||
impl FileExplorer {
|
||||
/// ### new
|
||||
///
|
||||
/// Instantiates a new FileExplorer
|
||||
pub fn new(stack_size: usize) -> FileExplorer {
|
||||
FileExplorer {
|
||||
wrkdir: PathBuf::from("/"),
|
||||
index: 0,
|
||||
files: Vec::new(),
|
||||
dirstack: VecDeque::with_capacity(stack_size),
|
||||
stack_size,
|
||||
hidden_files: false, // Default: don't show hidden files
|
||||
}
|
||||
}
|
||||
|
||||
/// ### pushd
|
||||
///
|
||||
/// push directory to stack
|
||||
pub fn pushd(&mut self, dir: &Path) {
|
||||
// Check if stack would overflow the size
|
||||
while self.dirstack.len() >= self.stack_size {
|
||||
self.dirstack.pop_front(); // Start cleaning events from back
|
||||
}
|
||||
// Eventually push front the new record
|
||||
self.dirstack.push_back(PathBuf::from(dir));
|
||||
}
|
||||
|
||||
/// ### popd
|
||||
///
|
||||
/// Pop directory from the stack and return the directory
|
||||
pub fn popd(&mut self) -> Option<PathBuf> {
|
||||
self.dirstack.pop_back()
|
||||
}
|
||||
|
||||
/// ### set_files
|
||||
///
|
||||
/// Set Explorer files
|
||||
/// Index is then moved to first valid `FsEntry` for current setup
|
||||
pub fn set_files(&mut self, files: Vec<FsEntry>) {
|
||||
self.files = files;
|
||||
// Set index to first valid entry
|
||||
self.index_at_first();
|
||||
}
|
||||
|
||||
/// ### count
|
||||
///
|
||||
/// Return amount of files
|
||||
pub fn count(&self) -> usize {
|
||||
self.files.len()
|
||||
}
|
||||
|
||||
/// ### iter_files
|
||||
///
|
||||
/// Iterate over files
|
||||
/// Filters are applied based on current options (e.g. hidden files not returned)
|
||||
pub fn iter_files(&self) -> Box<dyn Iterator<Item = &FsEntry> + '_> {
|
||||
// Match options
|
||||
match self.hidden_files {
|
||||
false => Box::new(self.files.iter().filter(|x| !x.is_hidden())), // Show only visible files
|
||||
true => self.iter_files_all(), // Show all
|
||||
}
|
||||
}
|
||||
|
||||
/// ### iter_files_all
|
||||
///
|
||||
/// Iterate all files; doesn't care about options
|
||||
pub fn iter_files_all(&self) -> Box<dyn Iterator<Item = &FsEntry> + '_> {
|
||||
Box::new(self.files.iter())
|
||||
}
|
||||
|
||||
/// ### get_current_file
|
||||
///
|
||||
/// Get file at index
|
||||
pub fn get_current_file(&self) -> Option<&FsEntry> {
|
||||
self.files.get(self.index)
|
||||
}
|
||||
|
||||
/// ### sort_files_by_name
|
||||
///
|
||||
/// Sort explorer files by their name. All names are converted to lowercase
|
||||
pub fn sort_files_by_name(&mut self) {
|
||||
self.files.sort_by_key(|x: &FsEntry| match x {
|
||||
FsEntry::Directory(dir) => dir.name.as_str().to_lowercase(),
|
||||
FsEntry::File(file) => file.name.as_str().to_lowercase(),
|
||||
});
|
||||
// Reset index
|
||||
self.index_at_first();
|
||||
}
|
||||
|
||||
/// ### incr_index
|
||||
///
|
||||
/// Increment index to the first visible FsEntry.
|
||||
/// If index goes to `files.len() - 1`, the value will be seto to the minimum acceptable value
|
||||
pub fn incr_index(&mut self) {
|
||||
let sz: usize = self.files.len();
|
||||
// Increment or wrap
|
||||
if self.index + 1 >= sz {
|
||||
self.index = 0; // Wrap
|
||||
} else {
|
||||
self.index += 1; // Increment
|
||||
}
|
||||
// Validate
|
||||
match self.files.get(self.index) {
|
||||
Some(assoc_entry) => {
|
||||
if !self.hidden_files {
|
||||
// Check if file is hidden, otherwise increment
|
||||
if assoc_entry.is_hidden() {
|
||||
// Check if all files are hidden (NOTE: PREVENT STACK OVERFLOWS)
|
||||
let hidden_files: usize =
|
||||
self.files.iter().filter(|x| x.is_hidden()).count();
|
||||
// Only if there are more files, than hidden files keep incrementing
|
||||
if sz > hidden_files {
|
||||
self.incr_index();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => self.index = 0, // Reset to 0, for safety reasons
|
||||
}
|
||||
}
|
||||
|
||||
/// ### incr_index_by
|
||||
///
|
||||
/// Increment index by up to n
|
||||
/// If index goes to `files.len() - 1`, the value will be seto to the minimum acceptable value
|
||||
pub fn incr_index_by(&mut self, n: usize) {
|
||||
for _ in 0..n {
|
||||
let prev_idx: usize = self.index;
|
||||
// Increment
|
||||
self.incr_index();
|
||||
// If prev index is > index and break
|
||||
if prev_idx > self.index {
|
||||
self.index = prev_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ### decr_index
|
||||
///
|
||||
/// Decrement index to the first visible FsEntry.
|
||||
/// If index is 0, its value will be set to the maximum acceptable value
|
||||
pub fn decr_index(&mut self) {
|
||||
let sz: usize = self.files.len();
|
||||
// Increment or wrap
|
||||
if self.index > 0 {
|
||||
self.index -= 1; // Decrement
|
||||
} else {
|
||||
self.index = sz - 1; // Wrap
|
||||
}
|
||||
// Validate index
|
||||
match self.files.get(self.index) {
|
||||
Some(assoc_entry) => {
|
||||
if !self.hidden_files {
|
||||
// Check if file is hidden, otherwise increment
|
||||
if assoc_entry.is_hidden() {
|
||||
// Check if all files are hidden (NOTE: PREVENT STACK OVERFLOWS)
|
||||
let hidden_files: usize =
|
||||
self.files.iter().filter(|x| x.is_hidden()).count();
|
||||
// Only if there are more files, than hidden files keep decrementing
|
||||
if sz > hidden_files {
|
||||
self.decr_index();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => self.index = 0, // Reset to 0, for safety reasons
|
||||
}
|
||||
}
|
||||
|
||||
/// ### decr_index_by
|
||||
///
|
||||
/// Decrement index by up to n
|
||||
pub fn decr_index_by(&mut self, n: usize) {
|
||||
for _ in 0..n {
|
||||
let prev_idx: usize = self.index;
|
||||
// Increment
|
||||
self.decr_index();
|
||||
// If prev index is < index and break
|
||||
if prev_idx < self.index {
|
||||
self.index = prev_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ### index_at_first
|
||||
///
|
||||
/// Move index to first "visible" fs entry
|
||||
pub fn index_at_first(&mut self) {
|
||||
self.index = self.get_first_valid_index();
|
||||
}
|
||||
|
||||
/// ### get_first_valid_index
|
||||
///
|
||||
/// Return first valid index
|
||||
fn get_first_valid_index(&self) -> usize {
|
||||
match self.hidden_files {
|
||||
true => 0,
|
||||
false => {
|
||||
// Look for first "non-hidden" entry
|
||||
for (i, f) in self.files.iter().enumerate() {
|
||||
if !f.is_hidden() {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// If all files are hidden, return 0
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_index
|
||||
///
|
||||
/// Return index
|
||||
pub fn get_index(&self) -> usize {
|
||||
self.index
|
||||
}
|
||||
|
||||
/// ### get_relative_index
|
||||
///
|
||||
/// Get relative index based on current options
|
||||
pub fn get_relative_index(&self) -> usize {
|
||||
match self.files.get(self.index) {
|
||||
Some(abs_entry) => {
|
||||
// Search abs entry in relative iterator
|
||||
for (i, f) in self.iter_files().enumerate() {
|
||||
if abs_entry.get_name() == f.get_name() {
|
||||
// If abs entry is f, return index
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// Return 0 if not found
|
||||
0
|
||||
}
|
||||
None => 0, // Absolute entry doesn't exist
|
||||
}
|
||||
}
|
||||
|
||||
/// ### set_index
|
||||
///
|
||||
/// Set index to idx.
|
||||
/// If index exceeds size, is set to count() - 1; or 0
|
||||
pub fn set_index(&mut self, idx: usize) {
|
||||
let visible_sz: usize = self.iter_files().count();
|
||||
match idx >= visible_sz {
|
||||
true => match visible_sz {
|
||||
0 => self.index_at_first(),
|
||||
_ => self.index = visible_sz - 1,
|
||||
},
|
||||
false => match self.get_first_valid_index() > idx {
|
||||
true => self.index_at_first(),
|
||||
false => self.index = idx,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// ### toggle_hidden_files
|
||||
///
|
||||
/// Enable/disable hidden files
|
||||
pub fn toggle_hidden_files(&mut self) {
|
||||
self.hidden_files = !self.hidden_files;
|
||||
// Adjust index
|
||||
if self.index < self.get_first_valid_index() {
|
||||
self.index_at_first();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::fs::{FsDirectory, FsFile};
|
||||
|
||||
use std::time::SystemTime;
|
||||
|
||||
#[test]
|
||||
fn test_ui_filetransfer_activity_explorer_new() {
|
||||
let explorer: FileExplorer = FileExplorer::new(16);
|
||||
// Verify
|
||||
assert_eq!(explorer.dirstack.len(), 0);
|
||||
assert_eq!(explorer.files.len(), 0);
|
||||
assert_eq!(explorer.hidden_files, false);
|
||||
assert_eq!(explorer.wrkdir, PathBuf::from("/"));
|
||||
assert_eq!(explorer.stack_size, 16);
|
||||
assert_eq!(explorer.index, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ui_filetransfer_activity_explorer_stack() {
|
||||
let mut explorer: FileExplorer = FileExplorer::new(2);
|
||||
// Push dir
|
||||
explorer.pushd(&Path::new("/tmp"));
|
||||
explorer.pushd(&Path::new("/home/omar"));
|
||||
// Pop
|
||||
assert_eq!(explorer.popd().unwrap(), PathBuf::from("/home/omar"));
|
||||
assert_eq!(explorer.dirstack.len(), 1);
|
||||
assert_eq!(explorer.popd().unwrap(), PathBuf::from("/tmp"));
|
||||
assert_eq!(explorer.dirstack.len(), 0);
|
||||
// Dirstack is empty now
|
||||
assert!(explorer.popd().is_none());
|
||||
// Exceed limit
|
||||
explorer.pushd(&Path::new("/tmp"));
|
||||
explorer.pushd(&Path::new("/home/omar"));
|
||||
explorer.pushd(&Path::new("/dev"));
|
||||
assert_eq!(explorer.dirstack.len(), 2);
|
||||
assert_eq!(*explorer.dirstack.get(1).unwrap(), PathBuf::from("/dev"));
|
||||
assert_eq!(
|
||||
*explorer.dirstack.get(0).unwrap(),
|
||||
PathBuf::from("/home/omar")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ui_filetransfer_activity_explorer_files() {
|
||||
let mut explorer: FileExplorer = FileExplorer::new(16);
|
||||
explorer.hidden_files = false;
|
||||
// Create files
|
||||
explorer.set_files(vec![
|
||||
make_fs_entry("README.md", false),
|
||||
make_fs_entry("src/", true),
|
||||
make_fs_entry(".git/", true),
|
||||
make_fs_entry("CONTRIBUTING.md", false),
|
||||
make_fs_entry("codecov.yml", false),
|
||||
make_fs_entry(".gitignore", false),
|
||||
]);
|
||||
assert_eq!(explorer.count(), 6);
|
||||
// Verify
|
||||
assert_eq!(
|
||||
explorer.files.get(0).unwrap().get_name(),
|
||||
String::from("README.md")
|
||||
);
|
||||
// Sort files
|
||||
explorer.sort_files_by_name();
|
||||
// Verify
|
||||
assert_eq!(
|
||||
explorer.files.get(0).unwrap().get_name(),
|
||||
String::from(".git/")
|
||||
);
|
||||
// Iter files (all)
|
||||
assert_eq!(explorer.iter_files_all().count(), 6);
|
||||
// Iter files (hidden excluded) (.git, .gitignore are hidden)
|
||||
assert_eq!(explorer.iter_files().count(), 4);
|
||||
// Toggle hidden
|
||||
explorer.toggle_hidden_files();
|
||||
assert_eq!(explorer.iter_files().count(), 6); // All files are returned now
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ui_filetransfer_activity_explorer_index() {
|
||||
let mut explorer: FileExplorer = FileExplorer::new(16);
|
||||
explorer.hidden_files = false;
|
||||
// Create files
|
||||
explorer.set_files(vec![
|
||||
make_fs_entry("README.md", false),
|
||||
make_fs_entry("src/", true),
|
||||
make_fs_entry(".git/", true),
|
||||
make_fs_entry("CONTRIBUTING.md", false),
|
||||
make_fs_entry("CODE_OF_CONDUCT.md", false),
|
||||
make_fs_entry("CHANGELOG.md", false),
|
||||
make_fs_entry("LICENSE", false),
|
||||
make_fs_entry("Cargo.toml", false),
|
||||
make_fs_entry("Cargo.lock", false),
|
||||
make_fs_entry("codecov.yml", false),
|
||||
make_fs_entry(".gitignore", false),
|
||||
]);
|
||||
let sz: usize = explorer.count();
|
||||
// Sort by name
|
||||
explorer.sort_files_by_name();
|
||||
// Get first index
|
||||
assert_eq!(explorer.get_first_valid_index(), 2);
|
||||
// Index should be 2 now; files hidden; this happens because `index_at_first` is called after loading files
|
||||
assert_eq!(explorer.get_index(), 2);
|
||||
assert_eq!(explorer.get_relative_index(), 0); // Relative index should be 0
|
||||
assert_eq!(explorer.hidden_files, false);
|
||||
// Increment index
|
||||
explorer.incr_index();
|
||||
// Index should now be 3 (was 0, + 2 + 1); first 2 files are hidden (.git, .gitignore)
|
||||
assert_eq!(explorer.get_index(), 3);
|
||||
// Relative index should be 1 instead
|
||||
assert_eq!(explorer.get_relative_index(), 1);
|
||||
// Increment by 2
|
||||
explorer.incr_index_by(2);
|
||||
// Index should now be 5, 3
|
||||
assert_eq!(explorer.get_index(), 5);
|
||||
assert_eq!(explorer.get_relative_index(), 3);
|
||||
// Increment by (exceed size)
|
||||
explorer.incr_index_by(20);
|
||||
// Index should be at last element
|
||||
assert_eq!(explorer.get_index(), sz - 1);
|
||||
assert_eq!(explorer.get_relative_index(), sz - 3);
|
||||
// Increment; should go to 2
|
||||
explorer.incr_index();
|
||||
assert_eq!(explorer.get_index(), 2);
|
||||
assert_eq!(explorer.get_relative_index(), 0);
|
||||
// Increment and then decrement
|
||||
explorer.incr_index();
|
||||
explorer.decr_index();
|
||||
assert_eq!(explorer.get_index(), 2);
|
||||
assert_eq!(explorer.get_relative_index(), 0);
|
||||
// Decrement (and wrap)
|
||||
explorer.decr_index();
|
||||
// Index should be at last element
|
||||
assert_eq!(explorer.get_index(), sz - 1);
|
||||
assert_eq!(explorer.get_relative_index(), sz - 3);
|
||||
// Set index to 5
|
||||
explorer.set_index(5);
|
||||
assert_eq!(explorer.get_index(), 5);
|
||||
assert_eq!(explorer.get_relative_index(), 3);
|
||||
// Decr by 2
|
||||
explorer.decr_index_by(2);
|
||||
assert_eq!(explorer.get_index(), 3);
|
||||
assert_eq!(explorer.get_relative_index(), 1);
|
||||
// Decr by 2
|
||||
explorer.decr_index_by(2);
|
||||
// Should decrement actually by 1 (since first two files are hidden)
|
||||
assert_eq!(explorer.get_index(), 2);
|
||||
assert_eq!(explorer.get_relative_index(), 0);
|
||||
// Toggle hidden files
|
||||
explorer.toggle_hidden_files();
|
||||
assert_eq!(explorer.hidden_files, true);
|
||||
// Move index to 0
|
||||
explorer.set_index(0);
|
||||
assert_eq!(explorer.get_index(), 0);
|
||||
// Toggle hidden files
|
||||
explorer.toggle_hidden_files();
|
||||
// Index should now have been moved to 2
|
||||
assert_eq!(explorer.get_index(), 2);
|
||||
// Show hidden files
|
||||
explorer.toggle_hidden_files();
|
||||
// Set index to 5
|
||||
explorer.set_index(5);
|
||||
// Verify index
|
||||
assert_eq!(explorer.get_index(), 5);
|
||||
assert_eq!(explorer.get_relative_index(), 5); // Now relative matches
|
||||
// Decrement by 6, goes to 0
|
||||
explorer.decr_index_by(6);
|
||||
assert_eq!(explorer.get_index(), 0);
|
||||
assert_eq!(explorer.get_relative_index(), 0); // Now relative matches
|
||||
// Toggle; move at first
|
||||
explorer.toggle_hidden_files();
|
||||
assert_eq!(explorer.hidden_files, false);
|
||||
explorer.index_at_first();
|
||||
assert_eq!(explorer.get_index(), 2);
|
||||
assert_eq!(explorer.get_relative_index(), 0);
|
||||
// Verify set index if exceeds
|
||||
let sz: usize = explorer.iter_files().count();
|
||||
explorer.set_index(sz);
|
||||
assert_eq!(explorer.get_index(), sz - 1); // Should be at last element
|
||||
// Empty files
|
||||
explorer.files.clear();
|
||||
explorer.index_at_first();
|
||||
assert_eq!(explorer.get_index(), 0);
|
||||
assert_eq!(explorer.get_relative_index(), 0);
|
||||
}
|
||||
|
||||
fn make_fs_entry(name: &str, is_dir: bool) -> 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: 64,
|
||||
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
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
//! ## FileTransferActivity
|
||||
//!
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
|
||||
|
@ -102,41 +106,28 @@ impl FileTransferActivity {
|
|||
KeyCode::Tab => self.switch_input_field(), // <TAB> switch tab
|
||||
KeyCode::Right => self.tab = FileExplorerTab::Remote, // <RIGHT> switch to right tab
|
||||
KeyCode::Up => {
|
||||
// Move index up; or move to the last element if 0
|
||||
self.local.index = match self.local.index {
|
||||
0 => self.local.files.len() - 1,
|
||||
_ => self.local.index - 1,
|
||||
};
|
||||
// Decrement index
|
||||
self.local.decr_index();
|
||||
}
|
||||
KeyCode::Down => {
|
||||
// Move index down
|
||||
if self.local.index + 1 < self.local.files.len() {
|
||||
self.local.index += 1;
|
||||
} else {
|
||||
self.local.index = 0; // Move at the beginning of the list
|
||||
}
|
||||
// Increment index
|
||||
self.local.incr_index();
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
// Move index up (fast)
|
||||
if self.local.index > 8 {
|
||||
self.local.index -= 8; // Decrease by `8` if possible
|
||||
} else {
|
||||
self.local.index = 0; // Set to 0 otherwise
|
||||
}
|
||||
// Decrement index by 8
|
||||
self.local.decr_index_by(8);
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
// Move index down (fast)
|
||||
if self.local.index + 8 >= self.local.files.len() {
|
||||
// If overflows, set to size
|
||||
self.local.index = self.local.files.len() - 1;
|
||||
} else {
|
||||
self.local.index += 8; // Increase by `8`
|
||||
}
|
||||
// Increment index by 8
|
||||
self.local.incr_index_by(8);
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
// Match selected file
|
||||
let local_files: Vec<FsEntry> = self.local.files.clone();
|
||||
if let Some(entry) = local_files.get(self.local.index) {
|
||||
let mut entry: Option<FsEntry> = None;
|
||||
if let Some(e) = self.local.get_current_file() {
|
||||
entry = Some(e.clone());
|
||||
}
|
||||
if let Some(entry) = entry {
|
||||
// If directory, enter directory, otherwise check if symlink
|
||||
match entry {
|
||||
FsEntry::Directory(dir) => {
|
||||
|
@ -162,7 +153,7 @@ impl FileTransferActivity {
|
|||
}
|
||||
KeyCode::Delete => {
|
||||
// Get file at index
|
||||
if let Some(entry) = self.local.files.get(self.local.index) {
|
||||
if let Some(entry) = self.local.get_current_file() {
|
||||
// Get file name
|
||||
let file_name: String = match entry {
|
||||
FsEntry::Directory(dir) => dir.name.clone(),
|
||||
|
@ -177,6 +168,10 @@ impl FileTransferActivity {
|
|||
}
|
||||
}
|
||||
KeyCode::Char(ch) => match ch {
|
||||
'a' | 'A' => {
|
||||
// Toggle hidden files
|
||||
self.local.toggle_hidden_files();
|
||||
}
|
||||
'c' | 'C' => {
|
||||
// Copy
|
||||
self.input_mode = InputMode::Popup(PopupType::Input(
|
||||
|
@ -193,7 +188,7 @@ impl FileTransferActivity {
|
|||
}
|
||||
'e' | 'E' => {
|
||||
// Get file at index
|
||||
if let Some(entry) = self.local.files.get(self.local.index) {
|
||||
if let Some(entry) = self.local.get_current_file() {
|
||||
// Get file name
|
||||
let file_name: String = match entry {
|
||||
FsEntry::Directory(dir) => dir.name.clone(),
|
||||
|
@ -237,10 +232,9 @@ impl FileTransferActivity {
|
|||
}
|
||||
'o' | 'O' => {
|
||||
// Edit local file
|
||||
if self.local.files.get(self.local.index).is_some() {
|
||||
if self.local.get_current_file().is_some() {
|
||||
// Clone entry due to mutable stuff...
|
||||
let fsentry: FsEntry =
|
||||
self.local.files.get(self.local.index).unwrap().clone();
|
||||
let fsentry: FsEntry = self.local.get_current_file().unwrap().clone();
|
||||
// Check if file
|
||||
if fsentry.is_file() {
|
||||
self.log(
|
||||
|
@ -294,9 +288,8 @@ impl FileTransferActivity {
|
|||
// Get pwd
|
||||
let wrkdir: PathBuf = self.remote.wrkdir.clone();
|
||||
// Get file and clone (due to mutable / immutable stuff...)
|
||||
if self.local.files.get(self.local.index).is_some() {
|
||||
let file: FsEntry =
|
||||
self.local.files.get(self.local.index).unwrap().clone();
|
||||
if self.local.get_current_file().is_some() {
|
||||
let file: FsEntry = self.local.get_current_file().unwrap().clone();
|
||||
let name: String = file.get_name().to_string();
|
||||
// Call upload; pass realfile, keep link name
|
||||
self.filetransfer_send(
|
||||
|
@ -328,41 +321,28 @@ impl FileTransferActivity {
|
|||
KeyCode::Tab => self.switch_input_field(), // <TAB> switch tab
|
||||
KeyCode::Left => self.tab = FileExplorerTab::Local, // <LEFT> switch to local tab
|
||||
KeyCode::Up => {
|
||||
// Move index up; or move to the last element if 0
|
||||
self.remote.index = match self.remote.index {
|
||||
0 => self.remote.files.len() - 1,
|
||||
_ => self.remote.index - 1,
|
||||
};
|
||||
// Decrement index
|
||||
self.remote.decr_index();
|
||||
}
|
||||
KeyCode::Down => {
|
||||
// Move index down
|
||||
if self.remote.index + 1 < self.remote.files.len() {
|
||||
self.remote.index += 1;
|
||||
} else {
|
||||
self.remote.index = 0; // Move at the beginning of the list
|
||||
}
|
||||
// Increment index
|
||||
self.remote.incr_index();
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
// Move index up (fast)
|
||||
if self.remote.index > 8 {
|
||||
self.remote.index -= 8; // Decrease by `8` if possible
|
||||
} else {
|
||||
self.remote.index = 0; // Set to 0 otherwise
|
||||
}
|
||||
// Decrement index by 8
|
||||
self.remote.decr_index_by(8);
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
// Move index down (fast)
|
||||
if self.remote.index + 8 >= self.remote.files.len() {
|
||||
// If overflows, set to size
|
||||
self.remote.index = self.remote.files.len() - 1;
|
||||
} else {
|
||||
self.remote.index += 8; // Increase by `8`
|
||||
}
|
||||
// Increment index by 8
|
||||
self.remote.incr_index_by(8);
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
// Match selected file
|
||||
let files: Vec<FsEntry> = self.remote.files.clone();
|
||||
if let Some(entry) = files.get(self.remote.index) {
|
||||
let mut entry: Option<FsEntry> = None;
|
||||
if let Some(e) = self.remote.get_current_file() {
|
||||
entry = Some(e.clone());
|
||||
}
|
||||
if let Some(entry) = entry {
|
||||
// If directory, enter directory; if file, check if is symlink
|
||||
match entry {
|
||||
FsEntry::Directory(dir) => {
|
||||
|
@ -388,7 +368,7 @@ impl FileTransferActivity {
|
|||
}
|
||||
KeyCode::Delete => {
|
||||
// Get file at index
|
||||
if let Some(entry) = self.remote.files.get(self.remote.index) {
|
||||
if let Some(entry) = self.remote.get_current_file() {
|
||||
// Get file name
|
||||
let file_name: String = match entry {
|
||||
FsEntry::Directory(dir) => dir.name.clone(),
|
||||
|
@ -403,6 +383,10 @@ impl FileTransferActivity {
|
|||
}
|
||||
}
|
||||
KeyCode::Char(ch) => match ch {
|
||||
'a' | 'A' => {
|
||||
// Toggle hidden files
|
||||
self.remote.toggle_hidden_files();
|
||||
}
|
||||
'c' | 'C' => {
|
||||
// Copy
|
||||
self.input_mode = InputMode::Popup(PopupType::Input(
|
||||
|
@ -419,7 +403,7 @@ impl FileTransferActivity {
|
|||
}
|
||||
'e' | 'E' => {
|
||||
// Get file at index
|
||||
if let Some(entry) = self.remote.files.get(self.remote.index) {
|
||||
if let Some(entry) = self.remote.get_current_file() {
|
||||
// Get file name
|
||||
let file_name: String = match entry {
|
||||
FsEntry::Directory(dir) => dir.name.clone(),
|
||||
|
@ -462,10 +446,9 @@ impl FileTransferActivity {
|
|||
}
|
||||
'o' | 'O' => {
|
||||
// Edit remote file
|
||||
if self.remote.files.get(self.remote.index).is_some() {
|
||||
if self.remote.get_current_file().is_some() {
|
||||
// Clone entry due to mutable stuff...
|
||||
let fsentry: FsEntry =
|
||||
self.remote.files.get(self.remote.index).unwrap().clone();
|
||||
let fsentry: FsEntry = self.remote.get_current_file().unwrap().clone();
|
||||
// Check if file
|
||||
if let FsEntry::File(file) = fsentry {
|
||||
self.log(
|
||||
|
@ -516,9 +499,8 @@ impl FileTransferActivity {
|
|||
}
|
||||
' ' => {
|
||||
// Get file and clone (due to mutable / immutable stuff...)
|
||||
if self.remote.files.get(self.remote.index).is_some() {
|
||||
let file: FsEntry =
|
||||
self.remote.files.get(self.remote.index).unwrap().clone();
|
||||
if self.remote.get_current_file().is_some() {
|
||||
let file: FsEntry = self.remote.get_current_file().unwrap().clone();
|
||||
let name: String = file.get_name().to_string();
|
||||
// Call upload; pass realfile, keep link name
|
||||
let wrkdir: PathBuf = self.local.wrkdir.clone();
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
//! ## FileTransferActivity
|
||||
//!
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
|
||||
|
@ -70,10 +74,10 @@ impl FileTransferActivity {
|
|||
.split(chunks[0]);
|
||||
// Set localhost state
|
||||
let mut localhost_state: ListState = ListState::default();
|
||||
localhost_state.select(Some(self.local.index));
|
||||
localhost_state.select(Some(self.local.get_relative_index()));
|
||||
// Set remote state
|
||||
let mut remote_state: ListState = ListState::default();
|
||||
remote_state.select(Some(self.remote.index));
|
||||
remote_state.select(Some(self.remote.get_relative_index()));
|
||||
// Draw tabs
|
||||
f.render_stateful_widget(
|
||||
self.draw_local_explorer(tabs_chunks[0].width),
|
||||
|
@ -158,8 +162,7 @@ impl FileTransferActivity {
|
|||
};
|
||||
let files: Vec<ListItem> = self
|
||||
.local
|
||||
.files
|
||||
.iter()
|
||||
.iter_files()
|
||||
.map(|entry: &FsEntry| ListItem::new(Span::from(format!("{}", entry))))
|
||||
.collect();
|
||||
// Get colors to use; highlight element inverting fg/bg only when tab is active
|
||||
|
@ -199,8 +202,7 @@ impl FileTransferActivity {
|
|||
pub(super) fn draw_remote_explorer(&self, width: u16) -> List {
|
||||
let files: Vec<ListItem> = self
|
||||
.remote
|
||||
.files
|
||||
.iter()
|
||||
.iter_files()
|
||||
.map(|entry: &FsEntry| ListItem::new(Span::from(format!("{}", entry))))
|
||||
.collect();
|
||||
// Get colors to use; highlight element inverting fg/bg only when tab is active
|
||||
|
@ -468,12 +470,12 @@ impl FileTransferActivity {
|
|||
let fsentry: Option<&FsEntry> = match self.tab {
|
||||
FileExplorerTab::Local => {
|
||||
// Get selected file
|
||||
match self.local.files.get(self.local.index) {
|
||||
match self.local.get_current_file() {
|
||||
Some(entry) => Some(entry),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
FileExplorerTab::Remote => match self.remote.files.get(self.remote.index) {
|
||||
FileExplorerTab::Remote => match self.remote.get_current_file() {
|
||||
Some(entry) => Some(entry),
|
||||
None => None,
|
||||
},
|
||||
|
@ -715,6 +717,16 @@ impl FileTransferActivity {
|
|||
Span::raw(" "),
|
||||
Span::raw("Delete file"),
|
||||
])),
|
||||
ListItem::new(Spans::from(vec![
|
||||
Span::styled(
|
||||
"<A>",
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::raw(" "),
|
||||
Span::raw("Toggle hidden files"),
|
||||
])),
|
||||
ListItem::new(Spans::from(vec![
|
||||
Span::styled(
|
||||
"<C>",
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
// This module is split into files, cause it's just too big
|
||||
mod callbacks;
|
||||
mod explorer;
|
||||
mod input;
|
||||
mod layout;
|
||||
mod misc;
|
||||
|
@ -45,13 +46,14 @@ use crate::filetransfer::sftp_transfer::SftpFileTransfer;
|
|||
use crate::filetransfer::{FileTransfer, FileTransferProtocol};
|
||||
use crate::fs::FsEntry;
|
||||
use crate::system::config_client::ConfigClient;
|
||||
use explorer::FileExplorer;
|
||||
|
||||
// Includes
|
||||
use chrono::{DateTime, Local};
|
||||
use crossterm::event::Event as InputEvent;
|
||||
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
|
||||
use std::collections::VecDeque;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use std::time::Instant;
|
||||
use tui::style::Color;
|
||||
|
||||
|
@ -113,59 +115,6 @@ enum InputMode {
|
|||
Popup(PopupType),
|
||||
}
|
||||
|
||||
/// ## FileExplorer
|
||||
///
|
||||
/// File explorer states
|
||||
struct FileExplorer {
|
||||
pub wrkdir: PathBuf, // Current directory
|
||||
pub index: usize, // Selected file
|
||||
pub files: Vec<FsEntry>, // Files in directory
|
||||
dirstack: VecDeque<PathBuf>, // Stack of visited directory (max 16)
|
||||
}
|
||||
|
||||
impl FileExplorer {
|
||||
/// ### new
|
||||
///
|
||||
/// Instantiates a new FileExplorer
|
||||
pub fn new() -> FileExplorer {
|
||||
FileExplorer {
|
||||
wrkdir: PathBuf::from("/"),
|
||||
index: 0,
|
||||
files: Vec::new(),
|
||||
dirstack: VecDeque::with_capacity(16),
|
||||
}
|
||||
}
|
||||
|
||||
/// ### pushd
|
||||
///
|
||||
/// push directory to stack
|
||||
pub fn pushd(&mut self, dir: &Path) {
|
||||
// Check if stack overflows the size
|
||||
if self.dirstack.len() + 1 > 16 {
|
||||
self.dirstack.pop_back(); // Start cleaning events from back
|
||||
}
|
||||
// Eventually push front the new record
|
||||
self.dirstack.push_front(PathBuf::from(dir));
|
||||
}
|
||||
|
||||
/// ### popd
|
||||
///
|
||||
/// Pop directory from the stack and return the directory
|
||||
pub fn popd(&mut self) -> Option<PathBuf> {
|
||||
self.dirstack.pop_front()
|
||||
}
|
||||
|
||||
/// ### sort_files_by_name
|
||||
///
|
||||
/// Sort explorer files by their name
|
||||
pub fn sort_files_by_name(&mut self) {
|
||||
self.files.sort_by_key(|x: &FsEntry| match x {
|
||||
FsEntry::Directory(dir) => dir.name.as_str().to_lowercase(),
|
||||
FsEntry::File(file) => file.name.as_str().to_lowercase(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// ## FileExplorerTab
|
||||
///
|
||||
/// File explorer tab
|
||||
|
@ -312,18 +261,18 @@ impl FileTransferActivity {
|
|||
quit: false,
|
||||
context: None,
|
||||
client: match protocol {
|
||||
FileTransferProtocol::Sftp => {
|
||||
Box::new(SftpFileTransfer::new(Self::make_ssh_storage(config_client.as_ref())))
|
||||
}
|
||||
FileTransferProtocol::Sftp => Box::new(SftpFileTransfer::new(
|
||||
Self::make_ssh_storage(config_client.as_ref()),
|
||||
)),
|
||||
FileTransferProtocol::Ftp(ftps) => Box::new(FtpFileTransfer::new(ftps)),
|
||||
FileTransferProtocol::Scp => {
|
||||
Box::new(ScpFileTransfer::new(Self::make_ssh_storage(config_client.as_ref())))
|
||||
}
|
||||
FileTransferProtocol::Scp => Box::new(ScpFileTransfer::new(
|
||||
Self::make_ssh_storage(config_client.as_ref()),
|
||||
)),
|
||||
},
|
||||
config_cli: config_client,
|
||||
params,
|
||||
local: FileExplorer::new(),
|
||||
remote: FileExplorer::new(),
|
||||
local: FileExplorer::new(16),
|
||||
remote: FileExplorer::new(16),
|
||||
tab: FileExplorerTab::Local,
|
||||
log_index: 0,
|
||||
log_records: VecDeque::with_capacity(256), // 256 events is enough I guess
|
||||
|
@ -335,7 +284,6 @@ impl FileTransferActivity {
|
|||
transfer: TransferStates::default(),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
//! ## FileTransferActivity
|
||||
//!
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
|
||||
|
@ -599,17 +603,17 @@ impl FileTransferActivity {
|
|||
pub(super) fn local_scan(&mut self, path: &Path) {
|
||||
match self.context.as_ref().unwrap().local.scan_dir(path) {
|
||||
Ok(files) => {
|
||||
self.local.files = files;
|
||||
// Set index; keep if possible, otherwise set to last item
|
||||
self.local.index = match self.local.files.get(self.local.index) {
|
||||
Some(_) => self.local.index,
|
||||
None => match self.local.files.len() {
|
||||
0 => 0,
|
||||
_ => self.local.files.len() - 1,
|
||||
},
|
||||
};
|
||||
self.local.set_files(files);
|
||||
// Sort files
|
||||
self.local.sort_files_by_name();
|
||||
// Set index; keep if possible, otherwise set to last item
|
||||
self.local.set_index(match self.local.get_current_file() {
|
||||
Some(_) => self.local.get_index(),
|
||||
None => match self.local.count() {
|
||||
0 => 0,
|
||||
_ => self.local.count() - 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
Err(err) => {
|
||||
self.log_and_alert(
|
||||
|
@ -626,17 +630,17 @@ impl FileTransferActivity {
|
|||
pub(super) fn remote_scan(&mut self, path: &Path) {
|
||||
match self.client.list_dir(path) {
|
||||
Ok(files) => {
|
||||
self.remote.files = files;
|
||||
// Set index; keep if possible, otherwise set to last item
|
||||
self.remote.index = match self.remote.files.get(self.remote.index) {
|
||||
Some(_) => self.remote.index,
|
||||
None => match self.remote.files.len() {
|
||||
0 => 0,
|
||||
_ => self.remote.files.len() - 1,
|
||||
},
|
||||
};
|
||||
self.remote.set_files(files);
|
||||
// Sort files
|
||||
self.remote.sort_files_by_name();
|
||||
// Set index; keep if possible, otherwise set to last item
|
||||
self.remote.set_index(match self.remote.get_current_file() {
|
||||
Some(_) => self.remote.get_index(),
|
||||
None => match self.remote.count() {
|
||||
0 => 0,
|
||||
_ => self.remote.count() - 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
Err(err) => {
|
||||
self.log_and_alert(
|
||||
|
@ -663,7 +667,7 @@ impl FileTransferActivity {
|
|||
// Reload files
|
||||
self.local_scan(path);
|
||||
// Reset index
|
||||
self.local.index = 0;
|
||||
self.local.set_index(0);
|
||||
// Set wrkdir
|
||||
self.local.wrkdir = PathBuf::from(path);
|
||||
// Push prev_dir to stack
|
||||
|
@ -694,7 +698,7 @@ impl FileTransferActivity {
|
|||
// Update files
|
||||
self.remote_scan(path);
|
||||
// Reset index
|
||||
self.remote.index = 0;
|
||||
self.remote.set_index(0);
|
||||
// Set wrkdir
|
||||
self.remote.wrkdir = PathBuf::from(path);
|
||||
// Push prev_dir to stack
|
||||
|
|
Loading…
Reference in a new issue