Re-use mounts in UI

This commit is contained in:
veeso 2021-09-19 11:16:18 +02:00
parent 88a0685097
commit 63e7023342
4 changed files with 205 additions and 308 deletions

View file

@ -38,6 +38,8 @@ Released on ??
- Install update via GUI from auth form: when the "new version message" is displayed press `<CTRL+R>`, then enter `YES` in the radio input asking whether to install the update.
- **❗ BREAKING CHANGES ❗**:
- Added a new key in themes: `misc_info_dialog`: if your theme won't load, just reload it. If you're using a customised theme, you can add to it the missing key via a text editor. Just edit the `theme.toml` in your `$CONFIG_DIR/termscp/theme.toml` and add `misc_info_dialog` (Read more in manual at Themes).
- Enhancements:
- Reuse mounts in UI, in order to reduce executable size
- Dependencies:
- Added `rust-s3 0.27-rc4`
- Added `self_update 0.27.0`

View file

@ -29,8 +29,6 @@ use super::{AuthActivity, FileTransferParams, FileTransferProtocol};
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams};
use crate::system::auto_update::{Update, UpdateStatus};
use tuirealm::tui::style::Color;
impl AuthActivity {
/// ### protocol_opt_to_enum
///
@ -164,7 +162,7 @@ impl AuthActivity {
// Umount release notes
self.umount_release_notes();
// Mount wait box
self.mount_wait("Installing update. Please wait…", Color::LightYellow);
self.mount_wait("Installing update. Please wait…");
// Refresh UI
self.view();
// Install update
@ -173,13 +171,10 @@ impl AuthActivity {
self.umount_wait();
// Show outcome
match result {
Ok(UpdateStatus::AlreadyUptodate) => {
self.mount_info("termscp is already up to date!", Color::Cyan)
Ok(UpdateStatus::AlreadyUptodate) => self.mount_info("termscp is already up to date!"),
Ok(UpdateStatus::UpdateInstalled(ver)) => {
self.mount_info(format!("termscp has been updated to version {}!", ver))
}
Ok(UpdateStatus::UpdateInstalled(ver)) => self.mount_info(
format!("termscp has been updated to version {}!", ver),
Color::Green,
),
Err(err) => self.mount_error(format!("Could not install update: {}", err)),
}
}

View file

@ -544,22 +544,8 @@ impl AuthActivity {
///
/// Mount error box
pub(super) fn mount_error<S: AsRef<str>>(&mut self, text: S) {
// Mount
let err_color = self.theme().misc_error_dialog;
self.view.mount(
super::COMPONENT_TEXT_ERROR,
Box::new(Paragraph::new(
ParagraphPropsBuilder::default()
.with_foreground(err_color)
.with_borders(Borders::ALL, BorderType::Thick, err_color)
.bold()
.with_text_alignment(Alignment::Center)
.with_texts(vec![TextSpan::from(text.as_ref().to_string())])
.build(),
)),
);
// Give focus to error
self.view.active(super::COMPONENT_TEXT_ERROR);
self.mount_text_dialog(super::COMPONENT_TEXT_ERROR, text.as_ref(), err_color);
}
/// ### umount_error
@ -572,22 +558,9 @@ impl AuthActivity {
/// ### mount_info
///
/// Mount info box
pub(super) fn mount_info<S: AsRef<str>>(&mut self, text: S, color: Color) {
// Mount
self.view.mount(
super::COMPONENT_TEXT_INFO,
Box::new(Paragraph::new(
ParagraphPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Thick, color)
.with_foreground(color)
.bold()
.with_text_alignment(Alignment::Center)
.with_texts(vec![TextSpan::from(text.as_ref().to_string())])
.build(),
)),
);
// Give focus to error
self.view.active(super::COMPONENT_TEXT_INFO);
pub(super) fn mount_info<S: AsRef<str>>(&mut self, text: S) {
let color = self.theme().misc_info_dialog;
self.mount_text_dialog(super::COMPONENT_TEXT_INFO, text.as_ref(), color);
}
/// ### umount_info
@ -600,22 +573,9 @@ impl AuthActivity {
/// ### mount_error
///
/// Mount wait box
pub(super) fn mount_wait(&mut self, text: &str, color: Color) {
// Mount
self.view.mount(
super::COMPONENT_TEXT_WAIT,
Box::new(Paragraph::new(
ParagraphPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Thick, color)
.with_foreground(color)
.bold()
.with_text_alignment(Alignment::Center)
.with_texts(vec![TextSpan::from(text)])
.build(),
)),
);
// Give focus to error
self.view.active(super::COMPONENT_TEXT_WAIT);
pub(super) fn mount_wait(&mut self, text: &str) {
let wait_color = self.theme().misc_info_dialog;
self.mount_text_dialog(super::COMPONENT_TEXT_WAIT, text, wait_color);
}
/// ### umount_wait
@ -631,22 +591,11 @@ impl AuthActivity {
pub(super) fn mount_size_err(&mut self) {
// Mount
let err_color = self.theme().misc_error_dialog;
self.view.mount(
self.mount_text_dialog(
super::COMPONENT_TEXT_SIZE_ERR,
Box::new(Paragraph::new(
ParagraphPropsBuilder::default()
.with_foreground(err_color)
.with_borders(Borders::ALL, BorderType::Thick, err_color)
.bold()
.with_texts(vec![TextSpan::from(
"termscp requires at least 24 lines of height to run",
)])
.with_text_alignment(Alignment::Center)
.build(),
)),
"termscp requires at least 24 lines of height to run",
err_color,
);
// Give focus to error
self.view.active(super::COMPONENT_TEXT_SIZE_ERR);
}
/// ### umount_size_err
@ -662,20 +611,13 @@ impl AuthActivity {
pub(super) fn mount_quit(&mut self) {
// Protocol
let quit_color = self.theme().misc_quit_dialog;
self.view.mount(
self.mount_radio_dialog(
super::COMPONENT_RADIO_QUIT,
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(quit_color)
.with_borders(Borders::ALL, BorderType::Rounded, quit_color)
.with_inverted_color(Color::Black)
.with_title("Quit termscp?", Alignment::Center)
.with_options(&[String::from("Yes"), String::from("No")])
.rewind(true)
.build(),
)),
"Quit termscp?",
&["Yes", "No"],
0,
quit_color,
);
self.view.active(super::COMPONENT_RADIO_QUIT);
}
/// ### umount_quit
@ -690,23 +632,13 @@ impl AuthActivity {
/// Mount bookmark delete dialog
pub(super) fn mount_bookmark_del_dialog(&mut self) {
let warn_color = self.theme().misc_warn_dialog;
self.view.mount(
self.mount_radio_dialog(
super::COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK,
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(warn_color)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, warn_color)
.with_title("Delete bookmark?", Alignment::Center)
.with_options(&[String::from("Yes"), String::from("No")])
.with_value(1)
.rewind(true)
.build(),
)),
"Delete bookmark?",
&["Yes", "No"],
1,
warn_color,
);
// Active
self.view
.active(super::COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK);
}
/// ### umount_bookmark_del_dialog
@ -722,22 +654,13 @@ impl AuthActivity {
/// Mount recent delete dialog
pub(super) fn mount_recent_del_dialog(&mut self) {
let warn_color = self.theme().misc_warn_dialog;
self.view.mount(
self.mount_radio_dialog(
super::COMPONENT_RADIO_BOOKMARK_DEL_RECENT,
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(warn_color)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, warn_color)
.with_title("Delete bookmark?", Alignment::Center)
.with_options(&[String::from("Yes"), String::from("No")])
.with_value(1)
.rewind(true)
.build(),
)),
"Delete bookmark?",
&["Yes", "No"],
1,
warn_color,
);
// Active
self.view.active(super::COMPONENT_RADIO_BOOKMARK_DEL_RECENT);
}
/// ### umount_recent_del_dialog
@ -859,32 +782,25 @@ impl AuthActivity {
if let Some(release_notes) = ctx.store().get_string(super::STORE_KEY_RELEASE_NOTES) {
// make spans
let spans: Vec<TextSpan> = release_notes.lines().map(TextSpan::from).collect();
let info_color = self.theme().misc_info_dialog;
self.view.mount(
super::COMPONENT_TEXT_NEW_VERSION_NOTES,
Box::new(Textarea::new(
TextareaPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightYellow)
.with_borders(Borders::ALL, BorderType::Rounded, info_color)
.with_title("Release notes", Alignment::Center)
.with_texts(spans)
.build(),
)),
);
// Mount install popup
self.view.mount(
self.mount_radio_dialog(
super::COMPONENT_RADIO_INSTALL_UPDATE,
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightYellow)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightYellow)
.with_title("Install new version?", Alignment::Left)
.with_options(&["Yes", "No"])
.with_value(0)
.rewind(true)
.build(),
)),
"Install new version?",
&["Yes", "No"],
0,
info_color,
);
self.view.active(super::COMPONENT_RADIO_INSTALL_UPDATE);
}
}
}
@ -1033,4 +949,50 @@ impl AuthActivity {
}
}
}
// -- mount helpers
fn mount_text_dialog(&mut self, id: &str, text: &str, color: Color) {
// Mount
self.view.mount(
id,
Box::new(Paragraph::new(
ParagraphPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Thick, color)
.with_foreground(color)
.bold()
.with_text_alignment(Alignment::Center)
.with_texts(vec![TextSpan::from(text)])
.build(),
)),
);
// Give focus to error
self.view.active(id);
}
fn mount_radio_dialog(
&mut self,
id: &str,
text: &str,
opts: &[&str],
default: usize,
color: Color,
) {
self.view.mount(
id,
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(color)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, color)
.with_title(text, Alignment::Center)
.with_options(opts)
.with_value(default)
.rewind(true)
.build(),
)),
);
// Active
self.view.active(id);
}
}

View file

@ -378,20 +378,7 @@ impl FileTransferActivity {
pub(super) fn mount_error(&mut self, text: &str) {
// Mount
let error_color = self.theme().misc_error_dialog;
self.view.mount(
super::COMPONENT_TEXT_ERROR,
Box::new(Paragraph::new(
ParagraphPropsBuilder::default()
.with_foreground(error_color)
.with_borders(Borders::ALL, BorderType::Rounded, error_color)
.bold()
.with_text_alignment(Alignment::Center)
.with_texts(vec![TextSpan::from(text)])
.build(),
)),
);
// Give focus to error
self.view.active(super::COMPONENT_TEXT_ERROR);
self.mount_text_dialog(super::COMPONENT_TEXT_ERROR, text, error_color);
}
/// ### umount_error
@ -404,46 +391,21 @@ impl FileTransferActivity {
pub(super) fn mount_fatal(&mut self, text: &str) {
// Mount
let error_color = self.theme().misc_error_dialog;
self.view.mount(
super::COMPONENT_TEXT_FATAL,
Box::new(Paragraph::new(
ParagraphPropsBuilder::default()
.with_foreground(error_color)
.with_borders(Borders::ALL, BorderType::Rounded, error_color)
.bold()
.with_text_alignment(Alignment::Center)
.with_texts(vec![TextSpan::from(text)])
.build(),
)),
);
// Give focus to error
self.view.active(super::COMPONENT_TEXT_FATAL);
self.mount_text_dialog(super::COMPONENT_TEXT_FATAL, text, error_color);
}
pub(super) fn mount_wait(&mut self, text: &str) {
self.mount_wait_ex(text, Color::Reset);
self.mount_wait_ex(text);
}
pub(super) fn mount_blocking_wait(&mut self, text: &str) {
self.mount_wait_ex(text, Color::Reset);
self.mount_wait_ex(text);
self.view();
}
fn mount_wait_ex(&mut self, text: &str, color: Color) {
// Mount
let mut builder: ParagraphPropsBuilder = ParagraphPropsBuilder::default();
builder
.with_foreground(color)
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.bold()
.with_text_alignment(Alignment::Center)
.with_texts(vec![TextSpan::from(text)]);
self.view.mount(
super::COMPONENT_TEXT_WAIT,
Box::new(Paragraph::new(builder.build())),
);
// Give focus to info
self.view.active(super::COMPONENT_TEXT_WAIT);
fn mount_wait_ex(&mut self, text: &str) {
let color = self.theme().misc_info_dialog;
self.mount_text_dialog(super::COMPONENT_TEXT_WAIT, text, color);
}
pub(super) fn umount_wait(&mut self) {
@ -456,20 +418,13 @@ impl FileTransferActivity {
pub(super) fn mount_quit(&mut self) {
// Protocol
let quit_color = self.theme().misc_quit_dialog;
self.view.mount(
self.mount_radio_dialog(
super::COMPONENT_RADIO_QUIT,
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(quit_color)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, quit_color)
.with_title("Are you sure you want to quit?", Alignment::Center)
.with_options(&[String::from("Yes"), String::from("No")])
.rewind(true)
.build(),
)),
"Are you sure you want to quit?",
&["Yes", "No"],
0,
quit_color,
);
self.view.active(super::COMPONENT_RADIO_QUIT);
}
/// ### umount_quit
@ -485,20 +440,13 @@ impl FileTransferActivity {
pub(super) fn mount_disconnect(&mut self) {
// Protocol
let quit_color = self.theme().misc_quit_dialog;
self.view.mount(
self.mount_radio_dialog(
super::COMPONENT_RADIO_DISCONNECT,
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(quit_color)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, quit_color)
.with_title("Are you sure you want to disconnect?", Alignment::Center)
.with_options(&[String::from("Yes"), String::from("No")])
.rewind(true)
.build(),
)),
"Are you sure you want to disconnect?",
&["Yes", "No"],
0,
quit_color,
);
self.view.active(super::COMPONENT_RADIO_DISCONNECT);
}
/// ### umount_disconnect
@ -510,17 +458,12 @@ impl FileTransferActivity {
pub(super) fn mount_copy(&mut self) {
let input_color = self.theme().misc_input_dialog;
self.view.mount(
self.mount_input_dialog(
super::COMPONENT_INPUT_COPY,
Box::new(Input::new(
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, input_color)
.with_foreground(input_color)
.with_label("Copy file(s) to…", Alignment::Center)
.build(),
)),
"Copy file(s) to…",
"",
input_color,
);
self.view.active(super::COMPONENT_INPUT_COPY);
}
pub(super) fn umount_copy(&mut self) {
@ -529,17 +472,12 @@ impl FileTransferActivity {
pub(super) fn mount_exec(&mut self) {
let input_color = self.theme().misc_input_dialog;
self.view.mount(
self.mount_input_dialog(
super::COMPONENT_INPUT_EXEC,
Box::new(Input::new(
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, input_color)
.with_foreground(input_color)
.with_label("Execute command", Alignment::Center)
.build(),
)),
"Execute command",
"",
input_color,
);
self.view.active(super::COMPONENT_INPUT_EXEC);
}
pub(super) fn umount_exec(&mut self) {
@ -586,18 +524,12 @@ impl FileTransferActivity {
pub(super) fn mount_find_input(&mut self) {
let input_color = self.theme().misc_input_dialog;
self.view.mount(
self.mount_input_dialog(
super::COMPONENT_INPUT_FIND,
Box::new(Input::new(
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, input_color)
.with_foreground(input_color)
.with_label("Search files by name", Alignment::Center)
.build(),
)),
"Search files by name",
"",
input_color,
);
// Give focus to input find
self.view.active(super::COMPONENT_INPUT_FIND);
}
pub(super) fn umount_find_input(&mut self) {
@ -607,17 +539,12 @@ impl FileTransferActivity {
pub(super) fn mount_goto(&mut self) {
let input_color = self.theme().misc_input_dialog;
self.view.mount(
self.mount_input_dialog(
super::COMPONENT_INPUT_GOTO,
Box::new(Input::new(
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, input_color)
.with_foreground(input_color)
.with_label("Change working directory", Alignment::Center)
.build(),
)),
"Change working directory",
"",
input_color,
);
self.view.active(super::COMPONENT_INPUT_GOTO);
}
pub(super) fn umount_goto(&mut self) {
@ -626,17 +553,12 @@ impl FileTransferActivity {
pub(super) fn mount_mkdir(&mut self) {
let input_color = self.theme().misc_input_dialog;
self.view.mount(
self.mount_input_dialog(
super::COMPONENT_INPUT_MKDIR,
Box::new(Input::new(
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, input_color)
.with_foreground(input_color)
.with_label("Insert directory name", Alignment::Center)
.build(),
)),
"Insert directory name",
"",
input_color,
);
self.view.active(super::COMPONENT_INPUT_MKDIR);
}
pub(super) fn umount_mkdir(&mut self) {
@ -645,17 +567,12 @@ impl FileTransferActivity {
pub(super) fn mount_newfile(&mut self) {
let input_color = self.theme().misc_input_dialog;
self.view.mount(
self.mount_input_dialog(
super::COMPONENT_INPUT_NEWFILE,
Box::new(Input::new(
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, input_color)
.with_foreground(input_color)
.with_label("New file name", Alignment::Center)
.build(),
)),
"New file name",
"",
input_color,
);
self.view.active(super::COMPONENT_INPUT_NEWFILE);
}
pub(super) fn umount_newfile(&mut self) {
@ -664,17 +581,12 @@ impl FileTransferActivity {
pub(super) fn mount_openwith(&mut self) {
let input_color = self.theme().misc_input_dialog;
self.view.mount(
self.mount_input_dialog(
super::COMPONENT_INPUT_OPEN_WITH,
Box::new(Input::new(
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, input_color)
.with_foreground(input_color)
.with_label("Open file with…", Alignment::Center)
.build(),
)),
"Open file with…",
"",
input_color,
);
self.view.active(super::COMPONENT_INPUT_OPEN_WITH);
}
pub(super) fn umount_openwith(&mut self) {
@ -683,17 +595,12 @@ impl FileTransferActivity {
pub(super) fn mount_rename(&mut self) {
let input_color = self.theme().misc_input_dialog;
self.view.mount(
self.mount_input_dialog(
super::COMPONENT_INPUT_RENAME,
Box::new(Input::new(
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, input_color)
.with_foreground(input_color)
.with_label("Move file(s) to…", Alignment::Center)
.build(),
)),
"Move file(s) to…",
"",
input_color,
);
self.view.active(super::COMPONENT_INPUT_RENAME);
}
pub(super) fn umount_rename(&mut self) {
@ -702,17 +609,7 @@ impl FileTransferActivity {
pub(super) fn mount_saveas(&mut self) {
let input_color = self.theme().misc_input_dialog;
self.view.mount(
super::COMPONENT_INPUT_SAVEAS,
Box::new(Input::new(
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, input_color)
.with_foreground(input_color)
.with_label("Save as…", Alignment::Center)
.build(),
)),
);
self.view.active(super::COMPONENT_INPUT_SAVEAS);
self.mount_input_dialog(super::COMPONENT_INPUT_SAVEAS, "Save as…", "", input_color);
}
pub(super) fn umount_saveas(&mut self) {
@ -773,25 +670,13 @@ impl FileTransferActivity {
FileSorting::Name => 0,
FileSorting::Size => 3,
};
self.view.mount(
self.mount_radio_dialog(
super::COMPONENT_RADIO_SORTING,
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(sorting_color)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, sorting_color)
.with_title("Sort files by", Alignment::Center)
.with_options(&[
String::from("Name"),
String::from("Modify time"),
String::from("Creation time"),
String::from("Size"),
])
.with_value(index)
.build(),
)),
"Sort files by",
&["Name", "Modify time", "Creation time", "Size"],
index,
sorting_color,
);
self.view.active(super::COMPONENT_RADIO_SORTING);
}
pub(super) fn umount_file_sorting(&mut self) {
@ -800,21 +685,13 @@ impl FileTransferActivity {
pub(super) fn mount_radio_delete(&mut self) {
let warn_color = self.theme().misc_warn_dialog;
self.view.mount(
self.mount_radio_dialog(
super::COMPONENT_RADIO_DELETE,
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(warn_color)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Plain, warn_color)
.with_title("Delete file", Alignment::Center)
.with_options(&[String::from("Yes"), String::from("No")])
.with_value(1)
.rewind(true)
.build(),
)),
"Delete file",
&["Yes", "No"],
1,
warn_color,
);
self.view.active(super::COMPONENT_RADIO_DELETE);
}
pub(super) fn umount_radio_delete(&mut self) {
@ -1109,4 +986,65 @@ impl FileTransferActivity {
false => "Hide",
}
}
// -- Mount helpers
fn mount_text_dialog(&mut self, id: &str, text: &str, color: Color) {
// Mount
self.view.mount(
id,
Box::new(Paragraph::new(
ParagraphPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Thick, color)
.with_foreground(color)
.bold()
.with_text_alignment(Alignment::Center)
.with_texts(vec![TextSpan::from(text)])
.build(),
)),
);
// Give focus to error
self.view.active(id);
}
fn mount_input_dialog(&mut self, id: &str, text: &str, val: &str, color: Color) {
self.view.mount(
id,
Box::new(Input::new(
InputPropsBuilder::default()
.with_foreground(color)
.with_label(text, Alignment::Center)
.with_borders(Borders::ALL, BorderType::Rounded, color)
.with_value(val.to_string())
.build(),
)),
);
self.view.active(id);
}
fn mount_radio_dialog(
&mut self,
id: &str,
text: &str,
opts: &[&str],
default: usize,
color: Color,
) {
self.view.mount(
id,
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(color)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, color)
.with_title(text, Alignment::Center)
.with_options(opts)
.with_value(default)
.rewind(true)
.build(),
)),
);
// Active
self.view.active(id);
}
}