Remove pending transfer with storage (use action)

This commit is contained in:
veeso
2021-12-13 12:32:16 +01:00
committed by Christian Visintin
parent 197b3095b6
commit e047179ea0
7 changed files with 106 additions and 148 deletions

View File

@@ -78,15 +78,16 @@ impl FileTransferActivity {
SelectedEntry::One(entry) => match self.browser.tab() { SelectedEntry::One(entry) => match self.browser.tab() {
FileExplorerTab::FindLocal | FileExplorerTab::Local => { FileExplorerTab::FindLocal | FileExplorerTab::Local => {
let file_to_check = Self::file_to_check(&entry, opts.save_as.as_ref()); let file_to_check = Self::file_to_check(&entry, opts.save_as.as_ref());
if opts.check_replace if self.config().get_prompt_on_file_replace()
&& self.config().get_prompt_on_file_replace()
&& self.remote_file_exists(file_to_check.as_path()) && self.remote_file_exists(file_to_check.as_path())
{ && !self.should_replace_file(
// Save pending transfer
self.set_pending_transfer(
opts.save_as.as_deref().unwrap_or_else(|| entry.name()), opts.save_as.as_deref().unwrap_or_else(|| entry.name()),
); )
} else if let Err(err) = self.filetransfer_send( {
// Do not replace
return;
}
if let Err(err) = self.filetransfer_send(
TransferPayload::Any(entry), TransferPayload::Any(entry),
wrkdir.as_path(), wrkdir.as_path(),
opts.save_as, opts.save_as,
@@ -99,15 +100,16 @@ impl FileTransferActivity {
} }
FileExplorerTab::FindRemote | FileExplorerTab::Remote => { FileExplorerTab::FindRemote | FileExplorerTab::Remote => {
let file_to_check = Self::file_to_check(&entry, opts.save_as.as_ref()); let file_to_check = Self::file_to_check(&entry, opts.save_as.as_ref());
if opts.check_replace if self.config().get_prompt_on_file_replace()
&& self.config().get_prompt_on_file_replace()
&& self.local_file_exists(file_to_check.as_path()) && self.local_file_exists(file_to_check.as_path())
{ && !self.should_replace_file(
// Save pending transfer
self.set_pending_transfer(
opts.save_as.as_deref().unwrap_or_else(|| entry.name()), opts.save_as.as_deref().unwrap_or_else(|| entry.name()),
); )
} else if let Err(err) = self.filetransfer_recv( {
// Do not replace
return;
}
if let Err(err) = self.filetransfer_recv(
TransferPayload::Any(entry), TransferPayload::Any(entry),
wrkdir.as_path(), wrkdir.as_path(),
opts.save_as, opts.save_as,
@@ -128,7 +130,7 @@ impl FileTransferActivity {
// Iter files // Iter files
match self.browser.tab() { match self.browser.tab() {
FileExplorerTab::FindLocal | FileExplorerTab::Local => { FileExplorerTab::FindLocal | FileExplorerTab::Local => {
if opts.check_replace && self.config().get_prompt_on_file_replace() { if self.config().get_prompt_on_file_replace() {
// Check which file would be replaced // Check which file would be replaced
let existing_files: Vec<&Entry> = entries let existing_files: Vec<&Entry> = entries
.iter() .iter()
@@ -138,12 +140,10 @@ impl FileTransferActivity {
) )
}) })
.collect(); .collect();
// Save pending transfer // Check whether to replace files
if !existing_files.is_empty() { if !existing_files.is_empty()
self.set_pending_transfer_many( && !self.should_replace_files(existing_files)
existing_files, {
&dest_path.to_string_lossy().to_owned(),
);
return; return;
} }
} }
@@ -161,7 +161,7 @@ impl FileTransferActivity {
} }
} }
FileExplorerTab::FindRemote | FileExplorerTab::Remote => { FileExplorerTab::FindRemote | FileExplorerTab::Remote => {
if opts.check_replace && self.config().get_prompt_on_file_replace() { if self.config().get_prompt_on_file_replace() {
// Check which file would be replaced // Check which file would be replaced
let existing_files: Vec<&Entry> = entries let existing_files: Vec<&Entry> = entries
.iter() .iter()
@@ -171,13 +171,10 @@ impl FileTransferActivity {
) )
}) })
.collect(); .collect();
// Save pending transfer // Check whether to replace files
// Save pending transfer if !existing_files.is_empty()
if !existing_files.is_empty() { && !self.should_replace_files(existing_files)
self.set_pending_transfer_many( {
existing_files,
&dest_path.to_string_lossy().to_owned(),
);
return; return;
} }
} }

View File

@@ -28,7 +28,7 @@
*/ */
use super::{FileTransferActivity, Msg}; use super::{FileTransferActivity, Msg};
use tuirealm::PollStrategy; use tuirealm::{PollStrategy, Update};
impl FileTransferActivity { impl FileTransferActivity {
/// Block execution of activity, preventing ANY kind of message not specified in the `wait_for` argument. /// Block execution of activity, preventing ANY kind of message not specified in the `wait_for` argument.
@@ -42,12 +42,22 @@ impl FileTransferActivity {
loop { loop {
// Poll // Poll
match self.app.tick(PollStrategy::Once) { match self.app.tick(PollStrategy::Once) {
Ok(messages) => { Ok(mut messages) => {
if !messages.is_empty() { if !messages.is_empty() {
self.redraw = true; self.redraw = true;
} }
if let Some(msg) = messages.into_iter().find(|m| wait_for.contains(m)) { let found = messages.iter().position(|m| wait_for.contains(m));
return msg; // Return if found
if let Some(index) = found {
return messages.remove(index);
} else {
// Update
for msg in messages.into_iter() {
let mut msg = Some(msg);
while msg.is_some() {
msg = self.update(msg);
}
}
} }
} }
Err(err) => { Err(err) => {

View File

@@ -27,8 +27,8 @@
*/ */
// locals // locals
use super::{ use super::{
super::STORAGE_PENDING_TRANSFER, Entry, FileExplorerTab, FileTransferActivity, LogLevel, Entry, FileTransferActivity, LogLevel, Msg, PendingActionMsg, SelectedEntry, TransferOpts,
SelectedEntry, TransferOpts, TransferPayload, TransferPayload,
}; };
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@@ -49,59 +49,21 @@ impl FileTransferActivity {
self.remote_recv_file(TransferOpts::default()); self.remote_recv_file(TransferOpts::default());
} }
/// Finalize "pending" transfer.
/// The pending transfer is created after a transfer which required a user action to be completed first.
/// The name of the file to transfer, is contained in the storage at `STORAGE_PENDING_TRANSFER`.
/// NOTE: Panics if `STORAGE_PENDING_TRANSFER` is undefined
pub(crate) fn action_finalize_pending_transfer(&mut self) {
// Retrieve pending transfer
let file_name = self
.context_mut()
.store_mut()
.take_string(STORAGE_PENDING_TRANSFER);
// Send file
match self.browser.tab() {
FileExplorerTab::Local => self.local_send_file(
TransferOpts::default()
.save_as(file_name)
.check_replace(false),
),
FileExplorerTab::Remote => self.remote_recv_file(
TransferOpts::default()
.save_as(file_name)
.check_replace(false),
),
FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => self.action_find_transfer(
TransferOpts::default()
.save_as(file_name)
.check_replace(false),
),
}
// Reload browsers
match self.browser.tab() {
FileExplorerTab::Local | FileExplorerTab::FindLocal => {
self.update_remote_filelist();
}
FileExplorerTab::Remote | FileExplorerTab::FindRemote => {
self.update_local_filelist();
}
}
}
fn local_send_file(&mut self, opts: TransferOpts) { fn local_send_file(&mut self, opts: TransferOpts) {
let wrkdir: PathBuf = self.remote().wrkdir.clone(); let wrkdir: PathBuf = self.remote().wrkdir.clone();
match self.get_local_selected_entries() { match self.get_local_selected_entries() {
SelectedEntry::One(entry) => { SelectedEntry::One(entry) => {
let file_to_check = Self::file_to_check(&entry, opts.save_as.as_ref()); let file_to_check = Self::file_to_check(&entry, opts.save_as.as_ref());
if opts.check_replace if self.config().get_prompt_on_file_replace()
&& self.config().get_prompt_on_file_replace()
&& self.remote_file_exists(file_to_check.as_path()) && self.remote_file_exists(file_to_check.as_path())
{ && !self.should_replace_file(
// Save pending transfer
self.set_pending_transfer(
opts.save_as.as_deref().unwrap_or_else(|| entry.name()), opts.save_as.as_deref().unwrap_or_else(|| entry.name()),
); )
} else if let Err(err) = self.filetransfer_send( {
// Do not replace
return;
}
if let Err(err) = self.filetransfer_send(
TransferPayload::Any(entry.clone()), TransferPayload::Any(entry.clone()),
wrkdir.as_path(), wrkdir.as_path(),
opts.save_as, opts.save_as,
@@ -121,7 +83,7 @@ impl FileTransferActivity {
dest_path.push(save_as); dest_path.push(save_as);
} }
// Iter files // Iter files
if opts.check_replace && self.config().get_prompt_on_file_replace() { if self.config().get_prompt_on_file_replace() {
// Check which file would be replaced // Check which file would be replaced
let existing_files: Vec<&Entry> = entries let existing_files: Vec<&Entry> = entries
.iter() .iter()
@@ -131,12 +93,8 @@ impl FileTransferActivity {
) )
}) })
.collect(); .collect();
// Save pending transfer // Check whether to replace files
if !existing_files.is_empty() { if !existing_files.is_empty() && !self.should_replace_files(existing_files) {
self.set_pending_transfer_many(
existing_files,
&dest_path.to_string_lossy().to_owned(),
);
return; return;
} }
} }
@@ -162,15 +120,15 @@ impl FileTransferActivity {
match self.get_remote_selected_entries() { match self.get_remote_selected_entries() {
SelectedEntry::One(entry) => { SelectedEntry::One(entry) => {
let file_to_check = Self::file_to_check(&entry, opts.save_as.as_ref()); let file_to_check = Self::file_to_check(&entry, opts.save_as.as_ref());
if opts.check_replace if self.config().get_prompt_on_file_replace()
&& self.config().get_prompt_on_file_replace()
&& self.local_file_exists(file_to_check.as_path()) && self.local_file_exists(file_to_check.as_path())
{ && !self.should_replace_file(
// Save pending transfer
self.set_pending_transfer(
opts.save_as.as_deref().unwrap_or_else(|| entry.name()), opts.save_as.as_deref().unwrap_or_else(|| entry.name()),
); )
} else if let Err(err) = self.filetransfer_recv( {
return;
}
if let Err(err) = self.filetransfer_recv(
TransferPayload::Any(entry.clone()), TransferPayload::Any(entry.clone()),
wrkdir.as_path(), wrkdir.as_path(),
opts.save_as, opts.save_as,
@@ -190,7 +148,7 @@ impl FileTransferActivity {
dest_path.push(save_as); dest_path.push(save_as);
} }
// Iter files // Iter files
if opts.check_replace && self.config().get_prompt_on_file_replace() { if self.config().get_prompt_on_file_replace() {
// Check which file would be replaced // Check which file would be replaced
let existing_files: Vec<&Entry> = entries let existing_files: Vec<&Entry> = entries
.iter() .iter()
@@ -200,12 +158,8 @@ impl FileTransferActivity {
) )
}) })
.collect(); .collect();
// Save pending transfer // Check whether to replace files
if !existing_files.is_empty() { if !existing_files.is_empty() && !self.should_replace_files(existing_files) {
self.set_pending_transfer_many(
existing_files,
&dest_path.to_string_lossy().to_owned(),
);
return; return;
} }
} }
@@ -227,21 +181,47 @@ impl FileTransferActivity {
} }
/// Set pending transfer into storage /// Set pending transfer into storage
pub(crate) fn set_pending_transfer(&mut self, file_name: &str) { pub(crate) fn should_replace_file(&mut self, file_name: &str) -> bool {
self.mount_radio_replace(file_name); self.mount_radio_replace(file_name);
// Put pending transfer in store // Wait for answer
self.context_mut() trace!("Asking user whether he wants to replace file {}", file_name);
.store_mut() if self.wait_for_pending_msg(&[
.set_string(STORAGE_PENDING_TRANSFER, file_name.to_string()); Msg::PendingAction(PendingActionMsg::CloseReplacePopups),
Msg::PendingAction(PendingActionMsg::TransferPendingFile),
]) == Msg::PendingAction(PendingActionMsg::TransferPendingFile)
{
trace!("User wants to replace file");
self.umount_radio_replace();
true
} else {
trace!("The user doesn't want replace file");
self.umount_radio_replace();
false
}
} }
/// Set pending transfer for many files into storage and mount radio /// Set pending transfer for many files into storage and mount radio
pub(crate) fn set_pending_transfer_many(&mut self, files: Vec<&Entry>, dest_path: &str) { pub(crate) fn should_replace_files(&mut self, files: Vec<&Entry>) -> bool {
let file_names: Vec<&str> = files.iter().map(|x| x.name()).collect(); let file_names: Vec<&str> = files.iter().map(|x| x.name()).collect();
self.mount_radio_replace_many(file_names.as_slice()); self.mount_radio_replace_many(file_names.as_slice());
self.context_mut() // Wait for answer
.store_mut() trace!(
.set_string(STORAGE_PENDING_TRANSFER, dest_path.to_string()); "Asking user whether he wants to replace files {:?}",
file_names
);
if self.wait_for_pending_msg(&[
Msg::PendingAction(PendingActionMsg::CloseReplacePopups),
Msg::PendingAction(PendingActionMsg::TransferPendingFile),
]) == Msg::PendingAction(PendingActionMsg::TransferPendingFile)
{
trace!("User wants to replace files");
self.umount_radio_replace();
true
} else {
trace!("The user doesn't want replace file");
self.umount_radio_replace();
false
}
} }
/// Get file to check for path /// Get file to check for path

View File

@@ -1343,7 +1343,7 @@ impl Component<Msg, NoUserEvent> for ReplacePopup {
Some(Msg::None) Some(Msg::None)
} }
Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => { Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => {
Some(Msg::Ui(UiMsg::CloseReplacePopups)) Some(Msg::PendingAction(PendingActionMsg::CloseReplacePopups))
} }
Event::Keyboard(KeyEvent { Event::Keyboard(KeyEvent {
code: Key::Enter, .. code: Key::Enter, ..
@@ -1352,9 +1352,9 @@ impl Component<Msg, NoUserEvent> for ReplacePopup {
self.perform(Cmd::Submit), self.perform(Cmd::Submit),
CmdResult::Submit(State::One(StateValue::Usize(0))) CmdResult::Submit(State::One(StateValue::Usize(0)))
) { ) {
Some(Msg::Transfer(TransferMsg::TransferPendingFile)) Some(Msg::PendingAction(PendingActionMsg::TransferPendingFile))
} else { } else {
Some(Msg::Ui(UiMsg::CloseReplacePopups)) Some(Msg::PendingAction(PendingActionMsg::CloseReplacePopups))
} }
} }
_ => None, _ => None,
@@ -1393,7 +1393,7 @@ impl Component<Msg, NoUserEvent> for ReplacingFilesListPopup {
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> { fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
match ev { match ev {
Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => { Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => {
Some(Msg::Ui(UiMsg::CloseReplacePopups)) Some(Msg::PendingAction(PendingActionMsg::CloseReplacePopups))
} }
Event::Keyboard(KeyEvent { code: Key::Tab, .. }) => { Event::Keyboard(KeyEvent { code: Key::Tab, .. }) => {
Some(Msg::Ui(UiMsg::ReplacePopupTabbed)) Some(Msg::Ui(UiMsg::ReplacePopupTabbed))

View File

@@ -183,20 +183,10 @@ impl ProgressStates {
// -- Options // -- Options
/// Defines the transfer options for transfer actions /// Defines the transfer options for transfer actions
#[derive(Default)]
pub struct TransferOpts { pub struct TransferOpts {
/// Save file as /// Save file as
pub save_as: Option<String>, pub save_as: Option<String>,
/// Whether to check if file is being replaced
pub check_replace: bool,
}
impl Default for TransferOpts {
fn default() -> Self {
Self {
save_as: None,
check_replace: true,
}
}
} }
impl TransferOpts { impl TransferOpts {
@@ -205,12 +195,6 @@ impl TransferOpts {
self.save_as = n.map(|x| x.as_ref().to_string()); self.save_as = n.map(|x| x.as_ref().to_string());
self self
} }
/// Set whether to check if the file being transferred will "replace" an existing one
pub fn check_replace(mut self, opt: bool) -> Self {
self.check_replace = opt;
self
}
} }
#[cfg(test)] #[cfg(test)]
@@ -289,12 +273,8 @@ mod test {
#[test] #[test]
fn transfer_opts() { fn transfer_opts() {
let opts = TransferOpts::default(); let opts = TransferOpts::default();
assert_eq!(opts.check_replace, true);
assert!(opts.save_as.is_none()); assert!(opts.save_as.is_none());
let opts = TransferOpts::default() let opts = TransferOpts::default().save_as(Some("omar.txt"));
.check_replace(false)
.save_as(Some("omar.txt"));
assert_eq!(opts.save_as.as_deref().unwrap(), "omar.txt"); assert_eq!(opts.save_as.as_deref().unwrap(), "omar.txt");
assert_eq!(opts.check_replace, false);
} }
} }

View File

@@ -58,8 +58,6 @@ use tuirealm::{Application, EventListenerCfg, NoUserEvent};
/// Stores the explorer width /// Stores the explorer width
const STORAGE_EXPLORER_WIDTH: &str = "FT_EW"; const STORAGE_EXPLORER_WIDTH: &str = "FT_EW";
/// Stores the filename of the entry to transfer, when the replace file dialog must be shown
const STORAGE_PENDING_TRANSFER: &str = "FT_PT";
// -- components // -- components
@@ -108,8 +106,10 @@ enum Msg {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
enum PendingActionMsg { enum PendingActionMsg {
CloseReplacePopups,
CloseSyncBrowsingMkdirPopup, CloseSyncBrowsingMkdirPopup,
MakePendingDirectory, MakePendingDirectory,
TransferPendingFile,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@@ -132,7 +132,6 @@ enum TransferMsg {
SaveFileAs(String), SaveFileAs(String),
SearchFile(String), SearchFile(String),
TransferFile, TransferFile,
TransferPendingFile,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@@ -155,7 +154,6 @@ enum UiMsg {
CloseNewFilePopup, CloseNewFilePopup,
CloseOpenWithPopup, CloseOpenWithPopup,
CloseQuitPopup, CloseQuitPopup,
CloseReplacePopups,
CloseRenamePopup, CloseRenamePopup,
CloseSaveAsPopup, CloseSaveAsPopup,
Disconnect, Disconnect,

View File

@@ -340,10 +340,6 @@ impl FileTransferActivity {
} }
self.update_browser_file_list_swapped(); self.update_browser_file_list_swapped();
} }
TransferMsg::TransferPendingFile => {
self.umount_radio_replace();
self.action_finalize_pending_transfer();
}
} }
// Force redraw // Force redraw
self.redraw = true; self.redraw = true;
@@ -411,9 +407,6 @@ impl FileTransferActivity {
UiMsg::CloseOpenWithPopup => self.umount_openwith(), UiMsg::CloseOpenWithPopup => self.umount_openwith(),
UiMsg::CloseQuitPopup => self.umount_quit(), UiMsg::CloseQuitPopup => self.umount_quit(),
UiMsg::CloseRenamePopup => self.umount_rename(), UiMsg::CloseRenamePopup => self.umount_rename(),
UiMsg::CloseReplacePopups => {
self.umount_radio_replace();
}
UiMsg::CloseSaveAsPopup => self.umount_saveas(), UiMsg::CloseSaveAsPopup => self.umount_saveas(),
UiMsg::Disconnect => { UiMsg::Disconnect => {
self.disconnect(); self.disconnect();