mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
Context as Activity member; on_destroy context is released
This commit is contained in:
@@ -51,7 +51,7 @@ pub enum NextActivity {
|
|||||||
///
|
///
|
||||||
/// The activity manager takes care of running activities and handling them until the application has ended
|
/// The activity manager takes care of running activities and handling them until the application has ended
|
||||||
pub struct ActivityManager {
|
pub struct ActivityManager {
|
||||||
context: Context,
|
context: Option<Context>,
|
||||||
ftparams: Option<FileTransferParams>,
|
ftparams: Option<FileTransferParams>,
|
||||||
interval: Duration,
|
interval: Duration,
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ impl ActivityManager {
|
|||||||
};
|
};
|
||||||
let ctx: Context = Context::new(host);
|
let ctx: Context = Context::new(host);
|
||||||
Ok(ActivityManager {
|
Ok(ActivityManager {
|
||||||
context: ctx,
|
context: Some(ctx),
|
||||||
ftparams: None,
|
ftparams: None,
|
||||||
interval: interval,
|
interval: interval,
|
||||||
})
|
})
|
||||||
@@ -127,11 +127,16 @@ impl ActivityManager {
|
|||||||
let mut activity: AuthActivity = AuthActivity::new();
|
let mut activity: AuthActivity = AuthActivity::new();
|
||||||
// Prepare result
|
// Prepare result
|
||||||
let result: Option<NextActivity>;
|
let result: Option<NextActivity>;
|
||||||
|
// Get context
|
||||||
|
let ctx: Context = match self.context.take() {
|
||||||
|
Some(ctx) => ctx,
|
||||||
|
None => return None
|
||||||
|
};
|
||||||
// Create activity
|
// Create activity
|
||||||
activity.on_create(&mut self.context);
|
activity.on_create(ctx);
|
||||||
loop {
|
loop {
|
||||||
// Draw activity
|
// Draw activity
|
||||||
activity.on_draw(&mut self.context);
|
activity.on_draw();
|
||||||
// Check if has to be terminated
|
// Check if has to be terminated
|
||||||
if activity.quit {
|
if activity.quit {
|
||||||
// Quit activities
|
// Quit activities
|
||||||
@@ -161,7 +166,7 @@ impl ActivityManager {
|
|||||||
sleep(self.interval);
|
sleep(self.interval);
|
||||||
}
|
}
|
||||||
// Destroy activity
|
// Destroy activity
|
||||||
activity.on_destroy(&mut self.context);
|
self.context = activity.on_destroy();
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,11 +184,16 @@ impl ActivityManager {
|
|||||||
FileTransferActivity::new(self.ftparams.take().unwrap());
|
FileTransferActivity::new(self.ftparams.take().unwrap());
|
||||||
// Prepare result
|
// Prepare result
|
||||||
let result: Option<NextActivity>;
|
let result: Option<NextActivity>;
|
||||||
|
// Get context
|
||||||
|
let ctx: Context = match self.context.take() {
|
||||||
|
Some(ctx) => ctx,
|
||||||
|
None => return None
|
||||||
|
};
|
||||||
// Create activity
|
// Create activity
|
||||||
activity.on_create(&mut self.context);
|
activity.on_create(ctx);
|
||||||
loop {
|
loop {
|
||||||
// Draw activity
|
// Draw activity
|
||||||
activity.on_draw(&mut self.context);
|
activity.on_draw();
|
||||||
// Check if has to be terminated
|
// Check if has to be terminated
|
||||||
if activity.quit {
|
if activity.quit {
|
||||||
// Quit activities
|
// Quit activities
|
||||||
@@ -199,7 +209,7 @@ impl ActivityManager {
|
|||||||
sleep(self.interval);
|
sleep(self.interval);
|
||||||
}
|
}
|
||||||
// Destroy activity
|
// Destroy activity
|
||||||
activity.on_destroy(&mut self.context);
|
self.context = activity.on_destroy();
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ pub struct AuthActivity {
|
|||||||
pub password: String,
|
pub password: String,
|
||||||
pub submit: bool, // becomes true after user has submitted fields
|
pub submit: bool, // becomes true after user has submitted fields
|
||||||
pub quit: bool, // Becomes true if user has pressed esc
|
pub quit: bool, // Becomes true if user has pressed esc
|
||||||
|
context: Option<Context>,
|
||||||
selected_field: InputField,
|
selected_field: InputField,
|
||||||
input_mode: InputMode,
|
input_mode: InputMode,
|
||||||
popup_message: Option<String>,
|
popup_message: Option<String>,
|
||||||
@@ -96,6 +97,7 @@ impl AuthActivity {
|
|||||||
password: String::new(),
|
password: String::new(),
|
||||||
submit: false,
|
submit: false,
|
||||||
quit: false,
|
quit: false,
|
||||||
|
context: None,
|
||||||
selected_field: InputField::Address,
|
selected_field: InputField::Address,
|
||||||
input_mode: InputMode::Text,
|
input_mode: InputMode::Text,
|
||||||
popup_message: None,
|
popup_message: None,
|
||||||
@@ -409,20 +411,27 @@ impl Activity for AuthActivity {
|
|||||||
///
|
///
|
||||||
/// `on_create` is the function which must be called to initialize the activity.
|
/// `on_create` is the function which must be called to initialize the activity.
|
||||||
/// `on_create` must initialize all the data structures used by the activity
|
/// `on_create` must initialize all the data structures used by the activity
|
||||||
fn on_create(&mut self, context: &mut Context) {
|
/// Context is taken from activity manager and will be released only when activity is destroyed
|
||||||
|
fn on_create(&mut self, context: Context) {
|
||||||
|
// Set context
|
||||||
|
self.context = Some(context);
|
||||||
|
// Clear terminal
|
||||||
|
let _ = self.context.as_mut().unwrap().terminal.clear();
|
||||||
// Put raw mode on enabled
|
// Put raw mode on enabled
|
||||||
let _ = enable_raw_mode();
|
let _ = enable_raw_mode();
|
||||||
// Clear terminal
|
|
||||||
let _ = context.terminal.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### on_draw
|
/// ### on_draw
|
||||||
///
|
///
|
||||||
/// `on_draw` is the function which draws the graphical interface.
|
/// `on_draw` is the function which draws the graphical interface.
|
||||||
/// This function must be called at each tick to refresh the interface
|
/// This function must be called at each tick to refresh the interface
|
||||||
fn on_draw(&mut self, context: &mut Context) {
|
fn on_draw(&mut self) {
|
||||||
|
// Context must be something
|
||||||
|
if self.context.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Start catching Input Events
|
// Start catching Input Events
|
||||||
if let Ok(input_events) = context.input_hnd.fetch_events() {
|
if let Ok(input_events) = self.context.as_ref().unwrap().input_hnd.fetch_events() {
|
||||||
// Iterate over input events
|
// Iterate over input events
|
||||||
for event in input_events.iter() {
|
for event in input_events.iter() {
|
||||||
self.handle_input_event(event);
|
self.handle_input_event(event);
|
||||||
@@ -431,7 +440,8 @@ impl Activity for AuthActivity {
|
|||||||
// Determine input mode
|
// Determine input mode
|
||||||
self.input_mode = self.select_input_mode();
|
self.input_mode = self.select_input_mode();
|
||||||
// draw interface
|
// draw interface
|
||||||
let _ = context.terminal.draw(|f| {
|
let mut ctx: Context = self.context.take().unwrap();
|
||||||
|
let _ = ctx.terminal.draw(|f| {
|
||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.margin(2)
|
.margin(2)
|
||||||
@@ -483,16 +493,28 @@ impl Activity for AuthActivity {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Reset ctx
|
||||||
|
self.context = Some(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### on_destroy
|
/// ### on_destroy
|
||||||
///
|
///
|
||||||
/// `on_destroy` is the function which cleans up runtime variables and data before terminating the activity.
|
/// `on_destroy` is the function which cleans up runtime variables and data before terminating the activity.
|
||||||
/// This function must be called once before terminating the activity.
|
/// This function must be called once before terminating the activity.
|
||||||
fn on_destroy(&mut self, context: &mut Context) {
|
/// This function finally releases the context
|
||||||
|
fn on_destroy(&mut self) -> Option<Context> {
|
||||||
// Disable raw mode
|
// Disable raw mode
|
||||||
let _ = disable_raw_mode();
|
let _ = disable_raw_mode();
|
||||||
// Clear terminal
|
if self.context.is_none() {
|
||||||
let _ = context.terminal.clear();
|
return None;
|
||||||
|
}
|
||||||
|
// Clear terminal and return
|
||||||
|
match self.context.take() {
|
||||||
|
Some(mut ctx) => {
|
||||||
|
let _ = ctx.terminal.clear();
|
||||||
|
Some(ctx)
|
||||||
|
},
|
||||||
|
None => None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ use tui::{
|
|||||||
style::{Color, Modifier, Style},
|
style::{Color, Modifier, Style},
|
||||||
terminal::Frame,
|
terminal::Frame,
|
||||||
text::{Span, Spans, Text},
|
text::{Span, Spans, Text},
|
||||||
widgets::{Block, Borders, Clear, Paragraph, Tabs},
|
widgets::{Block, Borders, List, ListItem, Paragraph, Tabs}
|
||||||
};
|
};
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
@@ -59,8 +59,8 @@ use unicode_width::UnicodeWidthStr;
|
|||||||
static mut UPLOAD_PROGRESS: f64 = 0.0; // VERY VERY BAD CODING
|
static mut UPLOAD_PROGRESS: f64 = 0.0; // VERY VERY BAD CODING
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
type DialogCallback = fn(&mut FileTransferActivity, &mut Context);
|
type DialogCallback = fn(&mut FileTransferActivity);
|
||||||
type OnInputSubmitCallback = fn(&mut FileTransferActivity, &mut Context, String);
|
type OnInputSubmitCallback = fn(&mut FileTransferActivity, String);
|
||||||
|
|
||||||
/// ### FileTransferParams
|
/// ### FileTransferParams
|
||||||
///
|
///
|
||||||
@@ -200,6 +200,7 @@ impl LogRecord {
|
|||||||
pub struct FileTransferActivity {
|
pub struct FileTransferActivity {
|
||||||
pub disconnected: bool, // Has disconnected from remote?
|
pub disconnected: bool, // Has disconnected from remote?
|
||||||
pub quit: bool, // Has quit term scp?
|
pub quit: bool, // Has quit term scp?
|
||||||
|
context: Option<Context>, // Context holder
|
||||||
params: FileTransferParams, // FT connection params
|
params: FileTransferParams, // FT connection params
|
||||||
client: Box<dyn FileTransfer>, // File transfer client
|
client: Box<dyn FileTransfer>, // File transfer client
|
||||||
local: FileExplorer, // Local File explorer state
|
local: FileExplorer, // Local File explorer state
|
||||||
@@ -223,6 +224,7 @@ impl FileTransferActivity {
|
|||||||
FileTransferActivity {
|
FileTransferActivity {
|
||||||
disconnected: false,
|
disconnected: false,
|
||||||
quit: false,
|
quit: false,
|
||||||
|
context: None,
|
||||||
params: params,
|
params: params,
|
||||||
client: match protocol {
|
client: match protocol {
|
||||||
FileTransferProtocol::Sftp => Box::new(SftpFileTransfer::new()),
|
FileTransferProtocol::Sftp => Box::new(SftpFileTransfer::new()),
|
||||||
@@ -269,7 +271,7 @@ impl FileTransferActivity {
|
|||||||
/// ### disconnect
|
/// ### disconnect
|
||||||
///
|
///
|
||||||
/// disconnect from remote
|
/// disconnect from remote
|
||||||
fn disconnect(&mut self, context: &mut Context) {
|
fn disconnect(&mut self) {
|
||||||
// Show popup disconnecting
|
// Show popup disconnecting
|
||||||
self.input_mode = InputMode::Popup(PopupType::Alert(
|
self.input_mode = InputMode::Popup(PopupType::Alert(
|
||||||
Color::Red,
|
Color::Red,
|
||||||
@@ -307,7 +309,7 @@ impl FileTransferActivity {
|
|||||||
/// Send fs entry to remote.
|
/// Send fs entry to remote.
|
||||||
/// If dst_name is Some, entry will be saved with a different name.
|
/// If dst_name is Some, entry will be saved with a different name.
|
||||||
/// If entry is a directory, this applies to directory only
|
/// If entry is a directory, this applies to directory only
|
||||||
fn filetransfer_send(&mut self, ctx: &mut Context, entry: &FsEntry, dst_name: Option<String>) {
|
fn filetransfer_send(&mut self, entry: &FsEntry, dst_name: Option<String>) {
|
||||||
// Write popup
|
// Write popup
|
||||||
let file_name: String = match entry {
|
let file_name: String = match entry {
|
||||||
FsEntry::Directory(dir) => dir.name.clone(),
|
FsEntry::Directory(dir) => dir.name.clone(),
|
||||||
@@ -334,7 +336,7 @@ impl FileTransferActivity {
|
|||||||
FsEntry::File(file) => {
|
FsEntry::File(file) => {
|
||||||
// Upload file
|
// Upload file
|
||||||
// Try to open local file
|
// Try to open local file
|
||||||
match ctx.local.open_file_read(file.abs_path.as_path()) {
|
match self.context.as_ref().unwrap().local.open_file_read(file.abs_path.as_path()) {
|
||||||
Ok(mut f) => {
|
Ok(mut f) => {
|
||||||
match self
|
match self
|
||||||
.client
|
.client
|
||||||
@@ -383,12 +385,12 @@ impl FileTransferActivity {
|
|||||||
format!("Created directory \"{}\"", dir.abs_path.display()).as_ref(),
|
format!("Created directory \"{}\"", dir.abs_path.display()).as_ref(),
|
||||||
);
|
);
|
||||||
// Get files in dir
|
// Get files in dir
|
||||||
match ctx.local.scan_dir(dir.abs_path.as_path()) {
|
match self.context.as_ref().unwrap().local.scan_dir(dir.abs_path.as_path()) {
|
||||||
Ok(entries) => {
|
Ok(entries) => {
|
||||||
// Iterate over files
|
// Iterate over files
|
||||||
for entry in entries.iter() {
|
for entry in entries.iter() {
|
||||||
// Send entry; name is always None after first call
|
// Send entry; name is always None after first call
|
||||||
self.filetransfer_send(ctx, &entry, None);
|
self.filetransfer_send(&entry, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => self.log(
|
Err(err) => self.log(
|
||||||
@@ -423,7 +425,6 @@ impl FileTransferActivity {
|
|||||||
/// If entry is a directory, this applies to directory only
|
/// If entry is a directory, this applies to directory only
|
||||||
fn filetransfer_recv(
|
fn filetransfer_recv(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut Context,
|
|
||||||
entry: &FsEntry,
|
entry: &FsEntry,
|
||||||
local_path: &Path,
|
local_path: &Path,
|
||||||
dst_name: Option<String>,
|
dst_name: Option<String>,
|
||||||
@@ -456,7 +457,7 @@ impl FileTransferActivity {
|
|||||||
};
|
};
|
||||||
local_file_path.push(local_file_name.as_str());
|
local_file_path.push(local_file_name.as_str());
|
||||||
// Try to open local file
|
// Try to open local file
|
||||||
match ctx.local.open_file_write(local_file_path.as_path()) {
|
match self.context.as_ref().unwrap().local.open_file_write(local_file_path.as_path()) {
|
||||||
Ok(mut local_file) => {
|
Ok(mut local_file) => {
|
||||||
// Download file from remote
|
// Download file from remote
|
||||||
match self.client.recv_file(
|
match self.client.recv_file(
|
||||||
@@ -506,7 +507,7 @@ impl FileTransferActivity {
|
|||||||
None => local_dir_path.push(dir.name.as_str()),
|
None => local_dir_path.push(dir.name.as_str()),
|
||||||
}
|
}
|
||||||
// Create directory on local
|
// Create directory on local
|
||||||
match ctx.local.mkdir_ex(local_dir_path.as_path(), true) {
|
match self.context.as_mut().unwrap().local.mkdir_ex(local_dir_path.as_path(), true) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
@@ -520,7 +521,6 @@ impl FileTransferActivity {
|
|||||||
// Receive entry; name is always None after first call
|
// Receive entry; name is always None after first call
|
||||||
// Local path becomes local_dir_path
|
// Local path becomes local_dir_path
|
||||||
self.filetransfer_recv(
|
self.filetransfer_recv(
|
||||||
ctx,
|
|
||||||
&entry,
|
&entry,
|
||||||
local_dir_path.as_path(),
|
local_dir_path.as_path(),
|
||||||
None,
|
None,
|
||||||
@@ -594,11 +594,11 @@ impl FileTransferActivity {
|
|||||||
/// ### handle_input_event
|
/// ### handle_input_event
|
||||||
///
|
///
|
||||||
/// Handle input event based on current input mode
|
/// Handle input event based on current input mode
|
||||||
fn handle_input_event(&mut self, context: &mut Context, ev: &InputEvent) {
|
fn handle_input_event(&mut self, ev: &InputEvent) {
|
||||||
match &self.input_mode {
|
match &self.input_mode {
|
||||||
InputMode::Explorer => self.handle_input_event_mode_explorer(context, ev),
|
InputMode::Explorer => self.handle_input_event_mode_explorer(ev),
|
||||||
InputMode::Popup(ptype) => {
|
InputMode::Popup(ptype) => {
|
||||||
self.handle_input_event_mode_popup(ev, ptype.clone(), context)
|
self.handle_input_event_mode_popup(ev, ptype.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -606,16 +606,16 @@ impl FileTransferActivity {
|
|||||||
/// ### handle_input_event_mode_explorer
|
/// ### handle_input_event_mode_explorer
|
||||||
///
|
///
|
||||||
/// Input event handler for explorer mode
|
/// Input event handler for explorer mode
|
||||||
fn handle_input_event_mode_explorer(&mut self, context: &mut Context, ev: &InputEvent) {
|
fn handle_input_event_mode_explorer(&mut self, ev: &InputEvent) {
|
||||||
// Match input field
|
// Match input field
|
||||||
match self.input_field {
|
match self.input_field {
|
||||||
InputField::Explorer => match self.tab {
|
InputField::Explorer => match self.tab {
|
||||||
// Match current selected tab
|
// Match current selected tab
|
||||||
FileExplorerTab::Local => {
|
FileExplorerTab::Local => {
|
||||||
self.handle_input_event_mode_explorer_tab_local(context, ev)
|
self.handle_input_event_mode_explorer_tab_local(ev)
|
||||||
}
|
}
|
||||||
FileExplorerTab::Remote => {
|
FileExplorerTab::Remote => {
|
||||||
self.handle_input_event_mode_explorer_tab_remote(context, ev)
|
self.handle_input_event_mode_explorer_tab_remote(ev)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
InputField::Logs => self.handle_input_event_mode_explorer_log(ev),
|
InputField::Logs => self.handle_input_event_mode_explorer_log(ev),
|
||||||
@@ -627,7 +627,6 @@ impl FileTransferActivity {
|
|||||||
/// Input event handler for explorer mode when localhost tab is selected
|
/// Input event handler for explorer mode when localhost tab is selected
|
||||||
fn handle_input_event_mode_explorer_tab_local(
|
fn handle_input_event_mode_explorer_tab_local(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: &mut Context,
|
|
||||||
ev: &InputEvent,
|
ev: &InputEvent,
|
||||||
) {
|
) {
|
||||||
// Match events
|
// Match events
|
||||||
@@ -658,9 +657,9 @@ impl FileTransferActivity {
|
|||||||
if let Some(entry) = self.local.files.get(self.local.index) {
|
if let Some(entry) = self.local.files.get(self.local.index) {
|
||||||
if let FsEntry::Directory(dir) = entry {
|
if let FsEntry::Directory(dir) = entry {
|
||||||
// Get current directory
|
// Get current directory
|
||||||
let prev_dir: PathBuf = context.local.pwd();
|
let prev_dir: PathBuf = self.context.as_ref().unwrap().local.pwd();
|
||||||
// Change directory
|
// Change directory
|
||||||
match context.local.change_wrkdir(dir.abs_path.clone()) {
|
match self.context.as_mut().unwrap().local.change_wrkdir(dir.abs_path.clone()) {
|
||||||
Ok(_) => self.local.pushd(prev_dir.as_path()), // Push prev_dir to stack
|
Ok(_) => self.local.pushd(prev_dir.as_path()), // Push prev_dir to stack
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// Report err
|
// Report err
|
||||||
@@ -671,7 +670,7 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update files
|
// Update files
|
||||||
self.local.files = context.local.list_dir();
|
self.local.files = self.context.as_ref().unwrap().local.list_dir();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -681,10 +680,10 @@ impl FileTransferActivity {
|
|||||||
// Till a valid directory is found
|
// Till a valid directory is found
|
||||||
match self.local.popd() {
|
match self.local.popd() {
|
||||||
Some(d) => {
|
Some(d) => {
|
||||||
match context.local.change_wrkdir(d) {
|
match self.context.as_mut().unwrap().local.change_wrkdir(d) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Update files
|
// Update files
|
||||||
self.local.files = context.local.list_dir();
|
self.local.files = self.context.as_ref().unwrap().local.list_dir();
|
||||||
// Break, directory has changed
|
// Break, directory has changed
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -769,7 +768,7 @@ impl FileTransferActivity {
|
|||||||
// Get file at index
|
// Get file at index
|
||||||
if let Some(entry) = files.get(self.local.index) {
|
if let Some(entry) = files.get(self.local.index) {
|
||||||
// Call upload
|
// Call upload
|
||||||
self.filetransfer_send(context, entry, None);
|
self.filetransfer_send(entry, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => { /* Nothing to do */ }
|
_ => { /* Nothing to do */ }
|
||||||
@@ -786,7 +785,6 @@ impl FileTransferActivity {
|
|||||||
/// Input event handler for explorer mode when remote tab is selected
|
/// Input event handler for explorer mode when remote tab is selected
|
||||||
fn handle_input_event_mode_explorer_tab_remote(
|
fn handle_input_event_mode_explorer_tab_remote(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: &mut Context,
|
|
||||||
ev: &InputEvent,
|
ev: &InputEvent,
|
||||||
) {
|
) {
|
||||||
// Match events
|
// Match events
|
||||||
@@ -961,9 +959,8 @@ impl FileTransferActivity {
|
|||||||
if let Some(entry) = files.get(self.remote.index) {
|
if let Some(entry) = files.get(self.remote.index) {
|
||||||
// Call upload
|
// Call upload
|
||||||
self.filetransfer_recv(
|
self.filetransfer_recv(
|
||||||
context,
|
|
||||||
entry,
|
entry,
|
||||||
context.local.pwd().as_path(),
|
self.context.as_ref().unwrap().local.pwd().as_path(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1035,16 +1032,15 @@ impl FileTransferActivity {
|
|||||||
&mut self,
|
&mut self,
|
||||||
ev: &InputEvent,
|
ev: &InputEvent,
|
||||||
popup: PopupType,
|
popup: PopupType,
|
||||||
ctx: &mut Context,
|
|
||||||
) {
|
) {
|
||||||
match popup {
|
match popup {
|
||||||
PopupType::Alert(_, _) => self.handle_input_event_mode_popup_alert(ev),
|
PopupType::Alert(_, _) => self.handle_input_event_mode_popup_alert(ev),
|
||||||
PopupType::Fatal(_) => self.handle_input_event_mode_popup_fatal(ev),
|
PopupType::Fatal(_) => self.handle_input_event_mode_popup_fatal(ev),
|
||||||
PopupType::Input(_, cb) => self.handle_input_event_mode_popup_input(ev, ctx, cb),
|
PopupType::Input(_, cb) => self.handle_input_event_mode_popup_input(ev, cb),
|
||||||
PopupType::Progress(_) => self.handle_input_event_mode_popup_progress(ev),
|
PopupType::Progress(_) => self.handle_input_event_mode_popup_progress(ev),
|
||||||
PopupType::Wait(_) => self.handle_input_event_mode_popup_wait(ev),
|
PopupType::Wait(_) => self.handle_input_event_mode_popup_wait(ev),
|
||||||
PopupType::YesNo(_, yes_cb, no_cb) => {
|
PopupType::YesNo(_, yes_cb, no_cb) => {
|
||||||
self.handle_input_event_mode_popup_yesno(ev, ctx, yes_cb, no_cb)
|
self.handle_input_event_mode_popup_yesno(ev, yes_cb, no_cb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1093,7 +1089,6 @@ impl FileTransferActivity {
|
|||||||
fn handle_input_event_mode_popup_input(
|
fn handle_input_event_mode_popup_input(
|
||||||
&mut self,
|
&mut self,
|
||||||
ev: &InputEvent,
|
ev: &InputEvent,
|
||||||
ctx: &mut Context,
|
|
||||||
cb: OnInputSubmitCallback,
|
cb: OnInputSubmitCallback,
|
||||||
) {
|
) {
|
||||||
// If enter, close popup, otherwise push chars to input
|
// If enter, close popup, otherwise push chars to input
|
||||||
@@ -1115,7 +1110,7 @@ impl FileTransferActivity {
|
|||||||
// Set mode back to explorer BEFORE CALLBACKS!!! Callback can then overwrite this, clever uh?
|
// Set mode back to explorer BEFORE CALLBACKS!!! Callback can then overwrite this, clever uh?
|
||||||
self.input_mode = InputMode::Explorer;
|
self.input_mode = InputMode::Explorer;
|
||||||
// Call cb
|
// Call cb
|
||||||
cb(self, ctx, input_text);
|
cb(self, input_text);
|
||||||
}
|
}
|
||||||
KeyCode::Char(ch) => self.input_txt.push(ch),
|
KeyCode::Char(ch) => self.input_txt.push(ch),
|
||||||
KeyCode::Backspace => {
|
KeyCode::Backspace => {
|
||||||
@@ -1154,7 +1149,6 @@ impl FileTransferActivity {
|
|||||||
fn handle_input_event_mode_popup_yesno(
|
fn handle_input_event_mode_popup_yesno(
|
||||||
&mut self,
|
&mut self,
|
||||||
ev: &InputEvent,
|
ev: &InputEvent,
|
||||||
ctx: &mut Context,
|
|
||||||
yes_cb: DialogCallback,
|
yes_cb: DialogCallback,
|
||||||
no_cb: DialogCallback,
|
no_cb: DialogCallback,
|
||||||
) {
|
) {
|
||||||
@@ -1167,8 +1161,8 @@ impl FileTransferActivity {
|
|||||||
self.input_mode = InputMode::Explorer;
|
self.input_mode = InputMode::Explorer;
|
||||||
// Check if user selected yes or not
|
// Check if user selected yes or not
|
||||||
match self.choice_opt {
|
match self.choice_opt {
|
||||||
DialogYesNoOption::No => no_cb(self, ctx),
|
DialogYesNoOption::No => no_cb(self),
|
||||||
DialogYesNoOption::Yes => yes_cb(self, ctx),
|
DialogYesNoOption::Yes => yes_cb(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Right => self.choice_opt = DialogYesNoOption::No, // Set to NO
|
KeyCode::Right => self.choice_opt = DialogYesNoOption::No, // Set to NO
|
||||||
@@ -1185,20 +1179,20 @@ impl FileTransferActivity {
|
|||||||
/// ### callback_nothing_to_do
|
/// ### callback_nothing_to_do
|
||||||
///
|
///
|
||||||
/// Self titled
|
/// Self titled
|
||||||
fn callback_nothing_to_do(&mut self, _context: &mut Context) {}
|
fn callback_nothing_to_do(&mut self) {}
|
||||||
|
|
||||||
/// ### callback_force_input_mode_to_explorer
|
/// ### callback_force_input_mode_to_explorer
|
||||||
///
|
///
|
||||||
/// force input mode to explorer
|
/// force input mode to explorer
|
||||||
fn callback_force_input_mode_to_explorer(&mut self, _context: &mut Context) {
|
fn callback_force_input_mode_to_explorer(&mut self) {
|
||||||
self.input_mode = InputMode::Explorer;
|
self.input_mode = InputMode::Explorer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### callback_change_directory
|
/// ### callback_change_directory
|
||||||
///
|
///
|
||||||
/// Callback for GOTO command
|
/// Callback for GOTO command
|
||||||
fn callback_change_directory(&mut self, context: &mut Context, input: String) {
|
fn callback_change_directory(&mut self, input: String) {
|
||||||
match context.local.change_wrkdir(PathBuf::from(input.as_str())) {
|
match self.context.as_mut().unwrap().local.change_wrkdir(PathBuf::from(input.as_str())) {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// Report err
|
// Report err
|
||||||
self.input_mode = InputMode::Popup(PopupType::Alert(
|
self.input_mode = InputMode::Popup(PopupType::Alert(
|
||||||
@@ -1206,24 +1200,24 @@ impl FileTransferActivity {
|
|||||||
format!("Could not change working directory: {}", err),
|
format!("Could not change working directory: {}", err),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Ok(_) => self.local.files = context.local.list_dir(), // Update files
|
Ok(_) => self.local.files = self.context.as_ref().unwrap().local.list_dir(), // Update files
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### callback_mkdir
|
/// ### callback_mkdir
|
||||||
///
|
///
|
||||||
/// Callback for MKDIR command (supports both local and remote)
|
/// Callback for MKDIR command (supports both local and remote)
|
||||||
fn callback_mkdir(&mut self, context: &mut Context, input: String) {
|
fn callback_mkdir(&mut self, input: String) {
|
||||||
match self.tab {
|
match self.tab {
|
||||||
FileExplorerTab::Local => {
|
FileExplorerTab::Local => {
|
||||||
match context.local.mkdir(PathBuf::from(input.as_str()).as_path()) {
|
match self.context.as_mut().unwrap().local.mkdir(PathBuf::from(input.as_str()).as_path()) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Reload files
|
// Reload files
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
format!("Created directory \"{}\"", input).as_ref(),
|
format!("Created directory \"{}\"", input).as_ref(),
|
||||||
);
|
);
|
||||||
self.local.files = context.local.list_dir();
|
self.local.files = self.context.as_ref().unwrap().local.list_dir();
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// Report err
|
// Report err
|
||||||
@@ -1267,13 +1261,13 @@ impl FileTransferActivity {
|
|||||||
/// ### callback_rename
|
/// ### callback_rename
|
||||||
///
|
///
|
||||||
/// Callback for RENAME command (supports borth local and remote)
|
/// Callback for RENAME command (supports borth local and remote)
|
||||||
fn callback_rename(&mut self, context: &mut Context, input: String) {
|
fn callback_rename(&mut self, input: String) {
|
||||||
match self.tab {
|
match self.tab {
|
||||||
FileExplorerTab::Local => {
|
FileExplorerTab::Local => {
|
||||||
let mut dst_path: PathBuf = PathBuf::from(input);
|
let mut dst_path: PathBuf = PathBuf::from(input);
|
||||||
// Check if path is relative
|
// Check if path is relative
|
||||||
if dst_path.as_path().is_relative() {
|
if dst_path.as_path().is_relative() {
|
||||||
let mut wrkdir: PathBuf = context.local.pwd();
|
let mut wrkdir: PathBuf = self.context.as_ref().unwrap().local.pwd();
|
||||||
wrkdir.push(dst_path);
|
wrkdir.push(dst_path);
|
||||||
dst_path = wrkdir;
|
dst_path = wrkdir;
|
||||||
}
|
}
|
||||||
@@ -1284,10 +1278,10 @@ impl FileTransferActivity {
|
|||||||
FsEntry::File(file) => file.abs_path.clone(),
|
FsEntry::File(file) => file.abs_path.clone(),
|
||||||
};
|
};
|
||||||
// Rename file or directory and report status as popup
|
// Rename file or directory and report status as popup
|
||||||
match context.local.rename(entry, dst_path.as_path()) {
|
match self.context.as_mut().unwrap().local.rename(entry, dst_path.as_path()) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Reload files
|
// Reload files
|
||||||
self.local.files = context.local.list_dir();
|
self.local.files = self.context.as_ref().unwrap().local.list_dir();
|
||||||
// Log
|
// Log
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
@@ -1329,7 +1323,7 @@ impl FileTransferActivity {
|
|||||||
match self.client.rename(entry, dst_path.as_path()) {
|
match self.client.rename(entry, dst_path.as_path()) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Reload files
|
// Reload files
|
||||||
self.local.files = context.local.list_dir();
|
self.local.files = self.context.as_ref().unwrap().local.list_dir();
|
||||||
// Log
|
// Log
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
@@ -1365,7 +1359,7 @@ impl FileTransferActivity {
|
|||||||
/// ### callback_delete_fsentry
|
/// ### callback_delete_fsentry
|
||||||
///
|
///
|
||||||
/// Delete current selected fsentry in the currently selected TAB
|
/// Delete current selected fsentry in the currently selected TAB
|
||||||
fn callback_delete_fsentry(&mut self, context: &mut Context) {
|
fn callback_delete_fsentry(&mut self) {
|
||||||
// Match current selected tab
|
// Match current selected tab
|
||||||
match self.tab {
|
match self.tab {
|
||||||
FileExplorerTab::Local => {
|
FileExplorerTab::Local => {
|
||||||
@@ -1376,10 +1370,10 @@ impl FileTransferActivity {
|
|||||||
FsEntry::File(file) => file.abs_path.clone(),
|
FsEntry::File(file) => file.abs_path.clone(),
|
||||||
};
|
};
|
||||||
// Delete file or directory and report status as popup
|
// Delete file or directory and report status as popup
|
||||||
match context.local.remove(entry) {
|
match self.context.as_mut().unwrap().local.remove(entry) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Reload files
|
// Reload files
|
||||||
self.local.files = context.local.list_dir();
|
self.local.files = self.context.as_ref().unwrap().local.list_dir();
|
||||||
// Log
|
// Log
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
@@ -1445,14 +1439,14 @@ impl FileTransferActivity {
|
|||||||
///
|
///
|
||||||
/// Call file upload, but save with input as name
|
/// Call file upload, but save with input as name
|
||||||
/// Handled both local and remote tab
|
/// Handled both local and remote tab
|
||||||
fn callback_save_as(&mut self, ctx: &mut Context, input: String) {
|
fn callback_save_as(&mut self, input: String) {
|
||||||
match self.tab {
|
match self.tab {
|
||||||
FileExplorerTab::Local => {
|
FileExplorerTab::Local => {
|
||||||
let files: Vec<FsEntry> = self.local.files.clone();
|
let files: Vec<FsEntry> = self.local.files.clone();
|
||||||
// Get file at index
|
// Get file at index
|
||||||
if let Some(entry) = files.get(self.local.index) {
|
if let Some(entry) = files.get(self.local.index) {
|
||||||
// Call send (upload)
|
// Call send (upload)
|
||||||
self.filetransfer_send(ctx, entry, Some(input));
|
self.filetransfer_send(entry, Some(input));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FileExplorerTab::Remote => {
|
FileExplorerTab::Remote => {
|
||||||
@@ -1460,7 +1454,7 @@ impl FileTransferActivity {
|
|||||||
// Get file at index
|
// Get file at index
|
||||||
if let Some(entry) = files.get(self.remote.index) {
|
if let Some(entry) = files.get(self.remote.index) {
|
||||||
// Call receive (download)
|
// Call receive (download)
|
||||||
self.filetransfer_recv(ctx, entry, ctx.local.pwd().as_path(), Some(input));
|
self.filetransfer_recv(entry, self.context.as_ref().unwrap().local.pwd().as_path(), Some(input));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1483,6 +1477,43 @@ impl FileTransferActivity {
|
|||||||
.style(Style::default().fg(Color::LightYellow).add_modifier(Modifier::BOLD))
|
.style(Style::default().fg(Color::LightYellow).add_modifier(Modifier::BOLD))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// ### draw_log_list
|
||||||
|
///
|
||||||
|
/// Draw log list
|
||||||
|
fn draw_log_list(&self) -> List {
|
||||||
|
let events: Vec<ListItem> = self.log_records
|
||||||
|
.iter()
|
||||||
|
.map(|&(evt, level)| {
|
||||||
|
let s = match level {
|
||||||
|
"CRITICAL" => Style::default().fg(Color::Red),
|
||||||
|
"ERROR" => Style::default().fg(Color::Magenta),
|
||||||
|
"WARNING" => Style::default().fg(Color::Yellow),
|
||||||
|
"INFO" => Style::default().fg(Color::Blue),
|
||||||
|
_ => Style::default(),
|
||||||
|
};
|
||||||
|
let header = Spans::from(vec![
|
||||||
|
Span::styled(format!("{:<9}", level), s),
|
||||||
|
Span::raw(" "),
|
||||||
|
Span::styled(
|
||||||
|
"2020-01-01 10:00:00",
|
||||||
|
Style::default().add_modifier(Modifier::ITALIC),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
let log = Spans::from(vec![Span::raw(evt)]);
|
||||||
|
ListItem::new(vec![
|
||||||
|
Spans::from("-".repeat(chunks[1].width as usize)),
|
||||||
|
header,
|
||||||
|
Spans::from(""),
|
||||||
|
log,
|
||||||
|
])
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let events_list = List::new(events)
|
||||||
|
.block(Block::default().borders(Borders::ALL).title("List"))
|
||||||
|
.start_corner(Corner::BottomLeft);
|
||||||
|
}*/
|
||||||
|
|
||||||
/// ### draw_footer
|
/// ### draw_footer
|
||||||
///
|
///
|
||||||
/// Draw authentication page footer
|
/// Draw authentication page footer
|
||||||
@@ -1577,20 +1608,26 @@ impl Activity for FileTransferActivity {
|
|||||||
///
|
///
|
||||||
/// `on_create` is the function which must be called to initialize the activity.
|
/// `on_create` is the function which must be called to initialize the activity.
|
||||||
/// `on_create` must initialize all the data structures used by the activity
|
/// `on_create` must initialize all the data structures used by the activity
|
||||||
fn on_create(&mut self, context: &mut Context) {
|
fn on_create(&mut self, context: Context) {
|
||||||
|
// Set context
|
||||||
|
self.context = Some(context);
|
||||||
|
// Clear terminal
|
||||||
|
let _ = self.context.as_mut().unwrap().terminal.clear();
|
||||||
// Put raw mode on enabled
|
// Put raw mode on enabled
|
||||||
let _ = enable_raw_mode();
|
let _ = enable_raw_mode();
|
||||||
// Clear terminal
|
|
||||||
let _ = context.terminal.clear();
|
|
||||||
// Get files at current wd
|
// Get files at current wd
|
||||||
self.local.files = context.local.list_dir();
|
self.local.files = self.context.as_ref().unwrap().local.list_dir();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### on_draw
|
/// ### on_draw
|
||||||
///
|
///
|
||||||
/// `on_draw` is the function which draws the graphical interface.
|
/// `on_draw` is the function which draws the graphical interface.
|
||||||
/// This function must be called at each tick to refresh the interface
|
/// This function must be called at each tick to refresh the interface
|
||||||
fn on_draw(&mut self, context: &mut Context) {
|
fn on_draw(&mut self) {
|
||||||
|
// Context must be something
|
||||||
|
if self.context.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Check if connected
|
// Check if connected
|
||||||
if !self.client.is_connected() {
|
if !self.client.is_connected() {
|
||||||
// Set init state to connecting popup
|
// Set init state to connecting popup
|
||||||
@@ -1599,37 +1636,47 @@ impl Activity for FileTransferActivity {
|
|||||||
self.params.address, self.params.port
|
self.params.address, self.params.port
|
||||||
)));
|
)));
|
||||||
// Force ui draw
|
// Force ui draw
|
||||||
let _ = context.terminal.draw(|f| {
|
let mut ctx: Context = self.context.take().unwrap();
|
||||||
|
let _ = ctx.terminal.draw(|f| {
|
||||||
self.draw(f);
|
self.draw(f);
|
||||||
});
|
});
|
||||||
|
self.context = Some(ctx);
|
||||||
// Connect to remote
|
// Connect to remote
|
||||||
self.connect();
|
self.connect();
|
||||||
}
|
}
|
||||||
// Handle input events FIXME: read one or multiple?
|
// Handle input events FIXME: read one or multiple?
|
||||||
if let Ok(event) = context.input_hnd.read_event() {
|
if let Ok(event) = self.context.as_ref().unwrap().input_hnd.read_event() {
|
||||||
// Iterate over input events
|
// Iterate over input events
|
||||||
if let Some(event) = event {
|
if let Some(event) = event {
|
||||||
self.handle_input_event(context, &event);
|
self.handle_input_event(&event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// @! draw interface
|
// @! draw interface
|
||||||
let _ = context.terminal.draw(|f| {
|
let mut ctx: Context = self.context.take().unwrap();
|
||||||
|
let _ = ctx.terminal.draw(|f| {
|
||||||
self.draw(f);
|
self.draw(f);
|
||||||
});
|
});
|
||||||
|
self.context = Some(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### on_destroy
|
/// ### on_destroy
|
||||||
///
|
///
|
||||||
/// `on_destroy` is the function which cleans up runtime variables and data before terminating the activity.
|
/// `on_destroy` is the function which cleans up runtime variables and data before terminating the activity.
|
||||||
/// This function must be called once before terminating the activity.
|
/// This function must be called once before terminating the activity.
|
||||||
fn on_destroy(&mut self, context: &mut Context) {
|
fn on_destroy(&mut self) -> Option<Context> {
|
||||||
// Disable raw mode
|
// Disable raw mode
|
||||||
let _ = disable_raw_mode();
|
let _ = disable_raw_mode();
|
||||||
// Clear terminal
|
|
||||||
let _ = context.terminal.clear();
|
|
||||||
// Disconnect client
|
// Disconnect client
|
||||||
if self.client.is_connected() {
|
if self.client.is_connected() {
|
||||||
let _ = self.client.disconnect();
|
let _ = self.client.disconnect();
|
||||||
}
|
}
|
||||||
|
// Clear terminal and return
|
||||||
|
match self.context.take() {
|
||||||
|
Some(mut ctx) => {
|
||||||
|
let _ = ctx.terminal.clear();
|
||||||
|
Some(ctx)
|
||||||
|
},
|
||||||
|
None => None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,17 +38,19 @@ pub trait Activity {
|
|||||||
///
|
///
|
||||||
/// `on_create` is the function which must be called to initialize the activity.
|
/// `on_create` is the function which must be called to initialize the activity.
|
||||||
/// `on_create` must initialize all the data structures used by the activity
|
/// `on_create` must initialize all the data structures used by the activity
|
||||||
fn on_create(&mut self, context: &mut Context);
|
/// Context is taken from activity manager and will be released only when activity is destroyed
|
||||||
|
fn on_create(&mut self, context: Context);
|
||||||
|
|
||||||
/// ### on_draw
|
/// ### on_draw
|
||||||
///
|
///
|
||||||
/// `on_draw` is the function which draws the graphical interface.
|
/// `on_draw` is the function which draws the graphical interface.
|
||||||
/// This function must be called at each tick to refresh the interface
|
/// This function must be called at each tick to refresh the interface
|
||||||
fn on_draw(&mut self, context: &mut Context);
|
fn on_draw(&mut self);
|
||||||
|
|
||||||
/// ### on_destroy
|
/// ### on_destroy
|
||||||
///
|
///
|
||||||
/// `on_destroy` is the function which cleans up runtime variables and data before terminating the activity.
|
/// `on_destroy` is the function which cleans up runtime variables and data before terminating the activity.
|
||||||
/// This function must be called once before terminating the activity.
|
/// This function must be called once before terminating the activity.
|
||||||
fn on_destroy(&mut self, context: &mut Context);
|
/// This function finally releases the context
|
||||||
|
fn on_destroy(&mut self) -> Option<Context>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user