Removed tui; added tuirealm

This commit is contained in:
veeso
2021-04-24 11:38:28 +02:00
parent 84c36f1789
commit 8bb66b53e0
35 changed files with 1191 additions and 4066 deletions

View File

@@ -32,11 +32,11 @@ extern crate dirs;
use super::{AuthActivity, FileTransferProtocol};
use crate::system::bookmarks_client::BookmarksClient;
use crate::system::environment;
use crate::ui::layout::props::PropValue;
use crate::ui::layout::Payload;
// Ext
use std::path::PathBuf;
use tuirealm::components::{input::InputPropsBuilder, radio::RadioPropsBuilder};
use tuirealm::{Payload, PropsBuilder};
impl AuthActivity {
/// ### del_bookmark
@@ -83,7 +83,7 @@ impl AuthActivity {
let password: Option<String> = match save_password {
true => match self
.view
.get_value(super::COMPONENT_RADIO_BOOKMARK_SAVE_PWD)
.get_state(super::COMPONENT_RADIO_BOOKMARK_SAVE_PWD)
{
Some(Payload::Unsigned(0)) => Some(password), // Yes
_ => None, // No such component / No
@@ -246,32 +246,34 @@ impl AuthActivity {
password: Option<String>,
) {
// Load parameters into components
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_ADDR) {
let props = props.with_value(PropValue::Str(addr)).build();
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_ADDR) {
let props = InputPropsBuilder::from(props).with_value(addr).build();
self.view.update(super::COMPONENT_INPUT_ADDR, props);
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_PORT) {
let props = props.with_value(PropValue::Str(port.to_string())).build();
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_PORT) {
let props = InputPropsBuilder::from(props)
.with_value(port.to_string())
.build();
self.view.update(super::COMPONENT_INPUT_PORT, props);
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_RADIO_PROTOCOL) {
let props = props
.with_value(PropValue::Unsigned(match protocol {
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_PROTOCOL) {
let props = RadioPropsBuilder::from(props)
.with_value(match protocol {
FileTransferProtocol::Sftp => 0,
FileTransferProtocol::Scp => 1,
FileTransferProtocol::Ftp(false) => 2,
FileTransferProtocol::Ftp(true) => 3,
}))
})
.build();
self.view.update(super::COMPONENT_RADIO_PROTOCOL, props);
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_USERNAME) {
let props = props.with_value(PropValue::Str(username)).build();
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_USERNAME) {
let props = InputPropsBuilder::from(props).with_value(username).build();
self.view.update(super::COMPONENT_INPUT_USERNAME, props);
}
if let Some(password) = password {
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_PASSWORD) {
let props = props.with_value(PropValue::Str(password)).build();
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_PASSWORD) {
let props = InputPropsBuilder::from(props).with_value(password).build();
self.view.update(super::COMPONENT_INPUT_PASSWORD, props);
}
}

View File

@@ -32,18 +32,18 @@ mod view;
// Dependencies
extern crate crossterm;
extern crate tui;
extern crate tuirealm;
// locals
use super::{Activity, Context, ExitReason};
use crate::filetransfer::FileTransferProtocol;
use crate::system::bookmarks_client::BookmarksClient;
use crate::ui::context::FileTransferParams;
use crate::ui::layout::view::View;
use crate::utils::git;
// Includes
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use tuirealm::View;
// -- components
const COMPONENT_TEXT_HEADER: &str = "TEXT_HEADER";

View File

@@ -35,7 +35,7 @@ use super::{
COMPONENT_TEXT_HELP,
};
use crate::ui::activities::keymap::*;
use crate::ui::layout::{Msg, Payload};
use tuirealm::{Msg, Payload};
// -- update
@@ -164,7 +164,7 @@ impl AuthActivity {
match *index {
0 => {
// Get selected bookmark
match self.view.get_value(COMPONENT_BOOKMARKS_LIST) {
match self.view.get_state(COMPONENT_BOOKMARKS_LIST) {
Some(Payload::Unsigned(index)) => {
// Delete bookmark
self.del_bookmark(index);
@@ -184,7 +184,7 @@ impl AuthActivity {
match *index {
0 => {
// Get selected bookmark
match self.view.get_value(COMPONENT_RECENTS_LIST) {
match self.view.get_state(COMPONENT_RECENTS_LIST) {
Some(Payload::Unsigned(index)) => {
// Delete recent
self.del_recent(index);
@@ -199,36 +199,12 @@ impl AuthActivity {
}
// <ESC> hide tab
(COMPONENT_RADIO_BOOKMARK_DEL_RECENT, &MSG_KEY_ESC) => {
match self
.view
.get_props(COMPONENT_RADIO_BOOKMARK_DEL_RECENT)
.as_mut()
{
Some(props) => {
let msg = self.view.update(
COMPONENT_RADIO_BOOKMARK_DEL_RECENT,
props.hidden().build(),
);
self.update(msg)
}
None => None,
}
self.umount_recent_del_dialog();
None
}
(COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK, &MSG_KEY_ESC) => {
match self
.view
.get_props(COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK)
.as_mut()
{
Some(props) => {
let msg = self.view.update(
COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK,
props.hidden().build(),
);
self.update(msg)
}
None => None,
}
self.umount_bookmark_del_dialog();
None
}
// Help
(_, &MSG_KEY_CTRL_H) => {
@@ -269,12 +245,12 @@ impl AuthActivity {
| (COMPONENT_RADIO_BOOKMARK_SAVE_PWD, Msg::OnSubmit(_)) => {
// Get values
let bookmark_name: String =
match self.view.get_value(COMPONENT_INPUT_BOOKMARK_NAME) {
match self.view.get_state(COMPONENT_INPUT_BOOKMARK_NAME) {
Some(Payload::Text(s)) => s,
_ => String::new(),
};
let save_pwd: bool = matches!(
self.view.get_value(COMPONENT_RADIO_BOOKMARK_SAVE_PWD),
self.view.get_state(COMPONENT_RADIO_BOOKMARK_SAVE_PWD),
Some(Payload::Unsigned(0))
);
// Save bookmark

View File

@@ -27,20 +27,27 @@
*/
// Locals
use super::{AuthActivity, Context, FileTransferProtocol};
use crate::ui::layout::components::{
bookmark_list::BookmarkList, input::Input, msgbox::MsgBox, radio_group::RadioGroup,
table::Table, text::Text, title::Title,
use crate::ui::components::{
bookmark_list::{BookmarkList, BookmarkListPropsBuilder},
msgbox::{MsgBox, MsgBoxPropsBuilder},
};
use crate::ui::layout::props::{
InputType, PropValue, PropsBuilder, TableBuilder, TextParts, TextSpan, TextSpanBuilder,
};
use crate::ui::layout::utils::draw_area_in;
use crate::ui::layout::{Msg, Payload};
use crate::utils::ui::draw_area_in;
// Ext
use tui::{
use tuirealm::components::{
input::{Input, InputPropsBuilder},
label::{Label, LabelPropsBuilder},
radio::{Radio, RadioPropsBuilder},
span::{Span, SpanPropsBuilder},
table::{Table, TablePropsBuilder},
};
use tuirealm::tui::{
layout::{Constraint, Direction, Layout},
style::Color,
widgets::Clear,
widgets::{BorderType, Borders, Clear},
};
use tuirealm::{
props::{InputType, PropsBuilder, TableBuilder, TextSpan, TextSpanBuilder},
Msg, Payload,
};
impl AuthActivity {
@@ -50,35 +57,32 @@ impl AuthActivity {
pub(super) fn init(&mut self) {
// Header
self.view.mount(super::COMPONENT_TEXT_HEADER, Box::new(
Title::new(
PropsBuilder::default().with_foreground(Color::White).with_texts(
TextParts::new(Some(String::from(" _____ ____ ____ ____ \n|_ _|__ _ __ _ __ ___ / ___| / ___| _ \\ \n | |/ _ \\ '__| '_ ` _ \\\\___ \\| | | |_) |\n | | __/ | | | | | | |___) | |___| __/ \n |_|\\___|_| |_| |_| |_|____/ \\____|_| \n")), None)
Label::new(
LabelPropsBuilder::default().with_foreground(Color::White).with_text(
String::from(" _____ ____ ____ ____ \n|_ _|__ _ __ _ __ ___ / ___| / ___| _ \\ \n | |/ _ \\ '__| '_ ` _ \\\\___ \\| | | |_) |\n | | __/ | | | | | | |___) | |___| __/ \n |_|\\___|_| |_| |_| |_|____/ \\____|_| \n")
).bold().build()
)
));
// Footer
self.view.mount(
super::COMPONENT_TEXT_FOOTER,
Box::new(Text::new(
PropsBuilder::default()
.with_texts(TextParts::new(
None,
Some(vec![
TextSpanBuilder::new("Press ").bold().build(),
TextSpanBuilder::new("<CTRL+H>")
.bold()
.with_foreground(Color::Cyan)
.build(),
TextSpanBuilder::new(" to show keybindings; ")
.bold()
.build(),
TextSpanBuilder::new("<CTRL+C>")
.bold()
.with_foreground(Color::Cyan)
.build(),
TextSpanBuilder::new(" to enter setup").bold().build(),
]),
))
Box::new(Span::new(
SpanPropsBuilder::default()
.with_spans(vec![
TextSpanBuilder::new("Press ").bold().build(),
TextSpanBuilder::new("<CTRL+H>")
.bold()
.with_foreground(Color::Cyan)
.build(),
TextSpanBuilder::new(" to show keybindings; ")
.bold()
.build(),
TextSpanBuilder::new("<CTRL+C>")
.bold()
.with_foreground(Color::Cyan)
.build(),
TextSpanBuilder::new(" to enter setup").bold().build(),
])
.build(),
)),
);
@@ -86,9 +90,10 @@ impl AuthActivity {
self.view.mount(
super::COMPONENT_INPUT_ADDR,
Box::new(Input::new(
PropsBuilder::default()
InputPropsBuilder::default()
.with_foreground(Color::Yellow)
.with_texts(TextParts::new(Some(String::from("Remote address")), None))
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightYellow)
.with_label(String::from("Remote address"))
.build(),
)),
);
@@ -96,31 +101,33 @@ impl AuthActivity {
self.view.mount(
super::COMPONENT_INPUT_PORT,
Box::new(Input::new(
PropsBuilder::default()
InputPropsBuilder::default()
.with_foreground(Color::LightCyan)
.with_texts(TextParts::new(Some(String::from("Port number")), None))
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightCyan)
.with_label(String::from("Port number"))
.with_input(InputType::Number)
.with_input_len(5)
.with_value(PropValue::Str(String::from("22")))
.with_value(String::from("22"))
.build(),
)),
);
// Protocol
self.view.mount(
super::COMPONENT_RADIO_PROTOCOL,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::LightGreen)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightGreen)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightGreen)
.with_options(
Some(String::from("Protocol")),
Some(vec![
TextSpan::from("SFTP"),
TextSpan::from("SCP"),
TextSpan::from("FTP"),
TextSpan::from("FTPS"),
]),
))
vec![
String::from("SFTP"),
String::from("SCP"),
String::from("FTP"),
String::from("FTPS"),
],
)
.build(),
)),
);
@@ -128,9 +135,10 @@ impl AuthActivity {
self.view.mount(
super::COMPONENT_INPUT_USERNAME,
Box::new(Input::new(
PropsBuilder::default()
InputPropsBuilder::default()
.with_foreground(Color::LightMagenta)
.with_texts(TextParts::new(Some(String::from("Username")), None))
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightMagenta)
.with_label(String::from("Username"))
.build(),
)),
);
@@ -138,9 +146,10 @@ impl AuthActivity {
self.view.mount(
super::COMPONENT_INPUT_PASSWORD,
Box::new(Input::new(
PropsBuilder::default()
InputPropsBuilder::default()
.with_foreground(Color::LightBlue)
.with_texts(TextParts::new(Some(String::from("Password")), None))
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightBlue)
.with_label(String::from("Password"))
.with_input(InputType::Password)
.build(),
)),
@@ -155,10 +164,16 @@ impl AuthActivity {
{
self.view.mount(
super::COMPONENT_TEXT_NEW_VERSION,
Box::new(Text::new(
PropsBuilder::default()
Box::new(Span::new(
SpanPropsBuilder::default()
.with_foreground(Color::Yellow)
.with_texts(TextParts::new(None, Some(vec![TextSpan::from(format!("TermSCP {} is now available! Download it from <https://github.com/veeso/termscp/releases/latest>", version))])))
.with_spans(
vec![
TextSpan::from("TermSCP "),
TextSpanBuilder::new(version).underlined().bold().build(),
TextSpan::from(" is now available! Download it from <https://github.com/veeso/termscp/releases/latest>")
]
)
.build()
))
);
@@ -167,10 +182,11 @@ impl AuthActivity {
self.view.mount(
super::COMPONENT_BOOKMARKS_LIST,
Box::new(BookmarkList::new(
PropsBuilder::default()
BookmarkListPropsBuilder::default()
.with_background(Color::LightGreen)
.with_foreground(Color::Black)
.with_texts(TextParts::new(Some(String::from("Bookmarks")), None))
.with_borders(Borders::ALL, BorderType::Plain, Color::LightGreen)
.with_bookmarks(Some(String::from("Bookmarks")), vec![])
.build(),
)),
);
@@ -179,13 +195,11 @@ impl AuthActivity {
self.view.mount(
super::COMPONENT_RECENTS_LIST,
Box::new(BookmarkList::new(
PropsBuilder::default()
BookmarkListPropsBuilder::default()
.with_background(Color::LightBlue)
.with_foreground(Color::Black)
.with_texts(TextParts::new(
Some(String::from("Recent connections")),
None,
))
.with_borders(Borders::ALL, BorderType::Plain, Color::LightBlue)
.with_bookmarks(Some(String::from("Recent connections")), vec![])
.build(),
)),
);
@@ -258,27 +272,27 @@ impl AuthActivity {
self.view
.render(super::COMPONENT_RECENTS_LIST, f, bookmark_chunks[1]);
// Popups
if let Some(mut props) = self.view.get_props(super::COMPONENT_TEXT_ERROR) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_ERROR) {
if props.visible {
let popup = draw_area_in(f.size(), 50, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_TEXT_ERROR, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_RADIO_QUIT) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_QUIT) {
if props.visible {
// make popup
let popup = draw_area_in(f.size(), 30, 10);
f.render_widget(Clear, popup);
self.view.render(super::COMPONENT_RADIO_QUIT, f, popup);
}
}
if let Some(mut props) = self
if let Some(props) = self
.view
.get_props(super::COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK)
{
if props.build().visible {
if props.visible {
// make popup
let popup = draw_area_in(f.size(), 30, 10);
f.render_widget(Clear, popup);
@@ -286,11 +300,11 @@ impl AuthActivity {
.render(super::COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK, f, popup);
}
}
if let Some(mut props) = self
if let Some(props) = self
.view
.get_props(super::COMPONENT_RADIO_BOOKMARK_DEL_RECENT)
{
if props.build().visible {
if props.visible {
// make popup
let popup = draw_area_in(f.size(), 30, 10);
f.render_widget(Clear, popup);
@@ -298,19 +312,19 @@ impl AuthActivity {
.render(super::COMPONENT_RADIO_BOOKMARK_DEL_RECENT, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_TEXT_HELP) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_HELP) {
if props.visible {
// make popup
let popup = draw_area_in(f.size(), 50, 70);
f.render_widget(Clear, popup);
self.view.render(super::COMPONENT_TEXT_HELP, f, popup);
}
}
if let Some(mut props) = self
if let Some(props) = self
.view
.get_props(super::COMPONENT_RADIO_BOOKMARK_SAVE_PWD)
{
if props.build().visible {
if props.visible {
// make popup
let popup = draw_area_in(f.size(), 20, 20);
f.render_widget(Clear, popup);
@@ -340,7 +354,7 @@ impl AuthActivity {
///
/// Make text span from bookmarks
pub(super) fn view_bookmarks(&mut self) -> Option<(String, Msg)> {
let bookmarks: Vec<TextSpan> = self
let bookmarks: Vec<String> = self
.bookmarks_list
.iter()
.map(|x| {
@@ -350,33 +364,23 @@ impl AuthActivity {
.unwrap()
.get_bookmark(x)
.unwrap();
TextSpan::from(
format!(
"{} ({}://{}@{}:{})",
x,
entry.2.to_string().to_lowercase(),
entry.3,
entry.0,
entry.1
)
.as_str(),
format!(
"{} ({}://{}@{}:{})",
x,
entry.2.to_string().to_lowercase(),
entry.3,
entry.0,
entry.1
)
})
.collect();
match self
.view
.get_props(super::COMPONENT_BOOKMARKS_LIST)
.as_mut()
{
match self.view.get_props(super::COMPONENT_BOOKMARKS_LIST) {
None => None,
Some(props) => {
let msg = self.view.update(
super::COMPONENT_BOOKMARKS_LIST,
props
.with_texts(TextParts::new(
Some(String::from("Bookmarks")),
Some(bookmarks),
))
BookmarkListPropsBuilder::from(props)
.with_bookmarks(Some(String::from("Bookmarks")), bookmarks)
.build(),
);
msg
@@ -388,7 +392,7 @@ impl AuthActivity {
///
/// View recent connections
pub(super) fn view_recent_connections(&mut self) -> Option<(String, Msg)> {
let bookmarks: Vec<TextSpan> = self
let bookmarks: Vec<String> = self
.recents_list
.iter()
.map(|x| {
@@ -398,28 +402,23 @@ impl AuthActivity {
.unwrap()
.get_recent(x)
.unwrap();
TextSpan::from(
format!(
"{}://{}@{}:{}",
entry.2.to_string().to_lowercase(),
entry.3,
entry.0,
entry.1
)
.as_str(),
format!(
"{}://{}@{}:{}",
entry.2.to_string().to_lowercase(),
entry.3,
entry.0,
entry.1
)
})
.collect();
match self.view.get_props(super::COMPONENT_RECENTS_LIST).as_mut() {
match self.view.get_props(super::COMPONENT_RECENTS_LIST) {
None => None,
Some(props) => {
let msg = self.view.update(
super::COMPONENT_RECENTS_LIST,
props
.with_texts(TextParts::new(
Some(String::from("Recent connections")),
Some(bookmarks),
))
BookmarkListPropsBuilder::from(props)
.with_bookmarks(Some(String::from("Recent connections")), bookmarks)
.build(),
);
msg
@@ -437,10 +436,11 @@ impl AuthActivity {
self.view.mount(
super::COMPONENT_TEXT_ERROR,
Box::new(MsgBox::new(
PropsBuilder::default()
MsgBoxPropsBuilder::default()
.with_foreground(Color::Red)
.with_borders(Borders::ALL, BorderType::Thick, Color::Red)
.bold()
.with_texts(TextParts::new(None, Some(vec![TextSpan::from(text)])))
.with_texts(None, vec![TextSpan::from(text)])
.build(),
)),
);
@@ -462,14 +462,15 @@ impl AuthActivity {
// Protocol
self.view.mount(
super::COMPONENT_RADIO_QUIT,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::Yellow)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::Yellow)
.with_borders(Borders::ALL, BorderType::Rounded, Color::Yellow)
.with_inverted_color(Color::Black)
.with_options(
Some(String::from("Quit TermSCP?")),
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
))
vec![String::from("Yes"), String::from("No")],
)
.build(),
)),
);
@@ -489,15 +490,16 @@ impl AuthActivity {
pub(super) fn mount_bookmark_del_dialog(&mut self) {
self.view.mount(
super::COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::Yellow)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::Yellow)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::Yellow)
.with_options(
Some(String::from("Delete bookmark?")),
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
))
.with_value(PropValue::Unsigned(1))
vec![String::from("Yes"), String::from("No")],
)
.with_value(1)
.build(),
)),
);
@@ -520,15 +522,16 @@ impl AuthActivity {
pub(super) fn mount_recent_del_dialog(&mut self) {
self.view.mount(
super::COMPONENT_RADIO_BOOKMARK_DEL_RECENT,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::Yellow)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::Yellow)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::Yellow)
.with_options(
Some(String::from("Delete bookmark?")),
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
))
.with_value(PropValue::Unsigned(1))
vec![String::from("Yes"), String::from("No")],
)
.with_value(1)
.build(),
)),
);
@@ -550,27 +553,31 @@ impl AuthActivity {
self.view.mount(
super::COMPONENT_INPUT_BOOKMARK_NAME,
Box::new(Input::new(
PropsBuilder::default()
InputPropsBuilder::default()
.with_foreground(Color::LightCyan)
.with_texts(TextParts::new(
Some(String::from("Save bookmark as...")),
None,
))
//.with_borders(Borders::TOP | Borders::RIGHT | Borders::LEFT)
.with_label(String::from("Save bookmark as..."))
.with_borders(
Borders::TOP | Borders::RIGHT | Borders::LEFT,
BorderType::Rounded,
Color::Reset,
)
.build(),
)),
);
self.view.mount(
super::COMPONENT_RADIO_BOOKMARK_SAVE_PWD,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::Red)
//.with_borders(Borders::BOTTOM | Borders::RIGHT | Borders::LEFT)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::Red)
.with_borders(
Borders::BOTTOM | Borders::RIGHT | Borders::LEFT,
BorderType::Rounded,
Color::Reset,
)
.with_options(
Some(String::from("Save password?")),
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
))
//.with_value(PropValue::Unsigned(1))
vec![String::from("Yes"), String::from("No")],
)
.build(),
)),
);
@@ -593,8 +600,9 @@ impl AuthActivity {
self.view.mount(
super::COMPONENT_TEXT_HELP,
Box::new(Table::new(
PropsBuilder::default()
.with_texts(TextParts::table(
TablePropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.with_table(
Some(String::from("Help")),
TableBuilder::default()
.add_col(
@@ -661,7 +669,7 @@ impl AuthActivity {
)
.add_col(TextSpan::from(" Save bookmark"))
.build(),
))
)
.build(),
)),
);
@@ -680,16 +688,16 @@ impl AuthActivity {
///
/// Collect input values from view
pub(super) fn get_input(&self) -> (String, u16, FileTransferProtocol, String, String) {
let addr: String = match self.view.get_value(super::COMPONENT_INPUT_ADDR) {
let addr: String = match self.view.get_state(super::COMPONENT_INPUT_ADDR) {
Some(Payload::Text(a)) => a,
_ => String::new(),
};
let port: u16 = match self.view.get_value(super::COMPONENT_INPUT_PORT) {
let port: u16 = match self.view.get_state(super::COMPONENT_INPUT_PORT) {
Some(Payload::Unsigned(p)) => p as u16,
_ => 0,
};
let protocol: FileTransferProtocol =
match self.view.get_value(super::COMPONENT_RADIO_PROTOCOL) {
match self.view.get_state(super::COMPONENT_RADIO_PROTOCOL) {
Some(Payload::Unsigned(p)) => match p {
1 => FileTransferProtocol::Scp,
2 => FileTransferProtocol::Ftp(false),
@@ -698,11 +706,11 @@ impl AuthActivity {
},
_ => FileTransferProtocol::Sftp,
};
let username: String = match self.view.get_value(super::COMPONENT_INPUT_USERNAME) {
let username: String = match self.view.get_state(super::COMPONENT_INPUT_USERNAME) {
Some(Payload::Text(a)) => a,
_ => String::new(),
};
let password: String = match self.view.get_value(super::COMPONENT_INPUT_PASSWORD) {
let password: String = match self.view.get_state(super::COMPONENT_INPUT_PASSWORD) {
Some(Payload::Text(a)) => a,
_ => String::new(),
};

View File

@@ -27,7 +27,7 @@
*/
// locals
use super::{FileExplorerTab, FileTransferActivity, FsEntry, LogLevel};
use crate::ui::layout::Payload;
use tuirealm::Payload;
// externals
use std::path::PathBuf;
@@ -622,7 +622,7 @@ impl FileTransferActivity {
///
/// Get index of selected file in the local tab
fn get_local_file_idx(&self) -> Option<usize> {
match self.view.get_value(super::COMPONENT_EXPLORER_LOCAL) {
match self.view.get_state(super::COMPONENT_EXPLORER_LOCAL) {
Some(Payload::Unsigned(idx)) => Some(idx),
_ => None,
}
@@ -632,7 +632,7 @@ impl FileTransferActivity {
///
/// Get index of selected file in the remote file
fn get_remote_file_idx(&self) -> Option<usize> {
match self.view.get_value(super::COMPONENT_EXPLORER_REMOTE) {
match self.view.get_state(super::COMPONENT_EXPLORER_REMOTE) {
Some(Payload::Unsigned(idx)) => Some(idx),
_ => None,
}

View File

@@ -36,7 +36,7 @@ mod view;
extern crate chrono;
extern crate crossterm;
extern crate textwrap;
extern crate tui;
extern crate tuirealm;
// locals
use super::{Activity, Context, ExitReason};
@@ -47,7 +47,6 @@ use crate::filetransfer::{FileTransfer, FileTransferProtocol};
use crate::fs::explorer::FileExplorer;
use crate::fs::FsEntry;
use crate::system::config_client::ConfigClient;
use crate::ui::layout::view::View;
// Includes
use chrono::{DateTime, Local};
@@ -55,6 +54,7 @@ use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use std::collections::VecDeque;
use std::path::PathBuf;
use std::time::Instant;
use tuirealm::View;
// -- Storage keys

View File

@@ -40,14 +40,16 @@ use super::{
use crate::fs::explorer::FileSorting;
use crate::fs::FsEntry;
use crate::ui::activities::keymap::*;
use crate::ui::layout::props::{
PropValue, PropsBuilder, TableBuilder, TextParts, TextSpan, TextSpanBuilder,
};
use crate::ui::layout::{Msg, Payload};
use crate::ui::components::{file_list::FileListPropsBuilder, logbox::LogboxPropsBuilder};
// externals
use bytesize::ByteSize;
use std::path::{Path, PathBuf};
use tui::style::Color;
use tuirealm::{
components::progress_bar::ProgressBarPropsBuilder,
props::{PropsBuilder, TableBuilder, TextSpan, TextSpanBuilder},
tui::style::Color,
Msg, Payload,
};
impl FileTransferActivity {
// -- update
@@ -394,7 +396,7 @@ impl FileTransferActivity {
}
(COMPONENT_EXPLORER_FIND, &MSG_KEY_SPACE) => {
// Get entry
match self.view.get_value(COMPONENT_EXPLORER_FIND) {
match self.view.get_state(COMPONENT_EXPLORER_FIND) {
Some(Payload::Unsigned(idx)) => {
self.action_find_transfer(idx, None);
// Reload files
@@ -585,7 +587,7 @@ impl FileTransferActivity {
FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {
// Get entry
if let Some(Payload::Unsigned(idx)) =
self.view.get_value(COMPONENT_EXPLORER_FIND)
self.view.get_state(COMPONENT_EXPLORER_FIND)
{
self.action_find_transfer(idx, Some(input.to_string()));
}
@@ -621,7 +623,7 @@ impl FileTransferActivity {
FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {
// Get entry
if let Some(Payload::Unsigned(idx)) =
self.view.get_value(COMPONENT_EXPLORER_FIND)
self.view.get_state(COMPONENT_EXPLORER_FIND)
{
self.action_find_delete(idx);
// Reload entries
@@ -662,11 +664,12 @@ impl FileTransferActivity {
None
}
// -- sorting
(COMPONENT_RADIO_SORTING, &MSG_KEY_ESC) => {
(COMPONENT_RADIO_SORTING, &MSG_KEY_ESC)
| (COMPONENT_RADIO_SORTING, Msg::OnSubmit(_)) => {
self.umount_file_sorting();
None
}
(COMPONENT_RADIO_SORTING, Msg::OnSubmit(Payload::Unsigned(mode))) => {
(COMPONENT_RADIO_SORTING, Msg::OnChange(Payload::Unsigned(mode))) => {
// Get sorting mode
let sorting: FileSorting = match mode {
1 => FileSorting::ByModifyTime,
@@ -679,7 +682,6 @@ impl FileTransferActivity {
FileExplorerTab::Remote => self.remote.sort_by(sorting),
_ => panic!("Found result doesn't support SORTING"),
}
self.umount_file_sorting();
// Reload files
match self.tab {
FileExplorerTab::Local => self.update_local_filelist(),
@@ -718,11 +720,7 @@ impl FileTransferActivity {
///
/// Update local file list
pub(super) fn update_local_filelist(&mut self) -> Option<(String, Msg)> {
match self
.view
.get_props(super::COMPONENT_EXPLORER_LOCAL)
.as_mut()
{
match self.view.get_props(super::COMPONENT_EXPLORER_LOCAL) {
Some(props) => {
// Get width
let width: usize = self
@@ -750,14 +748,14 @@ impl FileTransferActivity {
)
.display()
);
let files: Vec<TextSpan> = self
let files: Vec<String> = self
.local
.iter_files()
.map(|x: &FsEntry| TextSpan::from(self.local.fmt_file(x)))
.map(|x: &FsEntry| self.local.fmt_file(x))
.collect();
// Update
let props = props
.with_texts(TextParts::new(Some(hostname), Some(files)))
let props = FileListPropsBuilder::from(props)
.with_files(Some(hostname), files)
.build();
// Update
self.view.update(super::COMPONENT_EXPLORER_LOCAL, props)
@@ -770,11 +768,7 @@ impl FileTransferActivity {
///
/// Update remote file list
pub(super) fn update_remote_filelist(&mut self) -> Option<(String, Msg)> {
match self
.view
.get_props(super::COMPONENT_EXPLORER_REMOTE)
.as_mut()
{
match self.view.get_props(super::COMPONENT_EXPLORER_REMOTE) {
Some(props) => {
// Get width
let width: usize = self
@@ -795,14 +789,14 @@ impl FileTransferActivity {
)
.display()
);
let files: Vec<TextSpan> = self
let files: Vec<String> = self
.remote
.iter_files()
.map(|x: &FsEntry| TextSpan::from(self.remote.fmt_file(x)))
.map(|x: &FsEntry| self.remote.fmt_file(x))
.collect();
// Update
let props = props
.with_texts(TextParts::new(Some(hostname), Some(files)))
let props = FileListPropsBuilder::from(props)
.with_files(Some(hostname), files)
.build();
self.view.update(super::COMPONENT_EXPLORER_REMOTE, props)
}
@@ -814,7 +808,7 @@ impl FileTransferActivity {
///
/// Update log box
pub(super) fn update_logbox(&mut self) -> Option<(String, Msg)> {
match self.view.get_props(super::COMPONENT_LOG_BOX).as_mut() {
match self.view.get_props(super::COMPONENT_LOG_BOX) {
Some(props) => {
// Get width
let width: usize = self
@@ -876,8 +870,8 @@ impl FileTransferActivity {
}
}
let table = table.build();
let props = props
.with_texts(TextParts::table(Some(String::from("Log")), table))
let props = LogboxPropsBuilder::from(props)
.with_log(Some(String::from("Log")), table)
.build();
self.view.update(super::COMPONENT_LOG_BOX, props)
}
@@ -886,7 +880,7 @@ impl FileTransferActivity {
}
pub(super) fn update_progress_bar(&mut self, text: String) -> Option<(String, Msg)> {
match self.view.get_props(COMPONENT_PROGRESS_BAR).as_mut() {
match self.view.get_props(COMPONENT_PROGRESS_BAR) {
Some(props) => {
// Calculate ETA
let elapsed_secs: u64 = self.transfer.started.elapsed().as_secs();
@@ -905,12 +899,9 @@ impl FileTransferActivity {
eta,
ByteSize(self.transfer.bytes_per_second())
);
let props = props
.with_texts(TextParts::new(
Some(text),
Some(vec![TextSpan::from(label)]),
))
.with_value(PropValue::Float(self.transfer.progress / 100.0))
let props = ProgressBarPropsBuilder::from(props)
.with_texts(Some(text), label)
.with_progress(self.transfer.progress / 100.0)
.build();
self.view.update(COMPONENT_PROGRESS_BAR, props)
}
@@ -933,22 +924,20 @@ impl FileTransferActivity {
}
fn update_find_list(&mut self) -> Option<(String, Msg)> {
match self.view.get_props(COMPONENT_EXPLORER_FIND).as_mut() {
match self.view.get_props(COMPONENT_EXPLORER_FIND) {
None => None,
Some(props) => {
let props = props.build();
let title: String = props.texts.title.clone().unwrap_or_default();
let mut props = PropsBuilder::from(props);
// Prepare files
let file_texts: Vec<TextSpan> = self
let files: Vec<String> = self
.found
.as_ref()
.unwrap()
.iter_files()
.map(|x: &FsEntry| TextSpan::from(self.found.as_ref().unwrap().fmt_file(x)))
.map(|x: &FsEntry| self.found.as_ref().unwrap().fmt_file(x))
.collect();
let props = props
.with_texts(TextParts::new(Some(title), Some(file_texts)))
let props = FileListPropsBuilder::from(props)
.with_files(Some(title), files)
.build();
self.view.update(COMPONENT_EXPLORER_FIND, props)
}

View File

@@ -34,23 +34,28 @@ extern crate users;
use super::{Context, FileExplorerTab, FileTransferActivity};
use crate::fs::explorer::FileSorting;
use crate::fs::FsEntry;
use crate::ui::layout::components::{
file_list::FileList, input::Input, logbox::LogBox, msgbox::MsgBox, progress_bar::ProgressBar,
radio_group::RadioGroup, table::Table,
use crate::ui::components::{
file_list::{FileList, FileListPropsBuilder},
logbox::{LogBox, LogboxPropsBuilder},
msgbox::{MsgBox, MsgBoxPropsBuilder},
};
use crate::ui::layout::props::{
PropValue, PropsBuilder, TableBuilder, TextParts, TextSpan, TextSpanBuilder,
};
use crate::ui::layout::utils::draw_area_in;
use crate::ui::store::Store;
use crate::utils::fmt::fmt_time;
use crate::utils::ui::draw_area_in;
// Ext
use bytesize::ByteSize;
use std::path::PathBuf;
use tui::{
use tuirealm::components::{
input::{Input, InputPropsBuilder},
progress_bar::{ProgressBar, ProgressBarPropsBuilder},
radio::{Radio, RadioPropsBuilder},
table::{Table, TablePropsBuilder},
};
use tuirealm::props::{PropsBuilder, TableBuilder, TextSpan, TextSpanBuilder};
use tuirealm::tui::{
layout::{Constraint, Direction, Layout},
style::Color,
widgets::Clear,
widgets::{BorderType, Borders, Clear},
};
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
use users::{get_group_by_gid, get_user_by_uid};
@@ -66,9 +71,10 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_EXPLORER_LOCAL,
Box::new(FileList::new(
PropsBuilder::default()
FileListPropsBuilder::default()
.with_background(Color::Yellow)
.with_foreground(Color::Yellow)
.with_borders(Borders::ALL, BorderType::Plain, Color::Yellow)
.build(),
)),
);
@@ -76,9 +82,10 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_EXPLORER_REMOTE,
Box::new(FileList::new(
PropsBuilder::default()
FileListPropsBuilder::default()
.with_background(Color::LightBlue)
.with_foreground(Color::LightBlue)
.with_borders(Borders::ALL, BorderType::Plain, Color::LightBlue)
.build(),
)),
);
@@ -86,9 +93,8 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_LOG_BOX,
Box::new(LogBox::new(
PropsBuilder::default()
.with_foreground(Color::LightGreen)
.bold()
LogboxPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Plain, Color::LightGreen)
.build(),
)),
);
@@ -156,96 +162,96 @@ impl FileTransferActivity {
// Draw log box
self.view.render(super::COMPONENT_LOG_BOX, f, chunks[1]);
// @! Draw popups
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_COPY) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_COPY) {
if props.visible {
let popup = draw_area_in(f.size(), 40, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_INPUT_COPY, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_FIND) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_FIND) {
if props.visible {
let popup = draw_area_in(f.size(), 40, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_INPUT_FIND, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_GOTO) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_GOTO) {
if props.visible {
let popup = draw_area_in(f.size(), 40, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_INPUT_GOTO, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_MKDIR) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_MKDIR) {
if props.visible {
let popup = draw_area_in(f.size(), 40, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_INPUT_MKDIR, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_NEWFILE) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_NEWFILE) {
if props.visible {
let popup = draw_area_in(f.size(), 40, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_INPUT_NEWFILE, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_RENAME) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_RENAME) {
if props.visible {
let popup = draw_area_in(f.size(), 40, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_INPUT_RENAME, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_SAVEAS) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_SAVEAS) {
if props.visible {
let popup = draw_area_in(f.size(), 40, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_INPUT_SAVEAS, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_EXEC) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_EXEC) {
if props.visible {
let popup = draw_area_in(f.size(), 40, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_INPUT_EXEC, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_LIST_FILEINFO) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_LIST_FILEINFO) {
if props.visible {
let popup = draw_area_in(f.size(), 50, 50);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_LIST_FILEINFO, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_PROGRESS_BAR) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_PROGRESS_BAR) {
if props.visible {
let popup = draw_area_in(f.size(), 40, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_PROGRESS_BAR, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_RADIO_DELETE) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_DELETE) {
if props.visible {
let popup = draw_area_in(f.size(), 30, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_RADIO_DELETE, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_RADIO_DISCONNECT) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_DISCONNECT) {
if props.visible {
let popup = draw_area_in(f.size(), 30, 10);
f.render_widget(Clear, popup);
// make popup
@@ -253,48 +259,48 @@ impl FileTransferActivity {
.render(super::COMPONENT_RADIO_DISCONNECT, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_RADIO_QUIT) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_QUIT) {
if props.visible {
let popup = draw_area_in(f.size(), 30, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_RADIO_QUIT, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_RADIO_SORTING) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_SORTING) {
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_SORTING, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_TEXT_ERROR) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_ERROR) {
if props.visible {
let popup = draw_area_in(f.size(), 50, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_TEXT_ERROR, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_TEXT_FATAL) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_FATAL) {
if props.visible {
let popup = draw_area_in(f.size(), 50, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_TEXT_FATAL, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_TEXT_WAIT) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_WAIT) {
if props.visible {
let popup = draw_area_in(f.size(), 50, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_TEXT_WAIT, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_TEXT_HELP) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_HELP) {
if props.visible {
let popup = draw_area_in(f.size(), 50, 80);
f.render_widget(Clear, popup);
// make popup
@@ -316,10 +322,11 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_TEXT_ERROR,
Box::new(MsgBox::new(
PropsBuilder::default()
MsgBoxPropsBuilder::default()
.with_foreground(Color::Red)
.with_borders(Borders::ALL, BorderType::Rounded, Color::Red)
.bold()
.with_texts(TextParts::new(None, Some(vec![TextSpan::from(text)])))
.with_texts(None, vec![TextSpan::from(text)])
.build(),
)),
);
@@ -339,10 +346,11 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_TEXT_FATAL,
Box::new(MsgBox::new(
PropsBuilder::default()
MsgBoxPropsBuilder::default()
.with_foreground(Color::Red)
.with_borders(Borders::ALL, BorderType::Rounded, Color::Red)
.bold()
.with_texts(TextParts::new(None, Some(vec![TextSpan::from(text)])))
.with_texts(None, vec![TextSpan::from(text)])
.build(),
)),
);
@@ -355,10 +363,11 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_TEXT_WAIT,
Box::new(MsgBox::new(
PropsBuilder::default()
MsgBoxPropsBuilder::default()
.with_foreground(Color::White)
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.bold()
.with_texts(TextParts::new(None, Some(vec![TextSpan::from(text)])))
.with_texts(None, vec![TextSpan::from(text)])
.build(),
)),
);
@@ -377,14 +386,15 @@ impl FileTransferActivity {
// Protocol
self.view.mount(
super::COMPONENT_RADIO_QUIT,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::Yellow)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::Yellow)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::Yellow)
.with_options(
Some(String::from("Are you sure you want to quit?")),
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
))
vec![String::from("Yes"), String::from("No")],
)
.build(),
)),
);
@@ -405,14 +415,15 @@ impl FileTransferActivity {
// Protocol
self.view.mount(
super::COMPONENT_RADIO_DISCONNECT,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::Yellow)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::Yellow)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::Yellow)
.with_options(
Some(String::from("Are you sure you want to disconnect?")),
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
))
vec![String::from("Yes"), String::from("No")],
)
.build(),
)),
);
@@ -430,11 +441,9 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_INPUT_COPY,
Box::new(Input::new(
PropsBuilder::default()
.with_texts(TextParts::new(
Some(String::from("Insert destination name")),
None,
))
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.with_label(String::from("Insert destination name"))
.build(),
)),
);
@@ -449,8 +458,9 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_INPUT_EXEC,
Box::new(Input::new(
PropsBuilder::default()
.with_texts(TextParts::new(Some(String::from("Execute command")), None))
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Plain, Color::White)
.with_label(String::from("Execute command"))
.build(),
)),
);
@@ -471,11 +481,9 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_EXPLORER_FIND,
Box::new(FileList::new(
PropsBuilder::default()
.with_texts(TextParts::new(
Some(format!("Search results for \"{}\"", search)),
Some(vec![]),
))
FileListPropsBuilder::default()
.with_files(Some(format!("Search results for \"{}\"", search)), vec![])
.with_borders(Borders::ALL, BorderType::Plain, color)
.with_background(color)
.with_foreground(color)
.build(),
@@ -493,11 +501,9 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_INPUT_FIND,
Box::new(Input::new(
PropsBuilder::default()
.with_texts(TextParts::new(
Some(String::from("Search files by name")),
None,
))
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.with_label(String::from("Search files by name"))
.build(),
)),
);
@@ -514,11 +520,9 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_INPUT_GOTO,
Box::new(Input::new(
PropsBuilder::default()
.with_texts(TextParts::new(
Some(String::from("Change working directory")),
None,
))
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.with_label(String::from("Change working directory"))
.build(),
)),
);
@@ -533,11 +537,9 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_INPUT_MKDIR,
Box::new(Input::new(
PropsBuilder::default()
.with_texts(TextParts::new(
Some(String::from("Insert directory name")),
None,
))
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.with_label(String::from("Insert directory name"))
.build(),
)),
);
@@ -552,8 +554,9 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_INPUT_NEWFILE,
Box::new(Input::new(
PropsBuilder::default()
.with_texts(TextParts::new(Some(String::from("New file name")), None))
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.with_label(String::from("New file name"))
.build(),
)),
);
@@ -568,8 +571,9 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_INPUT_RENAME,
Box::new(Input::new(
PropsBuilder::default()
.with_texts(TextParts::new(Some(String::from("Insert new name")), None))
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.with_label(String::from("Insert new name"))
.build(),
)),
);
@@ -584,8 +588,9 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_INPUT_SAVEAS,
Box::new(Input::new(
PropsBuilder::default()
.with_texts(TextParts::new(Some(String::from("Save as...")), None))
InputPropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.with_label(String::from("Save as..."))
.build(),
)),
);
@@ -600,10 +605,11 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_PROGRESS_BAR,
Box::new(ProgressBar::new(
PropsBuilder::default()
.with_foreground(Color::LightGreen)
ProgressBarPropsBuilder::default()
.with_progbar_color(Color::LightGreen)
.with_background(Color::Black)
.with_texts(TextParts::new(Some(String::from("Please wait")), None))
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightGreen)
.with_texts(Some(String::from("Please wait")), String::new())
.build(),
)),
);
@@ -628,20 +634,21 @@ impl FileTransferActivity {
};
self.view.mount(
super::COMPONENT_RADIO_SORTING,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::LightMagenta)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightMagenta)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightMagenta)
.with_options(
Some(String::from("Sort files by")),
Some(vec![
TextSpan::from("Name"),
TextSpan::from("Modify time"),
TextSpan::from("Creation time"),
TextSpan::from("Size"),
]),
))
.with_value(PropValue::Unsigned(index))
vec![
String::from("Name"),
String::from("Modify time"),
String::from("Creation time"),
String::from("Size"),
],
)
.with_value(index)
.build(),
)),
);
@@ -655,15 +662,16 @@ impl FileTransferActivity {
pub(super) fn mount_radio_delete(&mut self) {
self.view.mount(
super::COMPONENT_RADIO_DELETE,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::Red)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::Red)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Plain, Color::Red)
.with_options(
Some(String::from("Delete file")),
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
))
.with_value(PropValue::Unsigned(1))
vec![String::from("Yes"), String::from("No")],
)
.with_value(1)
.build(),
)),
);
@@ -772,11 +780,9 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_LIST_FILEINFO,
Box::new(Table::new(
PropsBuilder::default()
.with_texts(TextParts::table(
Some(file.get_name().to_string()),
texts.build(),
))
TablePropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.with_table(Some(file.get_name().to_string()), texts.build())
.build(),
)),
);
@@ -794,8 +800,9 @@ impl FileTransferActivity {
self.view.mount(
super::COMPONENT_TEXT_HELP,
Box::new(Table::new(
PropsBuilder::default()
.with_texts(TextParts::table(
TablePropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.with_table(
Some(String::from("Help")),
TableBuilder::default()
.add_col(
@@ -984,7 +991,7 @@ impl FileTransferActivity {
)
.add_col(TextSpan::from(" Interrupt file transfer"))
.build(),
))
)
.build(),
)),
);

View File

@@ -25,8 +25,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::ui::layout::Msg;
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use tuirealm::event::{KeyCode, KeyEvent, KeyModifiers};
use tuirealm::Msg;
// -- Special keys

View File

@@ -28,10 +28,10 @@
*/
// Locals
use super::SetupActivity;
use crate::ui::layout::Payload;
// Ext
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use std::env;
use tuirealm::Payload;
impl SetupActivity {
/// ### action_save_config
@@ -63,7 +63,7 @@ impl SetupActivity {
// Get key
if let Some(config_cli) = self.context.as_mut().unwrap().config_client.as_mut() {
// get index
let idx: Option<usize> = match self.view.get_value(super::COMPONENT_LIST_SSH_KEYS) {
let idx: Option<usize> = match self.view.get_state(super::COMPONENT_LIST_SSH_KEYS) {
Some(Payload::Unsigned(idx)) => Some(idx),
_ => None,
};
@@ -99,11 +99,11 @@ impl SetupActivity {
pub(super) fn action_new_ssh_key(&mut self) {
if let Some(cli) = self.context.as_mut().unwrap().config_client.as_mut() {
// get parameters
let host: String = match self.view.get_value(super::COMPONENT_INPUT_SSH_HOST) {
let host: String = match self.view.get_state(super::COMPONENT_INPUT_SSH_HOST) {
Some(Payload::Text(host)) => host,
_ => String::new(),
};
let username: String = match self.view.get_value(super::COMPONENT_INPUT_SSH_USERNAME) {
let username: String = match self.view.get_state(super::COMPONENT_INPUT_SSH_USERNAME) {
Some(Payload::Text(user)) => user,
_ => String::new(),
};

View File

@@ -34,13 +34,13 @@ mod view;
// Deps
extern crate crossterm;
extern crate tui;
extern crate tuirealm;
// Locals
use super::{Activity, Context, ExitReason};
use crate::ui::layout::view::View;
// Ext
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use tuirealm::View;
// -- components
const COMPONENT_TEXT_HELP: &str = "TEXT_HELP";

View File

@@ -35,7 +35,9 @@ use super::{
COMPONENT_RADIO_UPDATES, COMPONENT_TEXT_ERROR, COMPONENT_TEXT_HELP,
};
use crate::ui::activities::keymap::*;
use crate::ui::layout::{Msg, Payload};
// ext
use tuirealm::{Msg, Payload};
impl SetupActivity {
/// ### update

View File

@@ -30,22 +30,27 @@
use super::{Context, SetupActivity, ViewLayout};
use crate::filetransfer::FileTransferProtocol;
use crate::fs::explorer::GroupDirs;
use crate::ui::layout::components::{
bookmark_list::BookmarkList, input::Input, msgbox::MsgBox, radio_group::RadioGroup,
table::Table, text::Text,
use crate::ui::components::{
bookmark_list::{BookmarkList, BookmarkListPropsBuilder},
msgbox::{MsgBox, MsgBoxPropsBuilder},
};
use crate::ui::layout::props::{
PropValue, PropsBuilder, TableBuilder, TextParts, TextSpan, TextSpanBuilder,
};
use crate::ui::layout::utils::draw_area_in;
use crate::ui::layout::view::View;
use crate::ui::layout::Payload;
use crate::utils::ui::draw_area_in;
// Ext
use std::path::PathBuf;
use tui::{
use tuirealm::components::{
input::{Input, InputPropsBuilder},
radio::{Radio, RadioPropsBuilder},
span::{Span, SpanPropsBuilder},
table::{Table, TablePropsBuilder},
};
use tuirealm::tui::{
layout::{Constraint, Direction, Layout},
style::Color,
widgets::{Borders, Clear},
widgets::{BorderType, Borders, Clear},
};
use tuirealm::{
props::{PropsBuilder, TableBuilder, TextSpan, TextSpanBuilder},
Payload, View,
};
impl SetupActivity {
@@ -61,38 +66,32 @@ impl SetupActivity {
// Radio tab
self.view.mount(
super::COMPONENT_RADIO_TAB,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::LightYellow)
.with_background(Color::Black)
.with_borders(Borders::BOTTOM)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightYellow)
.with_inverted_color(Color::Black)
.with_borders(Borders::BOTTOM, BorderType::Thick, Color::White)
.with_options(
None,
Some(vec![
TextSpan::from("User Interface"),
TextSpan::from("SSH Keys"),
]),
))
.with_value(PropValue::Unsigned(0))
vec![String::from("User Interface"), String::from("SSH Keys")],
)
.with_value(0)
.build(),
)),
);
// Footer
self.view.mount(
super::COMPONENT_TEXT_FOOTER,
Box::new(Text::new(
PropsBuilder::default()
.with_texts(TextParts::new(
None,
Some(vec![
TextSpanBuilder::new("Press ").bold().build(),
TextSpanBuilder::new("<CTRL+H>")
.bold()
.with_foreground(Color::Cyan)
.build(),
TextSpanBuilder::new(" to show keybindings").bold().build(),
]),
))
Box::new(Span::new(
SpanPropsBuilder::default()
.with_spans(vec![
TextSpanBuilder::new("Press ").bold().build(),
TextSpanBuilder::new("<CTRL+H>")
.bold()
.with_foreground(Color::Cyan)
.build(),
TextSpanBuilder::new(" to show keybindings").bold().build(),
])
.build(),
)),
);
@@ -100,83 +99,86 @@ impl SetupActivity {
self.view.mount(
super::COMPONENT_INPUT_TEXT_EDITOR,
Box::new(Input::new(
PropsBuilder::default()
InputPropsBuilder::default()
.with_foreground(Color::LightGreen)
.with_texts(TextParts::new(Some(String::from("Text editor")), None))
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightGreen)
.with_label(String::from("Text editor"))
.build(),
)),
);
self.view.active(super::COMPONENT_INPUT_TEXT_EDITOR); // <-- Focus
self.view.mount(
super::COMPONENT_RADIO_DEFAULT_PROTOCOL,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::LightCyan)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightCyan)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightCyan)
.with_options(
Some(String::from("Default file transfer protocol")),
Some(vec![
TextSpan::from("SFTP"),
TextSpan::from("SCP"),
TextSpan::from("FTP"),
TextSpan::from("FTPS"),
]),
))
vec![
String::from("SFTP"),
String::from("SCP"),
String::from("FTP"),
String::from("FTPS"),
],
)
.build(),
)),
);
self.view.mount(
super::COMPONENT_RADIO_HIDDEN_FILES,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::LightRed)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightRed)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightRed)
.with_options(
Some(String::from("Show hidden files (by default)")),
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
))
vec![String::from("Yes"), String::from("No")],
)
.build(),
)),
);
self.view.mount(
super::COMPONENT_RADIO_UPDATES,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::LightYellow)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightYellow)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightYellow)
.with_options(
Some(String::from("Check for updates?")),
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
))
vec![String::from("Yes"), String::from("No")],
)
.build(),
)),
);
self.view.mount(
super::COMPONENT_RADIO_GROUP_DIRS,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::LightMagenta)
.with_background(Color::Black)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightMagenta)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightMagenta)
.with_options(
Some(String::from("Group directories")),
Some(vec![
TextSpan::from("Display first"),
TextSpan::from("Display Last"),
TextSpan::from("No"),
]),
))
vec![
String::from("Display first"),
String::from("Display Last"),
String::from("No"),
],
)
.build(),
)),
);
self.view.mount(
super::COMPONENT_INPUT_FILE_FMT,
Box::new(Input::new(
PropsBuilder::default()
InputPropsBuilder::default()
.with_foreground(Color::LightBlue)
.with_texts(TextParts::new(
Some(String::from("File formatter syntax")),
None,
))
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightBlue)
.with_label(String::from("File formatter syntax"))
.build(),
)),
);
@@ -196,46 +198,41 @@ impl SetupActivity {
// Radio tab
self.view.mount(
super::COMPONENT_RADIO_TAB,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::LightYellow)
.with_background(Color::Black)
.with_borders(Borders::BOTTOM)
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightYellow)
.with_inverted_color(Color::Black)
.with_borders(Borders::BOTTOM, BorderType::Thick, Color::LightYellow)
.with_options(
None,
Some(vec![
TextSpan::from("User Interface"),
TextSpan::from("SSH Keys"),
]),
))
.with_value(PropValue::Unsigned(1))
vec![String::from("User Interface"), String::from("SSH Keys")],
)
.with_value(1)
.build(),
)),
);
// Footer
self.view.mount(
super::COMPONENT_TEXT_FOOTER,
Box::new(Text::new(
PropsBuilder::default()
.with_texts(TextParts::new(
None,
Some(vec![
TextSpanBuilder::new("Press ").bold().build(),
TextSpanBuilder::new("<CTRL+H>")
.bold()
.with_foreground(Color::Cyan)
.build(),
TextSpanBuilder::new(" to show keybindings").bold().build(),
]),
))
Box::new(Span::new(
SpanPropsBuilder::default()
.with_spans(vec![
TextSpanBuilder::new("Press ").bold().build(),
TextSpanBuilder::new("<CTRL+H>")
.bold()
.with_foreground(Color::Cyan)
.build(),
TextSpanBuilder::new(" to show keybindings").bold().build(),
])
.build(),
)),
);
self.view.mount(
super::COMPONENT_LIST_SSH_KEYS,
Box::new(BookmarkList::new(
PropsBuilder::default()
.with_texts(TextParts::new(Some(String::from("SSH Keys")), Some(vec![])))
BookmarkListPropsBuilder::default()
.with_bookmarks(Some(String::from("SSH Keys")), vec![])
.with_borders(Borders::ALL, BorderType::Plain, Color::LightGreen)
.with_background(Color::LightGreen)
.with_foreground(Color::Black)
.build(),
@@ -312,40 +309,40 @@ impl SetupActivity {
}
}
// Popups
if let Some(mut props) = self.view.get_props(super::COMPONENT_TEXT_ERROR) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_ERROR) {
if props.visible {
let popup = draw_area_in(f.size(), 50, 10);
f.render_widget(Clear, popup);
// make popup
self.view.render(super::COMPONENT_TEXT_ERROR, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_RADIO_QUIT) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_QUIT) {
if props.visible {
// make popup
let popup = draw_area_in(f.size(), 40, 10);
f.render_widget(Clear, popup);
self.view.render(super::COMPONENT_RADIO_QUIT, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_TEXT_HELP) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_HELP) {
if props.visible {
// make popup
let popup = draw_area_in(f.size(), 50, 70);
f.render_widget(Clear, popup);
self.view.render(super::COMPONENT_TEXT_HELP, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_RADIO_SAVE) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_SAVE) {
if props.visible {
// make popup
let popup = draw_area_in(f.size(), 30, 10);
f.render_widget(Clear, popup);
self.view.render(super::COMPONENT_RADIO_SAVE, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_RADIO_DEL_SSH_KEY) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_DEL_SSH_KEY) {
if props.visible {
// make popup
let popup = draw_area_in(f.size(), 30, 10);
f.render_widget(Clear, popup);
@@ -353,8 +350,8 @@ impl SetupActivity {
.render(super::COMPONENT_RADIO_DEL_SSH_KEY, f, popup);
}
}
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_SSH_HOST) {
if props.build().visible {
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_SSH_HOST) {
if props.visible {
// make popup
let popup = draw_area_in(f.size(), 50, 20);
f.render_widget(Clear, popup);
@@ -389,10 +386,11 @@ impl SetupActivity {
self.view.mount(
super::COMPONENT_TEXT_ERROR,
Box::new(MsgBox::new(
PropsBuilder::default()
MsgBoxPropsBuilder::default()
.with_foreground(Color::Red)
.bold()
.with_texts(TextParts::new(None, Some(vec![TextSpan::from(text)])))
.with_borders(Borders::ALL, BorderType::Rounded, Color::Red)
.with_texts(None, vec![TextSpan::from(text)])
.build(),
)),
);
@@ -413,15 +411,16 @@ impl SetupActivity {
pub(super) fn mount_del_ssh_key(&mut self) {
self.view.mount(
super::COMPONENT_RADIO_DEL_SSH_KEY,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::LightRed)
.bold()
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightRed)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightRed)
.with_options(
Some(String::from("Delete key?")),
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
))
.with_value(PropValue::Unsigned(1)) // Default: No
vec![String::from("Yes"), String::from("No")],
)
.with_value(1) // Default: No
.build(),
)),
);
@@ -443,21 +442,26 @@ impl SetupActivity {
self.view.mount(
super::COMPONENT_INPUT_SSH_HOST,
Box::new(Input::new(
PropsBuilder::default()
.with_texts(TextParts::new(
Some(String::from("Hostname or address")),
None,
))
.with_borders(Borders::TOP | Borders::RIGHT | Borders::LEFT)
InputPropsBuilder::default()
.with_label(String::from("Hostname or address"))
.with_borders(
Borders::TOP | Borders::RIGHT | Borders::LEFT,
BorderType::Plain,
Color::Reset,
)
.build(),
)),
);
self.view.mount(
super::COMPONENT_INPUT_SSH_USERNAME,
Box::new(Input::new(
PropsBuilder::default()
.with_texts(TextParts::new(Some(String::from("Username")), None))
.with_borders(Borders::BOTTOM | Borders::RIGHT | Borders::LEFT)
InputPropsBuilder::default()
.with_label(String::from("Username"))
.with_borders(
Borders::ALL | Borders::RIGHT | Borders::LEFT,
BorderType::Plain,
Color::Reset,
)
.build(),
)),
);
@@ -478,18 +482,19 @@ impl SetupActivity {
pub(super) fn mount_quit(&mut self) {
self.view.mount(
super::COMPONENT_RADIO_QUIT,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::LightRed)
.bold()
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightRed)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightRed)
.with_options(
Some(String::from("Exit setup?")),
Some(vec![
TextSpan::from("Save"),
TextSpan::from("Don't save"),
TextSpan::from("Cancel"),
]),
))
vec![
String::from("Save"),
String::from("Don't save"),
String::from("Cancel"),
],
)
.build(),
)),
);
@@ -510,14 +515,15 @@ impl SetupActivity {
pub(super) fn mount_save_popup(&mut self) {
self.view.mount(
super::COMPONENT_RADIO_SAVE,
Box::new(RadioGroup::new(
PropsBuilder::default()
.with_foreground(Color::LightYellow)
.bold()
.with_texts(TextParts::new(
Box::new(Radio::new(
RadioPropsBuilder::default()
.with_color(Color::LightYellow)
.with_inverted_color(Color::Black)
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightYellow)
.with_options(
Some(String::from("Save changes?")),
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
))
vec![String::from("Yes"), String::from("No")],
)
.build(),
)),
);
@@ -539,8 +545,9 @@ impl SetupActivity {
self.view.mount(
super::COMPONENT_TEXT_HELP,
Box::new(Table::new(
PropsBuilder::default()
.with_texts(TextParts::table(
TablePropsBuilder::default()
.with_borders(Borders::ALL, BorderType::Rounded, Color::White)
.with_table(
Some(String::from("Help")),
TableBuilder::default()
.add_col(
@@ -615,7 +622,7 @@ impl SetupActivity {
)
.add_col(TextSpan::from(" Save configuration"))
.build(),
))
)
.build(),
)),
);
@@ -636,77 +643,59 @@ impl SetupActivity {
pub(super) fn load_input_values(&mut self) {
if let Some(cli) = self.context.as_mut().unwrap().config_client.as_mut() {
// Text editor
if let Some(props) = self
.view
.get_props(super::COMPONENT_INPUT_TEXT_EDITOR)
.as_mut()
{
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_TEXT_EDITOR) {
let text_editor: String =
String::from(cli.get_text_editor().as_path().to_string_lossy());
let props = props.with_value(PropValue::Str(text_editor)).build();
let props = InputPropsBuilder::from(props)
.with_value(text_editor)
.build();
let _ = self.view.update(super::COMPONENT_INPUT_TEXT_EDITOR, props);
}
// Protocol
if let Some(props) = self
.view
.get_props(super::COMPONENT_RADIO_DEFAULT_PROTOCOL)
.as_mut()
{
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_DEFAULT_PROTOCOL) {
let protocol: usize = match cli.get_default_protocol() {
FileTransferProtocol::Sftp => 0,
FileTransferProtocol::Scp => 1,
FileTransferProtocol::Ftp(false) => 2,
FileTransferProtocol::Ftp(true) => 3,
};
let props = props.with_value(PropValue::Unsigned(protocol)).build();
let props = RadioPropsBuilder::from(props).with_value(protocol).build();
let _ = self
.view
.update(super::COMPONENT_RADIO_DEFAULT_PROTOCOL, props);
}
// Hidden files
if let Some(props) = self
.view
.get_props(super::COMPONENT_RADIO_HIDDEN_FILES)
.as_mut()
{
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_HIDDEN_FILES) {
let hidden: usize = match cli.get_show_hidden_files() {
true => 0,
false => 1,
};
let props = props.with_value(PropValue::Unsigned(hidden)).build();
let props = RadioPropsBuilder::from(props).with_value(hidden).build();
let _ = self.view.update(super::COMPONENT_RADIO_HIDDEN_FILES, props);
}
// Updates
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_UPDATES).as_mut() {
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_UPDATES) {
let updates: usize = match cli.get_check_for_updates() {
true => 0,
false => 1,
};
let props = props.with_value(PropValue::Unsigned(updates)).build();
let props = RadioPropsBuilder::from(props).with_value(updates).build();
let _ = self.view.update(super::COMPONENT_RADIO_UPDATES, props);
}
// Group dirs
if let Some(props) = self
.view
.get_props(super::COMPONENT_RADIO_GROUP_DIRS)
.as_mut()
{
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_GROUP_DIRS) {
let dirs: usize = match cli.get_group_dirs() {
Some(GroupDirs::First) => 0,
Some(GroupDirs::Last) => 1,
None => 2,
};
let props = props.with_value(PropValue::Unsigned(dirs)).build();
let props = RadioPropsBuilder::from(props).with_value(dirs).build();
let _ = self.view.update(super::COMPONENT_RADIO_GROUP_DIRS, props);
}
// File Fmt
if let Some(props) = self
.view
.get_props(super::COMPONENT_INPUT_FILE_FMT)
.as_mut()
{
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_FILE_FMT) {
let file_fmt: String = cli.get_file_fmt().unwrap_or_default();
let props = props.with_value(PropValue::Str(file_fmt)).build();
let props = InputPropsBuilder::from(props).with_value(file_fmt).build();
let _ = self.view.update(super::COMPONENT_INPUT_FILE_FMT, props);
}
}
@@ -718,12 +707,12 @@ impl SetupActivity {
pub(super) fn collect_input_values(&mut self) {
if let Some(cli) = self.context.as_mut().unwrap().config_client.as_mut() {
if let Some(Payload::Text(editor)) =
self.view.get_value(super::COMPONENT_INPUT_TEXT_EDITOR)
self.view.get_state(super::COMPONENT_INPUT_TEXT_EDITOR)
{
cli.set_text_editor(PathBuf::from(editor.as_str()));
}
if let Some(Payload::Unsigned(protocol)) =
self.view.get_value(super::COMPONENT_RADIO_DEFAULT_PROTOCOL)
self.view.get_state(super::COMPONENT_RADIO_DEFAULT_PROTOCOL)
{
let protocol: FileTransferProtocol = match protocol {
1 => FileTransferProtocol::Scp,
@@ -734,22 +723,22 @@ impl SetupActivity {
cli.set_default_protocol(protocol);
}
if let Some(Payload::Unsigned(opt)) =
self.view.get_value(super::COMPONENT_RADIO_HIDDEN_FILES)
self.view.get_state(super::COMPONENT_RADIO_HIDDEN_FILES)
{
let show: bool = matches!(opt, 0);
cli.set_show_hidden_files(show);
}
if let Some(Payload::Unsigned(opt)) =
self.view.get_value(super::COMPONENT_RADIO_UPDATES)
self.view.get_state(super::COMPONENT_RADIO_UPDATES)
{
let check: bool = matches!(opt, 0);
cli.set_check_for_updates(check);
}
if let Some(Payload::Text(fmt)) = self.view.get_value(super::COMPONENT_INPUT_FILE_FMT) {
if let Some(Payload::Text(fmt)) = self.view.get_state(super::COMPONENT_INPUT_FILE_FMT) {
cli.set_file_fmt(fmt);
}
if let Some(Payload::Unsigned(opt)) =
self.view.get_value(super::COMPONENT_RADIO_GROUP_DIRS)
self.view.get_state(super::COMPONENT_RADIO_GROUP_DIRS)
{
let dirs: Option<GroupDirs> = match opt {
0 => Some(GroupDirs::First),
@@ -767,17 +756,17 @@ impl SetupActivity {
pub(super) fn reload_ssh_keys(&mut self) {
if let Some(cli) = self.context.as_ref().unwrap().config_client.as_ref() {
// get props
if let Some(props) = self.view.get_props(super::COMPONENT_LIST_SSH_KEYS).as_mut() {
if let Some(props) = self.view.get_props(super::COMPONENT_LIST_SSH_KEYS) {
// Create texts
let keys: Vec<TextSpan> = cli
let keys: Vec<String> = cli
.iter_ssh_keys()
.map(|x| {
let (addr, username, _) = cli.get_ssh_key(x).ok().unwrap().unwrap();
TextSpan::from(format!("{} at {}", addr, username).as_str())
format!("{} at {}", addr, username)
})
.collect();
let props = props
.with_texts(TextParts::new(Some(String::from("SSH Keys")), Some(keys)))
let props = BookmarkListPropsBuilder::from(props)
.with_bookmarks(Some(String::from("SSH Keys")), keys)
.build();
self.view.update(super::COMPONENT_LIST_SSH_KEYS, props);
}