feat: 132 queuing transfers (#332)

the logic of selecting files has been extended!
From now on selecting file will put the files into a transfer queue, which is shown on the bottom panel.
When a file is selected the file is added to the queue with a destination path, which is the **current other explorer path at the moment of selection.
It is possible to navigate to the transfer queue by using `P` and pressing `ENTER` on a file will remove it from the transfer queue.Other commands will work as well on the transfer queue, like `COPY`, `MOVE`, `DELETE`, `RENAME`.

closes #132
This commit is contained in:
Christian Visintin
2025-03-23 14:36:13 +01:00
committed by GitHub
parent 368570592f
commit ec75ae1486
39 changed files with 955 additions and 330 deletions
+46 -5
View File
@@ -3,7 +3,8 @@ use std::path::{Path, PathBuf};
use bytesize::ByteSize;
use tuirealm::props::{
Alignment, AttrValue, Attribute, Color, PropPayload, PropValue, TableBuilder, TextSpan,
Alignment, AttrValue, Attribute, Color, PropPayload, PropValue, TableBuilder, TextModifiers,
TextSpan,
};
use tuirealm::{PollStrategy, Update};
@@ -227,7 +228,7 @@ impl FileTransferActivity {
transfer_stats
)
}
TransferPayload::Many(entries) => {
TransferPayload::TransferQueue(entries) => {
format!(
"{} files has been successfully transferred ({})",
entries.len(),
@@ -240,6 +241,11 @@ impl FileTransferActivity {
/// Update host bridge file list
pub(super) fn update_host_bridge_filelist(&mut self) {
self.reload_host_bridge_dir();
self.reload_host_bridge_filelist();
}
/// Update host bridge file list
pub(super) fn reload_host_bridge_filelist(&mut self) {
// Get width
let width = self
.context_mut()
@@ -261,7 +267,15 @@ impl FileTransferActivity {
let files: Vec<Vec<TextSpan>> = self
.host_bridge()
.iter_files()
.map(|x| vec![TextSpan::from(self.host_bridge().fmt_file(x))])
.map(|x| {
let mut span = TextSpan::from(self.host_bridge().fmt_file(x));
if self.host_bridge().enqueued().contains_key(x.path()) {
span.modifiers |=
TextModifiers::REVERSED | TextModifiers::UNDERLINED | TextModifiers::ITALIC;
}
vec![span]
})
.collect();
// Update content and title
assert!(
@@ -287,7 +301,10 @@ impl FileTransferActivity {
/// Update remote file list
pub(super) fn update_remote_filelist(&mut self) {
self.reload_remote_dir();
self.reload_remote_filelist();
}
pub(super) fn reload_remote_filelist(&mut self) {
let width = self
.context_mut()
.terminal()
@@ -308,7 +325,15 @@ impl FileTransferActivity {
let files: Vec<Vec<TextSpan>> = self
.remote()
.iter_files()
.map(|x| vec![TextSpan::from(self.remote().fmt_file(x))])
.map(|x| {
let mut span = TextSpan::from(self.remote().fmt_file(x));
if self.remote().enqueued().contains_key(x.path()) {
span.modifiers |=
TextModifiers::REVERSED | TextModifiers::UNDERLINED | TextModifiers::ITALIC;
}
vec![span]
})
.collect();
// Update content and title
assert!(
@@ -460,7 +485,14 @@ impl FileTransferActivity {
.found()
.unwrap()
.iter_files()
.map(|x| vec![TextSpan::from(self.found().unwrap().fmt_file(x))])
.map(|x| {
let mut span = TextSpan::from(self.found().unwrap().fmt_file(x));
if self.found().unwrap().enqueued().contains_key(x.path()) {
span.modifiers |=
TextModifiers::REVERSED | TextModifiers::UNDERLINED | TextModifiers::ITALIC;
}
vec![span]
})
.collect();
assert!(
self.app
@@ -482,6 +514,15 @@ impl FileTransferActivity {
}
}
pub(super) fn reload_browser_file_list(&mut self) {
match self.browser.tab() {
FileExplorerTab::HostBridge | FileExplorerTab::FindHostBridge => {
self.reload_host_bridge_filelist()
}
FileExplorerTab::Remote | FileExplorerTab::FindRemote => self.reload_remote_filelist(),
}
}
pub(super) fn update_browser_file_list_swapped(&mut self) {
match self.browser.tab() {
FileExplorerTab::HostBridge | FileExplorerTab::FindHostBridge => {