From 235eb5415e7acfc62d0414a7e6833e58f83e05eb Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 6 Sep 2022 19:08:45 +0800 Subject: [PATCH 1/3] update file transfer and adjust icon size --- .../lib/desktop/pages/file_manager_page.dart | 51 ++++++++++++------- flutter/lib/models/file_model.dart | 8 +-- flutter/lib/models/model.dart | 15 ++++-- src/client.rs | 1 + src/client/io_loop.rs | 31 +---------- src/flutter_ffi.rs | 2 +- src/ui_session_interface.rs | 26 ++++++++++ 7 files changed, 76 insertions(+), 58 deletions(-) diff --git a/flutter/lib/desktop/pages/file_manager_page.dart b/flutter/lib/desktop/pages/file_manager_page.dart index b13f40a5f..be0fedc5c 100644 --- a/flutter/lib/desktop/pages/file_manager_page.dart +++ b/flutter/lib/desktop/pages/file_manager_page.dart @@ -59,8 +59,11 @@ class _FileManagerPageState extends State super.initState(); _ffi = FFI(); _ffi.connect(widget.id, isFileTransfer: true); + WidgetsBinding.instance.addPostFrameCallback((_) { + _ffi.dialogManager + .showLoading(translate('Connecting...'), onCancel: closeConnection); + }); Get.put(_ffi, tag: 'ft_${widget.id}'); - // _ffi.ffiModel.updateEventListener(widget.id); if (!Platform.isLinux) { Wakelock.enable(); } @@ -117,7 +120,8 @@ class _FileManagerPageState extends State Widget menu({bool isLocal = false}) { return PopupMenuButton( - icon: Icon(Icons.more_vert), + icon: const Icon(Icons.more_vert), + splashRadius: 20, itemBuilder: (context) { return [ PopupMenuItem( @@ -413,6 +417,7 @@ class _FileManagerPageState extends State /// watch transfer status Widget statusList() { return PreferredSize( + preferredSize: const Size(200, double.infinity), child: Container( margin: const EdgeInsets.only(top: 16.0, bottom: 16.0, right: 16.0), padding: const EdgeInsets.all(8.0), @@ -429,8 +434,8 @@ class _FileManagerPageState extends State children: [ Transform.rotate( angle: item.isRemote ? pi : 0, - child: Icon(Icons.send)), - SizedBox( + child: const Icon(Icons.send)), + const SizedBox( width: 16.0, ), Expanded( @@ -441,7 +446,7 @@ class _FileManagerPageState extends State Tooltip( message: item.jobName, child: Text( - '${item.jobName}', + item.jobName, maxLines: 1, overflow: TextOverflow.ellipsis, )), @@ -455,7 +460,7 @@ class _FileManagerPageState extends State offstage: item.state != JobState.inProgress, child: Text( - '${readableFileSize(item.speed) + "/s"} ')), + '${"${readableFileSize(item.speed)}/s"} ')), Offstage( offstage: item.totalSize <= 0, child: Text( @@ -475,10 +480,12 @@ class _FileManagerPageState extends State onPressed: () { model.resumeJob(item.id); }, - icon: Icon(Icons.restart_alt_rounded)), + splashRadius: 20, + icon: const Icon(Icons.restart_alt_rounded)), ), IconButton( - icon: Icon(Icons.delete), + icon: const Icon(Icons.delete), + splashRadius: 20, onPressed: () { model.jobTable.removeAt(index); model.cancelJob(item.id); @@ -500,8 +507,7 @@ class _FileManagerPageState extends State itemCount: model.jobTable.length, ), ), - ), - preferredSize: Size(200, double.infinity)); + )); } goBack({bool? isLocal}) { @@ -551,12 +557,15 @@ class _FileManagerPageState extends State Row( children: [ IconButton( - onPressed: () { - model.goHome(isLocal: isLocal); - }, - icon: Icon(Icons.home_outlined)), + onPressed: () { + model.goHome(isLocal: isLocal); + }, + icon: const Icon(Icons.home_outlined), + splashRadius: 20, + ), IconButton( - icon: Icon(Icons.arrow_upward), + icon: const Icon(Icons.arrow_upward), + splashRadius: 20, onPressed: () { goBack(isLocal: isLocal); }, @@ -622,13 +631,15 @@ class _FileManagerPageState extends State ), )) ], - child: Icon(Icons.search), + splashRadius: 20, + child: const Icon(Icons.search), ), IconButton( onPressed: () { model.refresh(isLocal: isLocal); }, - icon: Icon(Icons.refresh)), + splashRadius: 20, + icon: const Icon(Icons.refresh)), ], ), Row( @@ -686,6 +697,7 @@ class _FileManagerPageState extends State ); }); }, + splashRadius: 20, icon: const Icon(Icons.create_new_folder_outlined)), IconButton( onPressed: () async { @@ -695,7 +707,8 @@ class _FileManagerPageState extends State await (model.removeAction(items, isLocal: isLocal)); items.clear(); }, - icon: Icon(Icons.delete_forever_outlined)), + splashRadius: 20, + icon: const Icon(Icons.delete_forever_outlined)), ], ), ), @@ -707,7 +720,7 @@ class _FileManagerPageState extends State }, icon: Transform.rotate( angle: isLocal ? 0 : pi, - child: Icon( + child: const Icon( Icons.send, ), ), diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index dedca5efa..3246346be 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -360,9 +360,9 @@ class FileModel extends ChangeNotifier { Future refresh({bool? isLocal}) async { if (isDesktop) { isLocal = isLocal ?? _isLocal; - await isLocal - ? openDirectory(currentLocalDir.path, isLocal: isLocal) - : openDirectory(currentRemoteDir.path, isLocal: isLocal); + isLocal + ? await openDirectory(currentLocalDir.path, isLocal: isLocal) + : await openDirectory(currentRemoteDir.path, isLocal: isLocal); } else { await openDirectory(currentDir.path); } @@ -393,7 +393,7 @@ class FileModel extends ChangeNotifier { } notifyListeners(); } catch (e) { - debugPrint("Failed to openDirectory ${path} :$e"); + debugPrint("Failed to openDirectory $path: $e"); } } diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 1993145e7..7d8cdc203 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -326,8 +326,8 @@ class FfiModel with ChangeNotifier { await bind.sessionGetOption(id: peerId, arg: "touch-mode") != ''; } - if (evt['is_file_transfer'] == "true") { - // TODO is file transfer + if (parent.target != null && + parent.target!.connType == ConnType.fileTransfer) { parent.target?.fileModel.onReady(); } else { _pi.displays = []; @@ -916,6 +916,8 @@ extension ToString on MouseButtons { } } +enum ConnType { defaultConn, fileTransfer, portForward, rdp } + /// FFI class for communicating with the Rust core. class FFI { var id = ""; @@ -924,6 +926,7 @@ class FFI { var alt = false; var command = false; var version = ""; + var connType = ConnType.defaultConn; /// dialogManager use late to ensure init after main page binding [globalKey] late final dialogManager = OverlayDialogManager(); @@ -1055,9 +1058,11 @@ class FFI { double tabBarHeight = 0.0}) { assert(!(isFileTransfer && isPortForward), "more than one connect type"); if (isFileTransfer) { - id = 'ft_${id}'; + connType = ConnType.fileTransfer; + id = 'ft_$id'; } else if (isPortForward) { - id = 'pf_${id}'; + connType = ConnType.portForward; + id = 'pf_$id'; } else { chatModel.resetClientMode(); canvasModel.id = id; @@ -1086,7 +1091,7 @@ class FFI { // every instance will bind a stream this.id = id; if (isFileTransfer) { - this.fileModel.initFileFetcher(); + fileModel.initFileFetcher(); } } diff --git a/src/client.rs b/src/client.rs index 32c0003fd..a4a864846 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1665,6 +1665,7 @@ pub async fn handle_login_from_ui( /// Interface for client to send data and commands. #[async_trait] pub trait Interface: Send + Clone + 'static + Sized { + /// Send message data to remote peer. fn send(&self, data: Data); fn msgbox(&self, msgtype: &str, title: &str, text: &str); fn handle_login_error(&mut self, err: &str) -> bool; diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 552fea7a8..f33f740a3 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -269,33 +269,6 @@ impl Remote { Some(tx) } - // TODO - fn load_last_jobs(&mut self) { - self.handler.clear_all_jobs(); - let pc = self.handler.load_config(); - if pc.transfer.write_jobs.is_empty() && pc.transfer.read_jobs.is_empty() { - // no last jobs - return; - } - // TODO: can add a confirm dialog - let mut cnt = 1; - for job_str in pc.transfer.read_jobs.iter() { - if !job_str.is_empty() { - self.handler.load_last_job(cnt, job_str); - cnt += 1; - log::info!("restore read_job: {:?}", job_str); - } - } - for job_str in pc.transfer.write_jobs.iter() { - if !job_str.is_empty() { - self.handler.load_last_job(cnt, job_str); - cnt += 1; - log::info!("restore write_job: {:?}", job_str); - } - } - self.handler.update_transfer_list(); - } - async fn handle_msg_from_ui(&mut self, data: Data, peer: &mut Stream) -> bool { match data { Data::Close => { @@ -768,7 +741,7 @@ impl Remote { } if self.handler.is_file_transfer() { - self.load_last_jobs(); + self.handler.load_last_jobs(); } } _ => {} @@ -827,7 +800,7 @@ impl Remote { &entries, fd.path, false, - fd.id > 0, + false, ); if let Some(job) = fs::get_job(fd.id, &mut self.write_jobs) { log::info!("job set_files: {:?}", entries); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 5da94c3c1..ef2aaeaa1 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -366,7 +366,7 @@ pub fn session_get_platform(id: String, is_remote: bool) -> String { pub fn session_load_last_transfer_jobs(id: String) { if let Some(session) = SESSIONS.read().unwrap().get(&id) { - // return session.load_last_jobs(); + return session.load_last_jobs(); } else { // a tip for flutter dev eprintln!( diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 717963561..f1444f4c3 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -532,6 +532,32 @@ impl Session { pub fn close(&self) { self.send(Data::Close); } + + pub fn load_last_jobs(&self) { + self.clear_all_jobs(); + let pc = self.load_config(); + if pc.transfer.write_jobs.is_empty() && pc.transfer.read_jobs.is_empty() { + // no last jobs + return; + } + // TODO: can add a confirm dialog + let mut cnt = 1; + for job_str in pc.transfer.read_jobs.iter() { + if !job_str.is_empty() { + self.load_last_job(cnt, job_str); + cnt += 1; + log::info!("restore read_job: {:?}", job_str); + } + } + for job_str in pc.transfer.write_jobs.iter() { + if !job_str.is_empty() { + self.load_last_job(cnt, job_str); + cnt += 1; + log::info!("restore write_job: {:?}", job_str); + } + } + self.update_transfer_list(); + } } pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default { From 05218ecabcdd019f1db42e082f800da727e7ebd5 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 6 Sep 2022 19:56:35 +0800 Subject: [PATCH 2/3] fix sciter confirm_delete_files bug --- src/client/io_loop.rs | 1 - src/ui/remote.rs | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index f33f740a3..cc2ca1dae 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -452,7 +452,6 @@ impl Remote { file_num, job.files[i].name.clone(), ); - self.handler.confirm_delete_files(id, file_num); } } } diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 08430110c..c6a36f5c6 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -709,18 +709,15 @@ impl SciterSession { } pub fn make_fd(id: i32, entries: &Vec, only_count: bool) -> Value { - log::debug!("make_fd"); let mut m = Value::map(); m.set_item("id", id); let mut a = Value::array(0); let mut n: u64 = 0; for entry in entries { - log::debug!("for"); n += entry.size; if only_count { continue; } - log::debug!("for1"); let mut e = Value::map(); e.set_item("name", entry.name.to_owned()); let tmp = entry.entry_type.value(); @@ -734,6 +731,5 @@ pub fn make_fd(id: i32, entries: &Vec, only_count: bool) -> Value { } m.set_item("num_entries", entries.len() as i32); m.set_item("total_size", n as f64); - log::debug!("make_fd end"); m } From 468527775eb24e184400e3a6a850adeadeded992 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 6 Sep 2022 21:10:59 +0800 Subject: [PATCH 3/3] fix sciter can't update connect status bug --- src/ui.rs | 96 +----------------------------------------------- src/ui/index.tis | 1 + 2 files changed, 2 insertions(+), 95 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index b8b136c45..96cf21f20 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -87,7 +87,7 @@ pub fn start(args: &mut [String]) { } #[cfg(windows)] if args.len() > 0 && args[0] == "--tray" { - let options = check_connect_status(false).1; + let options = crate::ui_interface::check_connect_status(false).1; crate::tray::start_tray(options); return; } @@ -664,79 +664,6 @@ pub fn check_zombie(childs: Childs) { } } -// notice: avoiding create ipc connecton repeatly, -// because windows named pipe has serious memory leak issue. -#[tokio::main(flavor = "current_thread")] -async fn check_connect_status_( - reconnect: bool, - status: Arc>, - options: Arc>>, - rx: mpsc::UnboundedReceiver, - password: Arc>, -) { - let mut key_confirmed = false; - let mut rx = rx; - let mut mouse_time = 0; - let mut id = "".to_owned(); - loop { - if let Ok(mut c) = ipc::connect(1000, "").await { - let mut timer = time::interval(time::Duration::from_secs(1)); - loop { - tokio::select! { - res = c.next() => { - match res { - Err(err) => { - log::error!("ipc connection closed: {}", err); - break; - } - Ok(Some(ipc::Data::MouseMoveTime(v))) => { - mouse_time = v; - status.lock().unwrap().2 = v; - } - Ok(Some(ipc::Data::Options(Some(v)))) => { - *options.lock().unwrap() = v - } - Ok(Some(ipc::Data::Config((name, Some(value))))) => { - if name == "id" { - id = value; - } else if name == "temporary-password" { - *password.lock().unwrap() = value; - } - } - Ok(Some(ipc::Data::OnlineStatus(Some((mut x, c))))) => { - if x > 0 { - x = 1 - } - key_confirmed = c; - *status.lock().unwrap() = (x as _, key_confirmed, mouse_time, id.clone()); - } - _ => {} - } - } - Some(data) = rx.recv() => { - allow_err!(c.send(&data).await); - } - _ = timer.tick() => { - c.send(&ipc::Data::OnlineStatus(None)).await.ok(); - c.send(&ipc::Data::Options(None)).await.ok(); - c.send(&ipc::Data::Config(("id".to_owned(), None))).await.ok(); - c.send(&ipc::Data::Config(("temporary-password".to_owned(), None))).await.ok(); - } - } - } - } - if !reconnect { - options - .lock() - .unwrap() - .insert("ipc-closed".to_owned(), "Y".to_owned()); - break; - } - *status.lock().unwrap() = (-1, key_confirmed, mouse_time, id.clone()); - sleep(1.).await; - } -} - #[cfg(not(target_os = "linux"))] fn get_sound_inputs() -> Vec { let mut out = Vec::new(); @@ -763,27 +690,6 @@ fn get_sound_inputs() -> Vec { .collect() } -fn check_connect_status( - reconnect: bool, -) -> ( - Arc>, - Arc>>, - mpsc::UnboundedSender, - Arc>, -) { - let status = Arc::new(Mutex::new((0, false, 0, "".to_owned()))); - let options = Arc::new(Mutex::new(Config::get_options())); - let cloned = status.clone(); - let cloned_options = options.clone(); - let (tx, rx) = mpsc::unbounded_channel::(); - let password = Arc::new(Mutex::new(String::default())); - let cloned_password = password.clone(); - std::thread::spawn(move || { - check_connect_status_(reconnect, cloned, cloned_options, rx, cloned_password) - }); - (status, options, tx, password) -} - const INVALID_FORMAT: &'static str = "Invalid format"; const UNKNOWN_ERROR: &'static str = "Unknown error"; diff --git a/src/ui/index.tis b/src/ui/index.tis index 256f00c44..d0a9d29a8 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -1055,6 +1055,7 @@ function showSettings() { } function checkConnectStatus() { + handler.check_mouse_time(); // trigger connection status updater self.timer(1s, function() { var tmp = !!handler.get_option("stop-service"); if (tmp != service_stopped) {