Added file replace prompt also for 'Many'

This commit is contained in:
veeso 2021-09-25 20:18:50 +02:00
parent 3c3d681ca0
commit bcc6fcd2e7
6 changed files with 200 additions and 38 deletions

View file

@ -130,9 +130,28 @@ impl FileTransferActivity {
dest_path.push(save_as);
}
// Iter files
let entries = entries.iter().map(|x| x.get_realfile()).collect();
let entries: Vec<FsEntry> = entries.iter().map(|x| x.get_realfile()).collect();
match self.browser.tab() {
FileExplorerTab::FindLocal | FileExplorerTab::Local => {
if opts.check_replace && self.config().get_prompt_on_file_replace() {
// Check which file would be replaced
let existing_files: Vec<&FsEntry> = entries
.iter()
.filter(|x| {
self.remote_file_exists(
Self::file_to_check_many(x, dest_path.as_path()).as_path(),
)
})
.collect();
// Save pending transfer
if !existing_files.is_empty() {
self.set_pending_transfer_many(
existing_files,
&dest_path.to_string_lossy().to_owned(),
);
return;
}
}
if let Err(err) = self.filetransfer_send(
TransferPayload::Many(entries),
dest_path.as_path(),
@ -148,6 +167,26 @@ impl FileTransferActivity {
}
}
FileExplorerTab::FindRemote | FileExplorerTab::Remote => {
if opts.check_replace && self.config().get_prompt_on_file_replace() {
// Check which file would be replaced
let existing_files: Vec<&FsEntry> = entries
.iter()
.filter(|x| {
self.local_file_exists(
Self::file_to_check_many(x, dest_path.as_path()).as_path(),
)
})
.collect();
// Save pending transfer
// Save pending transfer
if !existing_files.is_empty() {
self.set_pending_transfer_many(
existing_files,
&dest_path.to_string_lossy().to_owned(),
);
return;
}
}
if let Err(err) = self.filetransfer_recv(
TransferPayload::Many(entries),
dest_path.as_path(),

View file

@ -30,15 +30,15 @@ use super::{
super::STORAGE_PENDING_TRANSFER, FileExplorerTab, FileTransferActivity, FsEntry, LogLevel,
SelectedEntry, TransferOpts, TransferPayload,
};
use std::path::PathBuf;
use std::path::{Path, PathBuf};
impl FileTransferActivity {
pub(crate) fn action_local_saveas(&mut self, input: String) {
self.local_send_file(TransferOpts::default().save_as(input));
self.local_send_file(TransferOpts::default().save_as(Some(input)));
}
pub(crate) fn action_remote_saveas(&mut self, input: String) {
self.remote_recv_file(TransferOpts::default().save_as(input));
self.remote_recv_file(TransferOpts::default().save_as(Some(input)));
}
pub(crate) fn action_local_send(&mut self) {
@ -57,11 +57,10 @@ impl FileTransferActivity {
/// NOTE: Panics if `STORAGE_PENDING_TRANSFER` is undefined
pub(crate) fn action_finalize_pending_transfer(&mut self) {
// Retrieve pending transfer
let file_name: String = self
let file_name = self
.context_mut()
.store_mut()
.take_string(STORAGE_PENDING_TRANSFER)
.unwrap();
.take_string(STORAGE_PENDING_TRANSFER);
// Send file
match self.browser.tab() {
FileExplorerTab::Local => self.local_send_file(
@ -82,9 +81,12 @@ impl FileTransferActivity {
}
// Reload browsers
match self.browser.tab() {
FileExplorerTab::Local => self.reload_remote_dir(),
FileExplorerTab::Remote => self.reload_local_dir(),
FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {}
FileExplorerTab::Local | FileExplorerTab::FindLocal => {
self.update_remote_filelist();
}
FileExplorerTab::Remote | FileExplorerTab::FindRemote => {
self.update_local_filelist();
}
}
}
@ -122,7 +124,26 @@ impl FileTransferActivity {
dest_path.push(save_as);
}
// Iter files
let entries = entries.iter().map(|x| x.get_realfile()).collect();
let entries: Vec<FsEntry> = entries.iter().map(|x| x.get_realfile()).collect();
if opts.check_replace && self.config().get_prompt_on_file_replace() {
// Check which file would be replaced
let existing_files: Vec<&FsEntry> = entries
.iter()
.filter(|x| {
self.remote_file_exists(
Self::file_to_check_many(x, dest_path.as_path()).as_path(),
)
})
.collect();
// Save pending transfer
if !existing_files.is_empty() {
self.set_pending_transfer_many(
existing_files,
&dest_path.to_string_lossy().to_owned(),
);
return;
}
}
if let Err(err) = self.filetransfer_send(
TransferPayload::Many(entries),
dest_path.as_path(),
@ -175,7 +196,26 @@ impl FileTransferActivity {
dest_path.push(save_as);
}
// Iter files
let entries = entries.iter().map(|x| x.get_realfile()).collect();
let entries: Vec<FsEntry> = entries.iter().map(|x| x.get_realfile()).collect();
if opts.check_replace && self.config().get_prompt_on_file_replace() {
// Check which file would be replaced
let existing_files: Vec<&FsEntry> = entries
.iter()
.filter(|x| {
self.local_file_exists(
Self::file_to_check_many(x, dest_path.as_path()).as_path(),
)
})
.collect();
// Save pending transfer
if !existing_files.is_empty() {
self.set_pending_transfer_many(
existing_files,
&dest_path.to_string_lossy().to_owned(),
);
return;
}
}
if let Err(err) = self.filetransfer_recv(
TransferPayload::Many(entries),
dest_path.as_path(),
@ -205,6 +245,17 @@ impl FileTransferActivity {
.set_string(STORAGE_PENDING_TRANSFER, file_name.to_string());
}
/// ### set_pending_transfer_many
///
/// Set pending transfer for many files into storage and mount radio
pub(crate) fn set_pending_transfer_many(&mut self, files: Vec<&FsEntry>, dest_path: &str) {
let file_names: Vec<&str> = files.iter().map(|x| x.get_name()).collect();
self.mount_radio_replace_many(file_names.as_slice());
self.context_mut()
.store_mut()
.set_string(STORAGE_PENDING_TRANSFER, dest_path.to_string());
}
/// ### file_to_check
///
/// Get file to check for path
@ -214,4 +265,10 @@ impl FileTransferActivity {
None => PathBuf::from(e.get_name()),
}
}
pub(crate) fn file_to_check_many(e: &FsEntry, wrkdir: &Path) -> PathBuf {
let mut p = wrkdir.to_path_buf();
p.push(e.get_name());
p
}
}

View file

@ -222,8 +222,8 @@ impl TransferOpts {
/// ### save_as
///
/// Define the name of the file to be saved
pub fn save_as<S: AsRef<str>>(mut self, n: S) -> Self {
self.save_as = Some(n.as_ref().to_string());
pub fn save_as<S: AsRef<str>>(mut self, n: Option<S>) -> Self {
self.save_as = n.map(|x| x.as_ref().to_string());
self
}
@ -314,7 +314,7 @@ mod test {
assert!(opts.save_as.is_none());
let opts = TransferOpts::default()
.check_replace(false)
.save_as("omar.txt");
.save_as(Some("omar.txt"));
assert_eq!(opts.save_as.as_deref().unwrap(), "omar.txt");
assert_eq!(opts.check_replace, false);
}

View file

@ -88,6 +88,7 @@ const COMPONENT_RADIO_SORTING: &str = "RADIO_SORTING";
const COMPONENT_SPAN_STATUS_BAR_LOCAL: &str = "STATUS_BAR_LOCAL";
const COMPONENT_SPAN_STATUS_BAR_REMOTE: &str = "STATUS_BAR_REMOTE";
const COMPONENT_LIST_FILEINFO: &str = "LIST_FILEINFO";
const COMPONENT_LIST_REPLACING_FILES: &str = "LIST_REPLACING_FILES"; // NOTE: used for file transfers, to list files which are going to be replaced
/// ## LogLevel
///

View file

@ -31,10 +31,11 @@ use super::{
COMPONENT_EXPLORER_FIND, COMPONENT_EXPLORER_LOCAL, COMPONENT_EXPLORER_REMOTE,
COMPONENT_INPUT_COPY, COMPONENT_INPUT_EXEC, COMPONENT_INPUT_FIND, COMPONENT_INPUT_GOTO,
COMPONENT_INPUT_MKDIR, COMPONENT_INPUT_NEWFILE, COMPONENT_INPUT_OPEN_WITH,
COMPONENT_INPUT_RENAME, COMPONENT_INPUT_SAVEAS, COMPONENT_LIST_FILEINFO, COMPONENT_LOG_BOX,
COMPONENT_PROGRESS_BAR_FULL, COMPONENT_PROGRESS_BAR_PARTIAL, COMPONENT_RADIO_DELETE,
COMPONENT_RADIO_DISCONNECT, COMPONENT_RADIO_QUIT, COMPONENT_RADIO_REPLACE,
COMPONENT_RADIO_SORTING, COMPONENT_TEXT_ERROR, COMPONENT_TEXT_FATAL, COMPONENT_TEXT_HELP,
COMPONENT_INPUT_RENAME, COMPONENT_INPUT_SAVEAS, COMPONENT_LIST_FILEINFO,
COMPONENT_LIST_REPLACING_FILES, COMPONENT_LOG_BOX, COMPONENT_PROGRESS_BAR_FULL,
COMPONENT_PROGRESS_BAR_PARTIAL, COMPONENT_RADIO_DELETE, COMPONENT_RADIO_DISCONNECT,
COMPONENT_RADIO_QUIT, COMPONENT_RADIO_REPLACE, COMPONENT_RADIO_SORTING, COMPONENT_TEXT_ERROR,
COMPONENT_TEXT_FATAL, COMPONENT_TEXT_HELP,
};
use crate::fs::explorer::FileSorting;
use crate::fs::FsEntry;
@ -583,7 +584,7 @@ impl Update for FileTransferActivity {
FileExplorerTab::Remote => self.action_remote_saveas(input.to_string()),
FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {
// Get entry
self.action_find_transfer(TransferOpts::default().save_as(input));
self.action_find_transfer(TransferOpts::default().save_as(Some(input)));
}
}
self.umount_saveas();
@ -661,6 +662,12 @@ impl Update for FileTransferActivity {
self.umount_radio_replace();
None
}
(COMPONENT_RADIO_REPLACE, key) if key == &MSG_KEY_TAB => {
if self.is_radio_replace_extended() {
self.view.active(COMPONENT_LIST_REPLACING_FILES);
}
None
}
(COMPONENT_RADIO_REPLACE, Msg::OnSubmit(Payload::One(Value::Usize(0)))) => {
// Choice is 'YES'
self.umount_radio_replace();
@ -668,6 +675,15 @@ impl Update for FileTransferActivity {
None
}
(COMPONENT_RADIO_REPLACE, _) => None,
(COMPONENT_LIST_REPLACING_FILES, key) if key == &MSG_KEY_TAB => {
self.view.active(COMPONENT_RADIO_REPLACE);
None
}
(COMPONENT_LIST_REPLACING_FILES, key) if key == &MSG_KEY_ESC => {
self.umount_radio_replace();
None
}
(COMPONENT_LIST_REPLACING_FILES, _) => None,
// -- disconnect
(COMPONENT_RADIO_DISCONNECT, key)
if key == &MSG_KEY_ESC

View file

@ -310,10 +310,30 @@ impl FileTransferActivity {
}
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_REPLACE) {
if props.visible {
let popup = draw_area_in(f.size(), 50, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_RADIO_REPLACE, f, popup);
// NOTE: handle extended / normal modes
if self.is_radio_replace_extended() {
let popup = draw_area_in(f.size(), 50, 50);
f.render_widget(Clear, popup);
let popup_chunks = Layout::default()
.direction(Direction::Vertical)
.constraints(
[
Constraint::Percentage(85), // List
Constraint::Percentage(15), // Radio
]
.as_ref(),
)
.split(popup);
self.view
.render(super::COMPONENT_LIST_REPLACING_FILES, f, popup_chunks[0]);
self.view
.render(super::COMPONENT_RADIO_REPLACE, f, popup_chunks[1]);
} else {
let popup = draw_area_in(f.size(), 50, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_RADIO_REPLACE, f, popup);
}
}
}
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_DISCONNECT) {
@ -708,28 +728,57 @@ impl FileTransferActivity {
pub(super) fn mount_radio_replace(&mut self, file_name: &str) {
let warn_color = self.theme().misc_warn_dialog;
self.view.mount(
self.mount_radio_dialog(
super::COMPONENT_RADIO_REPLACE,
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(warn_color)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Plain, warn_color)
format!("File '{}' already exists. Overwrite file?", file_name),
&["Yes", "No"],
0,
warn_color,
);
}
pub(super) fn mount_radio_replace_many(&mut self, files: &[&str]) {
let warn_color = self.theme().misc_warn_dialog;
// Make rows
let rows = files.iter().map(|x| vec![TextSpan::new(x)]).collect();
self.view.mount(
super::COMPONENT_LIST_REPLACING_FILES,
Box::new(List::new(
ListPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, warn_color)
.scrollable(true)
.with_highlighted_color(warn_color)
.with_highlighted_str(Some("> "))
.with_title(
format!("File '{}' already exists. Overwrite file?", file_name),
"The following files are going to be replaced",
Alignment::Center,
)
.with_options(&[String::from("Yes"), String::from("No")])
.with_value(0)
.rewind(true)
.with_foreground(warn_color)
.with_rows(rows)
.build(),
)),
);
self.view.active(super::COMPONENT_RADIO_REPLACE);
self.mount_radio_dialog(
super::COMPONENT_RADIO_REPLACE,
"Overwrite files?",
&["Yes", "No"],
0,
warn_color,
);
}
/// ### is_radio_replace_extended
///
/// Returns whether radio replace is in "extended" mode (for many files)
pub(super) fn is_radio_replace_extended(&self) -> bool {
self.view
.get_state(super::COMPONENT_LIST_REPLACING_FILES)
.is_some()
}
pub(super) fn umount_radio_replace(&mut self) {
self.view.umount(super::COMPONENT_RADIO_REPLACE);
self.view.umount(super::COMPONENT_LIST_REPLACING_FILES); // NOTE: replace anyway
}
pub(super) fn mount_file_info(&mut self, file: &FsEntry) {
@ -1056,10 +1105,10 @@ impl FileTransferActivity {
self.view.active(id);
}
fn mount_radio_dialog(
fn mount_radio_dialog<S: AsRef<str>>(
&mut self,
id: &str,
text: &str,
text: S,
opts: &[&str],
default: usize,
color: Color,
@ -1071,7 +1120,7 @@ impl FileTransferActivity {
.with_color(color)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, color)
.with_title(text, Alignment::Center)
.with_title(text.as_ref(), Alignment::Center)
.with_options(opts)
.with_value(default)
.rewind(true)