mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
Working on auth activity view
This commit is contained in:
@@ -54,6 +54,7 @@ type DialogCallback = fn(&mut AuthActivity);
|
|||||||
|
|
||||||
// -- components
|
// -- components
|
||||||
const COMPONENT_TEXT_HEADER: &str = "TEXT_HEADER";
|
const COMPONENT_TEXT_HEADER: &str = "TEXT_HEADER";
|
||||||
|
const COMPONENT_TEXT_NEW_VERSION: &str = "TEXT_NEW_VERSION";
|
||||||
const COMPONENT_TEXT_FOOTER: &str = "TEXT_FOOTER";
|
const COMPONENT_TEXT_FOOTER: &str = "TEXT_FOOTER";
|
||||||
const COMPONENT_TEXT_HELP: &str = "TEXT_HELP";
|
const COMPONENT_TEXT_HELP: &str = "TEXT_HELP";
|
||||||
const COMPONENT_TEXT_ERROR: &str = "TEXT_ERROR";
|
const COMPONENT_TEXT_ERROR: &str = "TEXT_ERROR";
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
// locals
|
// locals
|
||||||
use super::{
|
use super::{
|
||||||
AuthActivity, FileTransferProtocol, InputEvent, COMPONENT_BOOKMARKS_LIST, COMPONENT_INPUT_ADDR,
|
AuthActivity, FileTransferProtocol, COMPONENT_BOOKMARKS_LIST, COMPONENT_INPUT_ADDR,
|
||||||
COMPONENT_INPUT_BOOKMARK_NAME, COMPONENT_INPUT_PASSWORD, COMPONENT_INPUT_PORT,
|
COMPONENT_INPUT_BOOKMARK_NAME, COMPONENT_INPUT_PASSWORD, COMPONENT_INPUT_PORT,
|
||||||
COMPONENT_INPUT_USERNAME, COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK,
|
COMPONENT_INPUT_USERNAME, COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK,
|
||||||
COMPONENT_RADIO_BOOKMARK_DEL_RECENT, COMPONENT_RADIO_BOOKMARK_SAVE_PWD,
|
COMPONENT_RADIO_BOOKMARK_DEL_RECENT, COMPONENT_RADIO_BOOKMARK_SAVE_PWD,
|
||||||
@@ -91,7 +91,6 @@ const MSG_KEY_CTRL_S: Msg = Msg::OnKey(KeyEvent {
|
|||||||
// -- update
|
// -- update
|
||||||
|
|
||||||
impl AuthActivity {
|
impl AuthActivity {
|
||||||
|
|
||||||
/// ### update
|
/// ### update
|
||||||
///
|
///
|
||||||
/// Update auth activity model based on msg
|
/// Update auth activity model based on msg
|
||||||
@@ -182,39 +181,17 @@ impl AuthActivity {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
// <DEL | 'E'>
|
// <DEL | 'E'>
|
||||||
(COMPONENT_BOOKMARKS_LIST, &MSG_KEY_DEL) | (COMPONENT_BOOKMARKS_LIST, &MSG_KEY_CHAR_E) => {
|
(COMPONENT_BOOKMARKS_LIST, &MSG_KEY_DEL)
|
||||||
|
| (COMPONENT_BOOKMARKS_LIST, &MSG_KEY_CHAR_E) => {
|
||||||
// Show delete popup
|
// Show delete popup
|
||||||
match self
|
self.mount_bookmark_del_dialog();
|
||||||
.view
|
None
|
||||||
.get_props(COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK)
|
|
||||||
.as_mut()
|
|
||||||
{
|
|
||||||
None => None,
|
|
||||||
Some(props) => {
|
|
||||||
let msg = self.view.update(
|
|
||||||
COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK,
|
|
||||||
props.visible().build(),
|
|
||||||
);
|
|
||||||
self.update(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
(COMPONENT_RECENTS_LIST, &MSG_KEY_DEL) | (COMPONENT_RECENTS_LIST, &MSG_KEY_CHAR_E) => {
|
(COMPONENT_RECENTS_LIST, &MSG_KEY_DEL)
|
||||||
|
| (COMPONENT_RECENTS_LIST, &MSG_KEY_CHAR_E) => {
|
||||||
// Show delete popup
|
// Show delete popup
|
||||||
match self
|
self.mount_recent_del_dialog();
|
||||||
.view
|
None
|
||||||
.get_props(COMPONENT_RADIO_BOOKMARK_DEL_RECENT)
|
|
||||||
.as_mut()
|
|
||||||
{
|
|
||||||
None => None,
|
|
||||||
Some(props) => {
|
|
||||||
let msg = self.view.update(
|
|
||||||
COMPONENT_RADIO_BOOKMARK_DEL_RECENT,
|
|
||||||
props.visible().build(),
|
|
||||||
);
|
|
||||||
self.update(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Bookmark radio
|
// Bookmark radio
|
||||||
// Del bookmarks
|
// Del bookmarks
|
||||||
@@ -222,52 +199,65 @@ impl AuthActivity {
|
|||||||
COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK,
|
COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK,
|
||||||
Msg::OnSubmit(Payload::Unsigned(index)),
|
Msg::OnSubmit(Payload::Unsigned(index)),
|
||||||
) => {
|
) => {
|
||||||
// Delete bookmark
|
// hide bookmark delete
|
||||||
self.del_bookmark(*index);
|
self.umount_bookmark_del_dialog();
|
||||||
// TODO: view bookmarks
|
// Index must be 0 => YES
|
||||||
// Hide bookmark del
|
match *index {
|
||||||
if let Some(props) = self
|
0 => {
|
||||||
.view
|
// Get selected bookmark
|
||||||
.get_props(COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK)
|
match self.view.get_value(COMPONENT_BOOKMARKS_LIST) {
|
||||||
.as_mut()
|
Some(Payload::Unsigned(index)) => {
|
||||||
{
|
// Delete bookmark
|
||||||
let msg = self.view.update(
|
self.del_bookmark(index);
|
||||||
COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK,
|
// TODO: view bookmarks
|
||||||
props.hidden().build(),
|
// Update bookmarks
|
||||||
);
|
match self.view.get_props(COMPONENT_BOOKMARKS_LIST).as_mut() {
|
||||||
let _ = self.update(msg);
|
None => None,
|
||||||
}
|
Some(props) => {
|
||||||
// Update bookmarks
|
let msg = self
|
||||||
match self.view.get_props(COMPONENT_BOOKMARKS_LIST).as_mut() {
|
.view
|
||||||
None => None,
|
.update(COMPONENT_BOOKMARKS_LIST, props.with_texts(
|
||||||
Some(props) => {
|
TextParts::new(Some(String::from("Bookmarks")), Some(self.view_bookmarks()))
|
||||||
let msg = self.view.update(COMPONENT_BOOKMARKS_LIST, props.build()); // TODO: set rows
|
).build()); // TODO: set rows
|
||||||
self.update(msg)
|
self.update(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(COMPONENT_RADIO_BOOKMARK_DEL_RECENT, Msg::OnSubmit(Payload::Unsigned(index))) => {
|
(COMPONENT_RADIO_BOOKMARK_DEL_RECENT, Msg::OnSubmit(Payload::Unsigned(index))) => {
|
||||||
// Delete recent
|
// hide bookmark delete
|
||||||
self.del_recent(*index);
|
self.umount_recent_del_dialog();
|
||||||
// TODO: view bookmarks
|
// Index must be 0 => YES
|
||||||
// Hide bookmark del
|
match *index {
|
||||||
if let Some(props) = self
|
0 => {
|
||||||
.view
|
// Get selected bookmark
|
||||||
.get_props(COMPONENT_RADIO_BOOKMARK_DEL_RECENT)
|
match self.view.get_value(COMPONENT_RECENTS_LIST) {
|
||||||
.as_mut()
|
Some(Payload::Unsigned(index)) => {
|
||||||
{
|
// Delete recent
|
||||||
let msg = self
|
self.del_recent(index);
|
||||||
.view
|
// TODO: view recents
|
||||||
.update(COMPONENT_RADIO_BOOKMARK_DEL_RECENT, props.hidden().build());
|
// Update bookmarks
|
||||||
let _ = self.update(msg);
|
match self.view.get_props(COMPONENT_RECENTS_LIST).as_mut() {
|
||||||
}
|
None => None,
|
||||||
// Update bookmarks
|
Some(props) => {
|
||||||
match self.view.get_props(COMPONENT_RECENTS_LIST).as_mut() {
|
let msg = self
|
||||||
None => None,
|
.view
|
||||||
Some(props) => {
|
.update(COMPONENT_RECENTS_LIST, props.with_texts(
|
||||||
let msg = self.view.update(COMPONENT_RECENTS_LIST, props.build()); // TODO: set rows
|
TextParts::new(Some(String::from("Recent connections")), Some(self.view_recent_connections()))
|
||||||
self.update(msg)
|
).build()); // TODO: set rows
|
||||||
|
self.update(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// <ESC> hide tab
|
// <ESC> hide tab
|
||||||
@@ -306,27 +296,13 @@ impl AuthActivity {
|
|||||||
// Help
|
// Help
|
||||||
(_, &MSG_KEY_CTRL_H) => {
|
(_, &MSG_KEY_CTRL_H) => {
|
||||||
// Show help
|
// Show help
|
||||||
match self.view.get_props(COMPONENT_TEXT_HELP).as_mut() {
|
self.mount_help();
|
||||||
Some(props) => {
|
None
|
||||||
let msg = self
|
|
||||||
.view
|
|
||||||
.update(COMPONENT_TEXT_HELP, props.visible().build());
|
|
||||||
self.update(msg)
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
(COMPONENT_TEXT_HELP, &MSG_KEY_ENTER) | (COMPONENT_TEXT_HELP, &MSG_KEY_ESC) => {
|
(COMPONENT_TEXT_HELP, &MSG_KEY_ENTER) | (COMPONENT_TEXT_HELP, &MSG_KEY_ESC) => {
|
||||||
// Hide text help
|
// Hide text help
|
||||||
match self.view.get_props(COMPONENT_TEXT_HELP).as_mut() {
|
self.umount_help();
|
||||||
None => None,
|
None
|
||||||
Some(props) => {
|
|
||||||
let msg = self
|
|
||||||
.view
|
|
||||||
.update(COMPONENT_TEXT_HELP, props.hidden().build());
|
|
||||||
self.update(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Enter setup
|
// Enter setup
|
||||||
(_, &MSG_KEY_CTRL_C) => {
|
(_, &MSG_KEY_CTRL_C) => {
|
||||||
@@ -336,23 +312,7 @@ impl AuthActivity {
|
|||||||
// Save bookmark; show popup
|
// Save bookmark; show popup
|
||||||
(_, &MSG_KEY_CTRL_S) => {
|
(_, &MSG_KEY_CTRL_S) => {
|
||||||
// Show popup
|
// Show popup
|
||||||
if let Some(props) = self
|
self.mount_bookmark_save_dialog();
|
||||||
.view
|
|
||||||
.get_props(COMPONENT_RADIO_BOOKMARK_SAVE_PWD)
|
|
||||||
.as_mut()
|
|
||||||
{
|
|
||||||
let msg = self
|
|
||||||
.view
|
|
||||||
.update(COMPONENT_RADIO_BOOKMARK_SAVE_PWD, props.visible().build());
|
|
||||||
let _ = self.update(msg);
|
|
||||||
}
|
|
||||||
if let Some(props) = self.view.get_props(COMPONENT_INPUT_BOOKMARK_NAME).as_mut()
|
|
||||||
{
|
|
||||||
let msg = self
|
|
||||||
.view
|
|
||||||
.update(COMPONENT_INPUT_BOOKMARK_NAME, props.visible().build());
|
|
||||||
let _ = self.update(msg);
|
|
||||||
}
|
|
||||||
// Give focus to bookmark name
|
// Give focus to bookmark name
|
||||||
self.view.active(COMPONENT_INPUT_BOOKMARK_NAME);
|
self.view.active(COMPONENT_INPUT_BOOKMARK_NAME);
|
||||||
None
|
None
|
||||||
@@ -385,47 +345,21 @@ impl AuthActivity {
|
|||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
// TODO: save bookmark
|
// TODO: save bookmark
|
||||||
// Hide popup
|
// Umount popup
|
||||||
if let Some(props) = self
|
self.umount_bookmark_save_dialog();
|
||||||
.view
|
|
||||||
.get_props(COMPONENT_RADIO_BOOKMARK_SAVE_PWD)
|
|
||||||
.as_mut()
|
|
||||||
{
|
|
||||||
let msg = self
|
|
||||||
.view
|
|
||||||
.update(COMPONENT_RADIO_BOOKMARK_SAVE_PWD, props.hidden().build());
|
|
||||||
let _ = self.update(msg);
|
|
||||||
}
|
|
||||||
if let Some(props) = self.view.get_props(COMPONENT_INPUT_BOOKMARK_NAME).as_mut()
|
|
||||||
{
|
|
||||||
let msg = self
|
|
||||||
.view
|
|
||||||
.update(COMPONENT_INPUT_BOOKMARK_NAME, props.hidden().build());
|
|
||||||
let _ = self.update(msg);
|
|
||||||
}
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
// Hide save bookmark
|
// Hide save bookmark
|
||||||
(COMPONENT_INPUT_BOOKMARK_NAME, &MSG_KEY_ESC)
|
(COMPONENT_INPUT_BOOKMARK_NAME, &MSG_KEY_ESC)
|
||||||
| (COMPONENT_RADIO_BOOKMARK_SAVE_PWD, &MSG_KEY_ESC) => {
|
| (COMPONENT_RADIO_BOOKMARK_SAVE_PWD, &MSG_KEY_ESC) => {
|
||||||
// Hide popup
|
// Umount popup
|
||||||
if let Some(props) = self
|
self.umount_bookmark_save_dialog();
|
||||||
.view
|
None
|
||||||
.get_props(COMPONENT_RADIO_BOOKMARK_SAVE_PWD)
|
}
|
||||||
.as_mut()
|
// Error message
|
||||||
{
|
(COMPONENT_TEXT_ERROR, &MSG_KEY_ENTER) => {
|
||||||
let msg = self
|
// Umount text error
|
||||||
.view
|
self.umount_error();
|
||||||
.update(COMPONENT_RADIO_BOOKMARK_SAVE_PWD, props.hidden().build());
|
|
||||||
let _ = self.update(msg);
|
|
||||||
}
|
|
||||||
if let Some(props) = self.view.get_props(COMPONENT_INPUT_BOOKMARK_NAME).as_mut()
|
|
||||||
{
|
|
||||||
let msg = self
|
|
||||||
.view
|
|
||||||
.update(COMPONENT_INPUT_BOOKMARK_NAME, props.hidden().build());
|
|
||||||
let _ = self.update(msg);
|
|
||||||
}
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
// On submit on any unhandled (connect)
|
// On submit on any unhandled (connect)
|
||||||
@@ -436,21 +370,7 @@ impl AuthActivity {
|
|||||||
Some(Payload::Text(addr)) => addr,
|
Some(Payload::Text(addr)) => addr,
|
||||||
_ => {
|
_ => {
|
||||||
// Show error
|
// Show error
|
||||||
if let Some(props) = self.view.get_props(COMPONENT_TEXT_ERROR).as_mut()
|
self.mount_error("Invalid address!");
|
||||||
{
|
|
||||||
let msg = self.view.update(
|
|
||||||
COMPONENT_TEXT_ERROR,
|
|
||||||
props
|
|
||||||
.visible()
|
|
||||||
.with_texts(TextParts::new(
|
|
||||||
None,
|
|
||||||
Some(vec![TextSpan::from("Invalid address!")]),
|
|
||||||
))
|
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
return self.update(msg);
|
|
||||||
}
|
|
||||||
// Return None
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -458,20 +378,7 @@ impl AuthActivity {
|
|||||||
Some(Payload::Unsigned(p)) => p as u16,
|
Some(Payload::Unsigned(p)) => p as u16,
|
||||||
_ => {
|
_ => {
|
||||||
// Show error
|
// Show error
|
||||||
if let Some(props) = self.view.get_props(COMPONENT_TEXT_ERROR).as_mut()
|
self.mount_error("Invalid port number!");
|
||||||
{
|
|
||||||
let msg = self.view.update(
|
|
||||||
COMPONENT_TEXT_ERROR,
|
|
||||||
props
|
|
||||||
.visible()
|
|
||||||
.with_texts(TextParts::new(
|
|
||||||
None,
|
|
||||||
Some(vec![TextSpan::from("Invalid port number!")]),
|
|
||||||
))
|
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
return self.update(msg);
|
|
||||||
}
|
|
||||||
// Return None
|
// Return None
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ use crate::ui::layout::components::{
|
|||||||
bookmark_list::BookmarkList, input::Input, radio_group::RadioGroup, table::Table, text::Text,
|
bookmark_list::BookmarkList, input::Input, radio_group::RadioGroup, table::Table, text::Text,
|
||||||
};
|
};
|
||||||
use crate::ui::layout::props::{
|
use crate::ui::layout::props::{
|
||||||
PropValue, Props, PropsBuilder, TextParts, TextSpan, TextSpanBuilder,
|
InputType, PropValue, Props, PropsBuilder, TableBuilder, TextParts, TextSpan, TextSpanBuilder,
|
||||||
};
|
};
|
||||||
use crate::utils::fmt::align_text_center;
|
use crate::utils::fmt::align_text_center;
|
||||||
// Ext
|
// Ext
|
||||||
@@ -37,7 +37,7 @@ use std::string::ToString;
|
|||||||
use tui::{
|
use tui::{
|
||||||
layout::{Constraint, Corner, Direction, Layout, Rect},
|
layout::{Constraint, Corner, Direction, Layout, Rect},
|
||||||
style::{Color, Modifier, Style},
|
style::{Color, Modifier, Style},
|
||||||
widgets::{Block, BorderType, Borders, Clear, List, ListItem, ListState, Paragraph, Tabs},
|
widgets::{Block, BorderType, Borders, Clear, List, ListItem, ListState, Paragraph, Tabs, Widget},
|
||||||
};
|
};
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ impl AuthActivity {
|
|||||||
/// ### init
|
/// ### init
|
||||||
///
|
///
|
||||||
/// Initialize view, mounting all startup components inside the view
|
/// Initialize view, mounting all startup components inside the view
|
||||||
pub fn init(&mut self) {
|
pub(super) fn init(&mut self) {
|
||||||
// Header
|
// Header
|
||||||
self.view.mount(super::COMPONENT_TEXT_HEADER, Box::new(
|
self.view.mount(super::COMPONENT_TEXT_HEADER, Box::new(
|
||||||
Text::new(
|
Text::new(
|
||||||
@@ -55,26 +55,394 @@ impl AuthActivity {
|
|||||||
)
|
)
|
||||||
));
|
));
|
||||||
// Footer
|
// Footer
|
||||||
self.view.mount(super::COMPONENT_TEXT_FOOTER, Box::new(
|
self.view.mount(
|
||||||
Text::new(
|
super::COMPONENT_TEXT_FOOTER,
|
||||||
PropsBuilder::default().with_foreground(Color::White).with_texts(
|
Box::new(Text::new(
|
||||||
TextParts::new(None, Some(vec![
|
PropsBuilder::default()
|
||||||
TextSpanBuilder::new("Press ").bold().build(),
|
.with_foreground(Color::White)
|
||||||
TextSpanBuilder::new("<CTRL+H>").bold().with_foreground(Color::Cyan).build(),
|
.with_texts(TextParts::new(
|
||||||
TextSpanBuilder::new(" to show keybindings; ").bold().build(),
|
None,
|
||||||
TextSpanBuilder::new("<CTRL+C>").bold().with_foreground(Color::Cyan).build(),
|
Some(vec![
|
||||||
TextSpanBuilder::new(" to enter setup").bold().build(),
|
TextSpanBuilder::new("Press ").bold().build(),
|
||||||
]))
|
TextSpanBuilder::new("<CTRL+H>")
|
||||||
).build()
|
.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(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Address
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_INPUT_ADDR,
|
||||||
|
Box::new(Input::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_foreground(Color::Yellow)
|
||||||
|
.with_texts(TextParts::new(Some(String::from("Remote address")), None))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Port
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_INPUT_PORT,
|
||||||
|
Box::new(Input::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_foreground(Color::LightCyan)
|
||||||
|
.with_texts(TextParts::new(Some(String::from("Port number")), None))
|
||||||
|
.with_input(InputType::Number)
|
||||||
|
.with_input_len(5)
|
||||||
|
.with_value(PropValue::Unsigned(22))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Protocol
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_RADIO_PROTOCOL,
|
||||||
|
Box::new(RadioGroup::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_foreground(Color::LightGreen)
|
||||||
|
.with_texts(TextParts::new(
|
||||||
|
Some(String::from("Protocol")),
|
||||||
|
Some(vec![
|
||||||
|
TextSpan::from("SFTP"),
|
||||||
|
TextSpan::from("SCP"),
|
||||||
|
TextSpan::from("FTP"),
|
||||||
|
TextSpan::from("FTPS"),
|
||||||
|
]),
|
||||||
|
))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Username
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_INPUT_USERNAME,
|
||||||
|
Box::new(Input::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_foreground(Color::LightMagenta)
|
||||||
|
.with_texts(TextParts::new(Some(String::from("Username")), None))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Password
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_INPUT_PASSWORD,
|
||||||
|
Box::new(Input::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_foreground(Color::LightBlue)
|
||||||
|
.with_texts(TextParts::new(Some(String::from("Password")), None))
|
||||||
|
.with_input(InputType::Password)
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Version notice
|
||||||
|
if let Some(version) = self.new_version.as_ref() {
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_TEXT_NEW_VERSION,
|
||||||
|
Box::new(Text::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_foreground(Color::Yellow)
|
||||||
|
.with_texts(TextParts::new(None, Some(vec![format!("TermSCP {} is now available! Download it from <https://github.com/veeso/termscp/releases/latest>", version)])))
|
||||||
|
.bold()
|
||||||
|
.build()
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### view
|
/// ### view
|
||||||
///
|
///
|
||||||
/// Display view on canvas
|
/// Display view on canvas
|
||||||
pub fn view(&mut self) {
|
pub(super) fn view(&mut self) {
|
||||||
|
let mut ctx: Context = self.context.take().unwrap();
|
||||||
|
let _ = ctx.terminal.draw(|f| {
|
||||||
|
// Prepare chunks
|
||||||
|
let chunks = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.margin(1)
|
||||||
|
.constraints(
|
||||||
|
[
|
||||||
|
Constraint::Percentage(70), // Auth Form
|
||||||
|
Constraint::Percentage(30), // Bookmarks
|
||||||
|
]
|
||||||
|
.as_ref(),
|
||||||
|
)
|
||||||
|
.split(f.size());
|
||||||
|
// Create explorer chunks
|
||||||
|
let auth_chunks = Layout::default()
|
||||||
|
.constraints(
|
||||||
|
[
|
||||||
|
Constraint::Length(5),
|
||||||
|
Constraint::Length(1), // Version
|
||||||
|
Constraint::Length(3),
|
||||||
|
Constraint::Length(3),
|
||||||
|
Constraint::Length(3),
|
||||||
|
Constraint::Length(3),
|
||||||
|
Constraint::Length(3),
|
||||||
|
Constraint::Length(3),
|
||||||
|
]
|
||||||
|
.as_ref(),
|
||||||
|
)
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.split(chunks[0]);
|
||||||
|
// Create bookmark chunks
|
||||||
|
let bookmark_chunks = Layout::default()
|
||||||
|
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.split(chunks[1]);
|
||||||
|
// Get focus holder
|
||||||
|
let focus: Option<String> = self.view.who_has_focus();
|
||||||
|
// Render
|
||||||
|
// Header
|
||||||
|
if let Some(render) = self.view.render(super::COMPONENT_TEXT_HEADER).as_ref() {
|
||||||
|
f.render_widget(render.widget, auth_chunks[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- partials
|
||||||
|
|
||||||
|
/// ### view_bookmarks
|
||||||
|
///
|
||||||
|
/// Make text span from bookmarks
|
||||||
|
pub(super) fn view_bookmarks(&self) -> Vec<TextSpan> {
|
||||||
|
self.bookmarks_list
|
||||||
|
.iter()
|
||||||
|
.map(|x| TextSpan::from(x.as_str()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### view_recent_connections
|
||||||
|
///
|
||||||
|
/// View recent connections
|
||||||
|
pub(super) fn view_recent_connections(&self) -> Vec<TextSpan> {
|
||||||
|
self.recents_list
|
||||||
|
.iter()
|
||||||
|
.map(|x| TextSpan::from(x.as_str()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- mount
|
||||||
|
|
||||||
|
/// ### mount_error
|
||||||
|
///
|
||||||
|
/// Mount error box
|
||||||
|
pub(super) fn mount_error(&mut self, text: &str) {
|
||||||
|
// Mount
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_TEXT_ERROR,
|
||||||
|
Box::new(Text::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_foreground(Color::Red)
|
||||||
|
.bold()
|
||||||
|
.with_texts(TextParts::new(None, Some(vec![TextSpan::from(text)])))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Give focus to error
|
||||||
|
self.view.active(super::COMPONENT_TEXT_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### umount_error
|
||||||
|
///
|
||||||
|
/// Umount error message
|
||||||
|
pub(super) fn umount_error(&mut self) {
|
||||||
|
self.view.umount(super::COMPONENT_TEXT_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### mount_bookmark_del_dialog
|
||||||
|
///
|
||||||
|
/// Mount bookmark delete dialog
|
||||||
|
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_texts(TextParts::new(
|
||||||
|
Some(String::from("Delete bookmark?")),
|
||||||
|
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
|
||||||
|
))
|
||||||
|
.with_value(PropValue::Unsigned(1))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Active
|
||||||
|
self.view
|
||||||
|
.active(super::COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### umount_bookmark_del_dialog
|
||||||
|
///
|
||||||
|
/// umount delete bookmark dialog
|
||||||
|
pub(super) fn umount_bookmark_del_dialog(&mut self) {
|
||||||
|
self.view
|
||||||
|
.umount(super::COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### mount_bookmark_del_dialog
|
||||||
|
///
|
||||||
|
/// Mount recent delete dialog
|
||||||
|
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_texts(TextParts::new(
|
||||||
|
Some(String::from("Delete bookmark?")),
|
||||||
|
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
|
||||||
|
))
|
||||||
|
.with_value(PropValue::Unsigned(1))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Active
|
||||||
|
self.view.active(super::COMPONENT_RADIO_BOOKMARK_DEL_RECENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### umount_recent_del_dialog
|
||||||
|
///
|
||||||
|
/// umount delete recent dialog
|
||||||
|
pub(super) fn umount_recent_del_dialog(&mut self) {
|
||||||
|
self.view.umount(super::COMPONENT_RADIO_BOOKMARK_DEL_RECENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### mount_bookmark_save_dialog
|
||||||
|
///
|
||||||
|
/// Mount bookmark save dialog
|
||||||
|
pub(super) fn mount_bookmark_save_dialog(&mut self) {
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_INPUT_BOOKMARK_NAME,
|
||||||
|
Box::new(Input::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_texts(TextParts::new(
|
||||||
|
Some(String::from("Save bookmark as...")),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_RADIO_BOOKMARK_SAVE_PWD,
|
||||||
|
Box::new(RadioGroup::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_foreground(Color::Red)
|
||||||
|
.with_texts(TextParts::new(
|
||||||
|
Some(String::from("Save password?")),
|
||||||
|
Some(vec![TextSpan::from("Yes"), TextSpan::from("No")]),
|
||||||
|
))
|
||||||
|
.with_value(PropValue::Unsigned(1))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Give focus to input bookmark name
|
||||||
|
self.view.active(super::COMPONENT_INPUT_BOOKMARK_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### umount_bookmark_save_dialog
|
||||||
|
///
|
||||||
|
/// Umount bookmark save dialog
|
||||||
|
pub(super) fn umount_bookmark_save_dialog(&mut self) {
|
||||||
|
self.view.umount(super::COMPONENT_RADIO_BOOKMARK_SAVE_PWD);
|
||||||
|
self.view.umount(super::COMPONENT_INPUT_BOOKMARK_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### mount_help
|
||||||
|
///
|
||||||
|
/// Mount help
|
||||||
|
pub(super) fn mount_help(&mut self) {
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_TEXT_HELP,
|
||||||
|
Box::new(Table::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_texts(TextParts::table(
|
||||||
|
Some(String::from("Help")),
|
||||||
|
TableBuilder::default()
|
||||||
|
.add_col(
|
||||||
|
TextSpanBuilder::new("<ESC>")
|
||||||
|
.bold()
|
||||||
|
.with_foreground(Color::Cyan)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.add_col(TextSpan::from(" Quit TermSCP"))
|
||||||
|
.add_row()
|
||||||
|
.add_col(
|
||||||
|
TextSpanBuilder::new("<TAB>")
|
||||||
|
.bold()
|
||||||
|
.with_foreground(Color::Cyan)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.add_col(TextSpan::from(" Switch from form and bookmarks"))
|
||||||
|
.add_row()
|
||||||
|
.add_col(
|
||||||
|
TextSpanBuilder::new("<RIGHT/LEFT>")
|
||||||
|
.bold()
|
||||||
|
.with_foreground(Color::Cyan)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.add_col(TextSpan::from(" Switch bookmark tab"))
|
||||||
|
.add_row()
|
||||||
|
.add_col(
|
||||||
|
TextSpanBuilder::new("<UP/DOWN>")
|
||||||
|
.bold()
|
||||||
|
.with_foreground(Color::Cyan)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.add_col(TextSpan::from(" Move up/down in current tab"))
|
||||||
|
.add_row()
|
||||||
|
.add_col(
|
||||||
|
TextSpanBuilder::new("<ENTER>")
|
||||||
|
.bold()
|
||||||
|
.with_foreground(Color::Cyan)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.add_col(TextSpan::from(" Connect/Load bookmark"))
|
||||||
|
.add_row()
|
||||||
|
.add_col(
|
||||||
|
TextSpanBuilder::new("<DEL|E>")
|
||||||
|
.bold()
|
||||||
|
.with_foreground(Color::Cyan)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.add_col(TextSpan::from(" Delete selected bookmark"))
|
||||||
|
.add_row()
|
||||||
|
.add_col(
|
||||||
|
TextSpanBuilder::new("<CTRL+C>")
|
||||||
|
.bold()
|
||||||
|
.with_foreground(Color::Cyan)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.add_col(TextSpan::from(" Enter setup"))
|
||||||
|
.add_row()
|
||||||
|
.add_col(
|
||||||
|
TextSpanBuilder::new("<CTRL+S>")
|
||||||
|
.bold()
|
||||||
|
.with_foreground(Color::Cyan)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.add_col(TextSpan::from(" Save bookmark"))
|
||||||
|
.build(),
|
||||||
|
))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Active help
|
||||||
|
self.view.active(super::COMPONENT_TEXT_HELP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### umount_help
|
||||||
|
///
|
||||||
|
/// Umount help
|
||||||
|
pub(super) fn umount_help(&mut self) {
|
||||||
|
self.view.umount(super::COMPONENT_TEXT_HELP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user