From ca9ca19fa7a95f17e1768aa228dcd1780260c032 Mon Sep 17 00:00:00 2001 From: 21pages Date: Sat, 8 Oct 2022 20:15:02 +0800 Subject: [PATCH] persist cm chat page if chat unanswered Signed-off-by: 21pages --- flutter/lib/desktop/pages/server_page.dart | 114 ++++++++++++--------- flutter/lib/models/server_model.dart | 86 +++++++--------- src/flutter.rs | 7 +- src/flutter_ffi.rs | 8 ++ src/ipc.rs | 1 + src/lang/cn.rs | 1 + src/lang/cs.rs | 1 + src/lang/da.rs | 1 + src/lang/de.rs | 1 + src/lang/eo.rs | 1 + src/lang/es.rs | 1 + src/lang/fr.rs | 1 + src/lang/hu.rs | 1 + src/lang/id.rs | 1 + src/lang/it.rs | 1 + src/lang/ja.rs | 1 + src/lang/ko.rs | 1 + src/lang/kz.rs | 1 + src/lang/pl.rs | 1 + src/lang/pt_PT.rs | 1 + src/lang/ptbr.rs | 1 + src/lang/ru.rs | 1 + src/lang/sk.rs | 1 + src/lang/template.rs | 1 + src/lang/tr.rs | 1 + src/lang/tw.rs | 1 + src/lang/ua.rs | 5 + src/lang/vn.rs | 1 + src/server/connection.rs | 17 ++- src/ui/cm.rs | 14 ++- src/ui/cm.tis | 72 ++++++++++--- src/ui_cm_interface.rs | 38 +++++-- 32 files changed, 259 insertions(+), 125 deletions(-) diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index 66b9b0350..3710b2932 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -158,40 +158,26 @@ class ConnectionManagerState extends State { ), ); } - - Widget buildTab(Client client) { - return Tab( - child: Row( - children: [ - SizedBox( - width: 80, - child: Text( - client.name, - maxLines: 1, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.center, - )), - ], - ), - ); - } } Widget buildConnectionCard(Client client) { - return Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - key: ValueKey(client.id), - children: [ - _CmHeader(client: client), - client.isFileTransfer ? Offstage() : _PrivilegeBoard(client: client), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: _CmControlPanel(client: client), - )) - ], - ).paddingSymmetric(vertical: 8.0, horizontal: 8.0); + return Consumer( + builder: (context, value, child) => Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + key: ValueKey(client.id), + children: [ + _CmHeader(client: client), + client.isFileTransfer || client.disconnected + ? Offstage() + : _PrivilegeBoard(client: client), + Expanded( + child: Align( + alignment: Alignment.bottomCenter, + child: _CmControlPanel(client: client), + )) + ], + ).paddingSymmetric(vertical: 8.0, horizontal: 8.0)); } class _AppIcon extends StatelessWidget { @@ -249,7 +235,7 @@ class _CmHeaderState extends State<_CmHeader> void initState() { super.initState(); _timer = Timer.periodic(Duration(seconds: 1), (_) { - _time.value = _time.value + 1; + if (!client.disconnected) _time.value = _time.value + 1; }); } @@ -303,7 +289,10 @@ class _CmHeaderState extends State<_CmHeader> FittedBox( child: Row( children: [ - Text(translate("Connected")).marginOnly(right: 8.0), + Text(client.disconnected + ? translate("Disconnected") + : translate("Connected")) + .marginOnly(right: 8.0), Obx(() => Text( formatDurationToTime(Duration(seconds: _time.value)))) ], @@ -311,15 +300,14 @@ class _CmHeaderState extends State<_CmHeader> ], ), ), - Consumer( - builder: (_, model, child) => Offstage( - offstage: !client.authorized || client.isFileTransfer, - child: IconButton( - onPressed: () => checkClickTime(client.id, - () => gFFI.chatModel.toggleCMChatPage(client.id)), - icon: Icon(Icons.message_outlined), - ), - )) + Offstage( + offstage: !client.authorized || client.isFileTransfer, + child: IconButton( + onPressed: () => checkClickTime( + client.id, () => gFFI.chatModel.toggleCMChatPage(client.id)), + icon: Icon(Icons.message_outlined), + ), + ) ], ); } @@ -435,11 +423,11 @@ class _CmControlPanel extends StatelessWidget { @override Widget build(BuildContext context) { - return Consumer(builder: (_, model, child) { - return client.authorized - ? buildAuthorized(context) - : buildUnAuthorized(context); - }); + return client.authorized + ? client.disconnected + ? buildDisconnected(context) + : buildAuthorized(context) + : buildUnAuthorized(context); } buildAuthorized(BuildContext context) { @@ -468,6 +456,31 @@ class _CmControlPanel extends StatelessWidget { ); } + buildDisconnected(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Ink( + width: 200, + height: 40, + decoration: BoxDecoration( + color: MyTheme.accent, borderRadius: BorderRadius.circular(10)), + child: InkWell( + onTap: () => handleClose(context), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + translate("Close"), + style: TextStyle(color: Colors.white), + ), + ], + )), + ) + ], + ); + } + buildUnAuthorized(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, @@ -527,6 +540,13 @@ class _CmControlPanel extends StatelessWidget { final model = Provider.of(context, listen: false); model.sendLoginResponse(client, true); } + + void handleClose(BuildContext context) async { + await bind.cmRemoveDisconnectedConnection(connId: client.id); + if (await bind.cmGetClientsLength() == 0) { + windowManager.close(); + } + } } void checkClickTime(int id, Function() callback) async { diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index 7a94da5ad..decb10e54 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -376,29 +376,29 @@ class ServerModel with ChangeNotifier { } else { _clients[index].authorized = true; } - tabController.add( - TabInfo( - key: client.id.toString(), - label: client.name, - closable: false, - page: Desktop.buildConnectionCard(client)), - authorized: true); - scrollToBottom(); - notifyListeners(); } else { if (_clients.any((c) => c.id == client.id)) { return; } _clients.add(client); - tabController.add(TabInfo( - key: client.id.toString(), - label: client.name, - closable: false, - page: Desktop.buildConnectionCard(client))); - scrollToBottom(); - notifyListeners(); - if (isAndroid) showLoginDialog(client); } + tabController.add( + TabInfo( + key: client.id.toString(), + label: client.name, + closable: false, + page: Desktop.buildConnectionCard(client)), + authorized: client.authorized); + // remove disconnected + final index_disconnected = _clients + .indexWhere((c) => c.disconnected && c.peerId == client.peerId); + if (index_disconnected >= 0) { + _clients.removeAt(index_disconnected); + tabController.remove(index_disconnected); + } + scrollToBottom(); + notifyListeners(); + if (isAndroid && !client.authorized) showLoginDialog(client); } catch (e) { debugPrint("Failed to call loginRequest,error:$e"); } @@ -477,38 +477,19 @@ class ServerModel with ChangeNotifier { } } - void onClientAuthorized(Map evt) { - try { - final client = Client.fromJson(jsonDecode(evt['client'])); - parent.target?.dialogManager.dismissByTag(getLoginDialogTag(client.id)); - final index = _clients.indexWhere((c) => c.id == client.id); - if (index < 0) { - _clients.add(client); - } else { - _clients[index].authorized = true; - } - tabController.add( - TabInfo( - key: client.id.toString(), - label: client.name, - closable: false, - page: Desktop.buildConnectionCard(client)), - authorized: true); - scrollToBottom(); - notifyListeners(); - } catch (e) { - debugPrint("onClientAuthorized:$e"); - } - } - void onClientRemove(Map evt) { try { final id = int.parse(evt['id'] as String); + final close = (evt['close'] as String) == 'true'; if (_clients.any((c) => c.id == id)) { final index = _clients.indexWhere((client) => client.id == id); if (index >= 0) { - _clients.removeAt(index); - tabController.remove(index); + if (close) { + _clients.removeAt(index); + tabController.remove(index); + } else { + _clients[index].disconnected = true; + } } parent.target?.dialogManager.dismissByTag(getLoginDialogTag(id)); parent.target?.invokeMethod("cancel_notification", id); @@ -545,6 +526,7 @@ class Client { bool file = false; bool restart = false; bool recording = false; + bool disconnected = false; Client(this.id, this.authorized, this.isFileTransfer, this.name, this.peerId, this.keyboard, this.clipboard, this.audio); @@ -561,18 +543,20 @@ class Client { file = json['file']; restart = json['restart']; recording = json['recording']; + disconnected = json['disconnected']; } Map toJson() { final Map data = new Map(); - data['id'] = this.id; - data['is_start'] = this.authorized; - data['is_file_transfer'] = this.isFileTransfer; - data['name'] = this.name; - data['peer_id'] = this.peerId; - data['keyboard'] = this.keyboard; - data['clipboard'] = this.clipboard; - data['audio'] = this.audio; + data['id'] = id; + data['is_start'] = authorized; + data['is_file_transfer'] = isFileTransfer; + data['name'] = name; + data['peer_id'] = peerId; + data['keyboard'] = keyboard; + data['clipboard'] = clipboard; + data['audio'] = audio; + data['disconnected'] = disconnected; return data; } } diff --git a/src/flutter.rs b/src/flutter.rs index 755e245fe..bf758e31c 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -368,8 +368,11 @@ pub mod connection_manager { self.push_event("add_connection", vec![("client", &client_json)]); } - fn remove_connection(&self, id: i32) { - self.push_event("on_client_remove", vec![("id", &id.to_string())]); + fn remove_connection(&self, id: i32, close: bool) { + self.push_event( + "on_client_remove", + vec![("id", &id.to_string()), ("close", &close.to_string())], + ); } fn new_message(&self, id: i32, text: String) { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index c1be51498..9ce92aeb2 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -779,6 +779,10 @@ pub fn cm_check_clients_length(length: usize) -> Option { } } +pub fn cm_get_clients_length() -> usize { + crate::ui_cm_interface::get_clients_length() +} + pub fn main_init(app_dir: String) { initialize(&app_dir); } @@ -941,6 +945,10 @@ pub fn cm_close_connection(conn_id: i32) { crate::ui_cm_interface::close(conn_id); } +pub fn cm_remove_disconnected_connection(conn_id: i32) { + crate::ui_cm_interface::remove(conn_id); +} + pub fn cm_check_click_time(conn_id: i32) { crate::ui_cm_interface::check_click_time(conn_id) } diff --git a/src/ipc.rs b/src/ipc.rs index 709384bb6..229bcf166 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -186,6 +186,7 @@ pub enum Data { Theme(String), Language(String), Empty, + Disconnected, } #[tokio::main(flavor = "current_thread")] diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 691caee52..e5f01b185 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", "以当前用户权限运行软件,可能导致远端在访问本机时,没有足够的权限来操作部分窗口。"), ("uac_warning", "暂时无法访问远端设备,因为远端设备正在请求用户账户权限,请等待对方关闭UAC窗口。为避免这个问题,建议在远端设备上安装或者以管理员权限运行本软件。"), ("elevated_foreground_window_warning", "暂时无法使用鼠标键盘,因为远端桌面的当前窗口需要更高的权限才能操作, 可以请求对方最小化当前窗口。为避免这个问题,建议在远端设备上安装或者以管理员权限运行本软件。"), + ("Disconnected", "会话已结束"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index f6f1f7651..9186454d1 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index f4173845b..073fda6a4 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 22ce0de2d..255ae932d 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index b8ccb3a2d..18d4e0ba2 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index fda44d4da..f6e8b803b 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 8065373f8..3dae5053c 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index e636d2ae8..14bd1a895 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index cc9de05cd..d260e0add 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index b4fd14d26..fb8d80435 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 4c6e84232..4107760c1 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 0dc7ef141..9a8ef361d 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 9260b67de..517157c83 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index b7934a087..14b95a979 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", "Monit o podwyższeniu uprawnień"), ("uac_warning", "Ostrzeżenie UAC"), ("elevated_foreground_window_warning", "Pierwszoplanowe okno ostrzeżenia o podwyższeniu uprawnień"), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index a387ade70..8798c90d9 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index c858b8c22..d59eb0624 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index f90f905cf..b04a80de0 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 96213b4f6..ec93850fe 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 4c02ab45b..666e1cf02 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 6bdebc24e..935faea84 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 460145cbe..9e3a040da 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", "以當前用戶權限運行軟件,可能導致遠端在訪問本機時,沒有足夠的權限來操作部分窗口。"), ("uac_warning", "暂时无法访问远端设备,因为远端设备正在请求用户账户权限,请等待对方关闭UAC窗口。为避免这个问题,建议在远端设备上安装或者以管理员权限运行本软件。"), ("elevated_foreground_window_warning", "暫時無法使用鼠標鍵盤,因為遠端桌面的當前窗口需要更高的權限才能操作, 可以請求對方最小化當前窗口。為避免這個問題,建議在遠端設備上安裝或者以管理員權限運行本軟件。"), + ("Disconnected", "會話已結束"), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index ed2f5bdcd..32f818911 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -362,5 +362,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable LAN Discovery", "Увімкнути пошук локальної мережі"), ("Deny LAN Discovery", "Заборонити виявлення локальної мережі"), ("Write a message", "Написати повідомлення"), + ("Prompt", ""), + ("elevation_prompt", ""), + ("uac_warning", ""), + ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 781c9629d..9310c90b7 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", ""), ("uac_warning", ""), ("elevated_foreground_window_warning", ""), + ("Disconnected", ""), ].iter().cloned().collect(); } diff --git a/src/server/connection.rs b/src/server/connection.rs index 8ad408885..14c906bcf 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -95,6 +95,8 @@ pub struct Connection { api_server: String, lr: LoginRequest, last_recv_time: Arc>, + chat_unanswered: bool, + close_manually: bool, } impl Subscriber for ConnInner { @@ -184,6 +186,8 @@ impl Connection { api_server: "".to_owned(), lr: Default::default(), last_recv_time: Arc::new(Mutex::new(Instant::now())), + chat_unanswered: false, + close_manually: false, }; #[cfg(not(any(target_os = "android", target_os = "ios")))] tokio::spawn(async move { @@ -246,6 +250,7 @@ impl Connection { } } ipc::Data::Close => { + conn.close_manually = true; let mut misc = Misc::new(); misc.set_close_reason("Closed manually by the peer".into()); let mut msg_out = Message::new(); @@ -264,6 +269,7 @@ impl Connection { let mut msg_out = Message::new(); msg_out.set_misc(misc); conn.send(msg_out).await; + conn.chat_unanswered = false; } ipc::Data::SwitchPermission{name, enabled} => { log::info!("Change permission {} -> {}", name, enabled); @@ -1245,6 +1251,7 @@ impl Connection { } Some(misc::Union::ChatMessage(c)) => { self.send_to_cm(ipc::Data::ChatMessage { text: c.text }); + self.chat_unanswered = true; } Some(misc::Union::Option(o)) => { self.update_option(&o).await; @@ -1445,7 +1452,15 @@ impl Connection { #[cfg(not(any(target_os = "android", target_os = "ios")))] lock_screen().await; } - self.tx_to_cm.send(ipc::Data::Close).ok(); + #[cfg(not(any(target_os = "android", target_os = "ios")))] + let data = if self.chat_unanswered && !self.close_manually { + ipc::Data::Disconnected + } else { + ipc::Data::Close + }; + #[cfg(any(target_os = "android", target_os = "ios"))] + let data = ipc::Data::Close; + self.tx_to_cm.send(data).ok(); self.port_forward_socket.take(); } diff --git a/src/ui/cm.rs b/src/ui/cm.rs index e0fea8bf3..e5a46817a 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -38,8 +38,8 @@ impl InvokeUiCM for SciterHandler { ); } - fn remove_connection(&self, id: i32) { - self.call("removeConnection", &make_args!(id)); + fn remove_connection(&self, id: i32, close: bool) { + self.call("removeConnection", &make_args!(id, close)); if crate::ui_cm_interface::get_clients_length().eq(&0) { crate::platform::quit_gui(); } @@ -109,6 +109,14 @@ impl SciterConnectionManager { crate::ui_cm_interface::close(id); } + fn remove_disconnected_connection(&self, id: i32) { + crate::ui_cm_interface::remove(id); + } + + fn quit(&self) { + crate::platform::quit_gui(); + } + fn authorize(&self, id: i32) { crate::ui_cm_interface::authorize(id); } @@ -133,6 +141,8 @@ impl sciter::EventHandler for SciterConnectionManager { fn get_click_time(); fn get_icon(); fn close(i32); + fn remove_disconnected_connection(i32); + fn quit(); fn authorize(i32); fn switch_permission(i32, String, bool); fn send_msg(i32, String); diff --git a/src/ui/cm.tis b/src/ui/cm.tis index c6664b50b..2b42b719c 100644 --- a/src/ui/cm.tis +++ b/src/ui/cm.tis @@ -26,6 +26,7 @@ class Body: Reactor.Component me.sendMsg(msg); }; var right_style = show_chat ? "" : "display: none"; + var disconnected = c.disconnected; // below size:* is work around for Linux, it alreayd set in css, but not work, shit sciter return
@@ -36,12 +37,12 @@ class Body: Reactor.Component
{c.name}
({c.peer_id})
-
{translate('Connected')} {" "} {getElaspsed(c.time)}
+
{disconnected ? translate('Disconnected') : translate('Connected')} {" "} {getElaspsed(c.time, c.now)}
- {c.is_file_transfer || c.port_forward ? "" :
{translate('Permissions')}
} - {c.is_file_transfer || c.port_forward ? "" :
+ {c.is_file_transfer || c.port_forward || disconnected ? "" :
{translate('Permissions')}
} + {c.is_file_transfer || c.port_forward || disconnected ? "" :
@@ -56,7 +57,8 @@ class Body: Reactor.Component
{auth ? "" : } {auth ? "" : } - {auth ? : ""} + {auth && !disconnected ? : ""} + {auth && disconnected ? : ""}
{c.is_file_transfer || c.port_forward ? "" :
{svg_chat}
}
@@ -155,6 +157,25 @@ class Body: Reactor.Component handler.close(cid); }); } + + event click $(button#close) { + var cid = this.cid; + if (this.cur >= 0 && this.cur < connections.length){ + handler.remove_disconnected_connection(cid); + connections.splice(this.cur, 1); + if (connections.length > 0) { + if (this.cur > 0) + this.cur -= 1; + else + this.cur = connections.length - 1; + header.update(); + body.update(); + } else { + handler.quit(); + } + } + + } } $(body).content(); @@ -299,15 +320,26 @@ handler.addConnection = function(id, is_file_transfer, port_forward, peer_id, na update(); return; } + var idx = -1; + connections.map(function(c, i) { + if (c.disconnected && c.peer_id == peer_id) idx = i; + }); if (!name) name = "NA"; - connections.push({ + conn = { id: id, is_file_transfer: is_file_transfer, peer_id: peer_id, port_forward: port_forward, - name: name, authorized: authorized, time: new Date(), + name: name, authorized: authorized, time: new Date(), now: new Date(), keyboard: keyboard, clipboard: clipboard, msgs: [], unreaded: 0, - audio: audio, file: file, restart: restart, recording: recording - }); - body.cur = connections.length - 1; + audio: audio, file: file, restart: restart, recording: recording, + disconnected: false + }; + if (idx < 0) { + connections.push(conn); + body.cur = connections.length - 1; + } else { + connections[idx] = conn; + body.cur = idx; + } bring_to_top(); update(); self.timer(1ms, adjustHeader); @@ -318,15 +350,20 @@ handler.addConnection = function(id, is_file_transfer, port_forward, peer_id, na } } -handler.removeConnection = function(id) { +handler.removeConnection = function(id, close) { var i = -1; connections.map(function(c, idx) { if (c.id == id) i = idx; }); if (i < 0) return; - connections.splice(i, 1); + if (close) { + connections.splice(i, 1); + } else { + var conn = connections[i]; + conn.disconnected = true; + } if (connections.length > 0) { - if (body.cur >= i && body.cur > 0) body.cur -= 1; + if (body.cur >= i && body.cur > 0 && close) body.cur -= 1; update(); } } @@ -361,8 +398,7 @@ function self.ready() { view.move(sw - w, 0, w, h); } -function getElaspsed(time) { - var now = new Date(); +function getElaspsed(time, now) { var seconds = Date.diff(time, now, #seconds); var hours = seconds / 3600; var days = hours / 24; @@ -378,11 +414,15 @@ function getElaspsed(time) { function updateTime() { self.timer(1s, function() { + var now = new Date(); + connections.map(function(c) { + if (!c.disconnected) c.now = now; + }); var el = $(#time); if (el) { var c = connections[body.cur]; - if (c) { - el.text = getElaspsed(c.time); + if (c && !c.disconnected) { + el.text = getElaspsed(c.time, c.now); } } updateTime(); diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 3813760a0..bd05f3bce 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -31,6 +31,7 @@ use hbb_common::{ pub struct Client { pub id: i32, pub authorized: bool, + pub disconnected: bool, pub is_file_transfer: bool, pub port_forward: String, pub name: String, @@ -58,7 +59,7 @@ pub struct ConnectionManager { pub trait InvokeUiCM: Send + Clone + 'static + Sized { fn add_connection(&self, client: &Client); - fn remove_connection(&self, id: i32); + fn remove_connection(&self, id: i32, close: bool); fn new_message(&self, id: i32, text: String); @@ -101,6 +102,7 @@ impl ConnectionManager { let client = Client { id, authorized, + disconnected: false, is_file_transfer, port_forward, name: name.clone(), @@ -113,12 +115,24 @@ impl ConnectionManager { recording, tx, }; + CLIENTS + .write() + .unwrap() + .retain(|_, c| !(c.disconnected && c.peer_id == client.peer_id)); + CLIENTS.write().unwrap().insert(id, client.clone()); self.ui_handler.add_connection(&client); - CLIENTS.write().unwrap().insert(id, client); } - fn remove_connection(&self, id: i32) { - CLIENTS.write().unwrap().remove(&id); + fn remove_connection(&self, id: i32, close: bool) { + if close { + CLIENTS.write().unwrap().remove(&id); + } else { + CLIENTS + .write() + .unwrap() + .get_mut(&id) + .map(|c| c.disconnected = true); + } #[cfg(any(target_os = "android"))] if CLIENTS @@ -136,7 +150,7 @@ impl ConnectionManager { } } - self.ui_handler.remove_connection(id); + self.ui_handler.remove_connection(id, close); } } @@ -167,6 +181,11 @@ pub fn close(id: i32) { }; } +#[inline] +pub fn remove(id: i32) { + CLIENTS.write().unwrap().remove(&id); +} + // server mode send chat to peer #[inline] pub fn send_chat(id: i32, text: String) { @@ -243,6 +262,7 @@ pub async fn start_ipc(cm: ConnectionManager) { let mut conn_id: i32 = 0; let (tx, mut rx) = mpsc::unbounded_channel::(); let mut write_jobs: Vec = Vec::new(); + let mut close = true; loop { tokio::select! { res = stream.next() => { @@ -264,6 +284,12 @@ pub async fn start_ipc(cm: ConnectionManager) { log::info!("cm ipc connection closed from connection request"); break; } + Data::Disconnected => { + close = false; + tx_file.send(ClipboardFileData::Enable((conn_id, false))).ok(); + log::info!("cm ipc connection disconnect"); + break; + } Data::PrivacyModeState((id, _)) => { conn_id = conn_id_tmp; allow_err!(tx.send(data)); @@ -312,7 +338,7 @@ pub async fn start_ipc(cm: ConnectionManager) { } } if conn_id != conn_id_tmp { - cm.remove_connection(conn_id); + cm.remove_connection(conn_id, close); } }); }