diff --git a/flutter/lib/cm_main.dart b/flutter/lib/cm_main.dart index 1f71b9e93..bf72849e8 100644 --- a/flutter/lib/cm_main.dart +++ b/flutter/lib/cm_main.dart @@ -14,7 +14,7 @@ void main(List args) async { await windowManager.ensureInitialized(); await windowManager.setSize(Size(400, 600)); await windowManager.setAlignment(Alignment.topRight); - await initEnv(kAppTypeConnectionManager); + await initEnv(kAppTypeMain); gFFI.serverModel.clients .add(Client(0, false, false, "UserA", "123123123", true, false, false)); gFFI.serverModel.clients diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index c33e2b291..ece2ec797 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -18,11 +18,11 @@ import 'models/platform_model.dart'; final globalKey = GlobalKey(); final navigationBarKey = GlobalKey(); -var isAndroid = Platform.isAndroid; -var isIOS = Platform.isIOS; +final isAndroid = Platform.isAndroid; +final isIOS = Platform.isIOS; +final isDesktop = Platform.isWindows || Platform.isMacOS || Platform.isLinux; var isWeb = false; var isWebDesktop = false; -var isDesktop = Platform.isWindows || Platform.isMacOS || Platform.isLinux; var version = ""; int androidVersion = 0; diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 09e80b482..000a1cb54 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -1,8 +1,9 @@ const double kDesktopRemoteTabBarHeight = 28.0; + +/// [kAppTypeMain] used by 'Desktop Main Page' , 'Mobile (Client and Server)' , 'Desktop CM Page' const String kAppTypeMain = "main"; const String kAppTypeDesktopRemote = "remote"; const String kAppTypeDesktopFileTransfer = "file transfer"; -const String kAppTypeConnectionManager = "connection manager"; const String kTabLabelHomePage = "Home"; const String kTabLabelSettingPage = "Settings"; diff --git a/flutter/lib/desktop/pages/file_manager_page.dart b/flutter/lib/desktop/pages/file_manager_page.dart index e07fadf28..4a2f11553 100644 --- a/flutter/lib/desktop/pages/file_manager_page.dart +++ b/flutter/lib/desktop/pages/file_manager_page.dart @@ -87,27 +87,6 @@ class _FileManagerPageState extends State @override Widget build(BuildContext context) { super.build(context); - return ChangeNotifierProvider.value( - value: _ffi.fileModel, - child: Consumer(builder: (_context, _model, _child) { - return WillPopScope( - onWillPop: () async { - if (model.selectMode) { - model.toggleSelectMode(); - } - return false; - }, - child: Scaffold( - backgroundColor: MyTheme.color(context).bg, - body: Row( - children: [ - Flexible(flex: 3, child: body(isLocal: true)), - Flexible(flex: 3, child: body(isLocal: false)), - Flexible(flex: 2, child: statusList()) - ], - ), - )); - })); return Overlay(initialEntries: [ OverlayEntry(builder: (context) { _ffi.dialogManager.setOverlayState(Overlay.of(context)); @@ -122,6 +101,7 @@ class _FileManagerPageState extends State return false; }, child: Scaffold( + backgroundColor: MyTheme.color(context).bg, body: Row( children: [ Flexible(flex: 3, child: body(isLocal: true)), diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index 0023158ca..bfcc28382 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -18,13 +18,27 @@ class DesktopServerPage extends StatefulWidget { } class _DesktopServerPageState extends State - with AutomaticKeepAliveClientMixin { + with WindowListener, AutomaticKeepAliveClientMixin { @override void initState() { gFFI.ffiModel.updateEventListener(""); + windowManager.addListener(this); super.initState(); } + @override + void dispose() { + windowManager.removeListener(this); + super.dispose(); + } + + @override + void onWindowClose() { + gFFI.serverModel.closeAll(); + gFFI.close(); + super.onWindowClose(); + } + Widget build(BuildContext context) { super.build(context); return MultiProvider( diff --git a/flutter/lib/desktop/widgets/peercard_widget.dart b/flutter/lib/desktop/widgets/peercard_widget.dart index 3ec149d60..e8f4d6801 100644 --- a/flutter/lib/desktop/widgets/peercard_widget.dart +++ b/flutter/lib/desktop/widgets/peercard_widget.dart @@ -62,7 +62,7 @@ class _PeerCardState extends State<_PeerCard> : null); }, child: GestureDetector( - onDoubleTap: () => _connect(peer.id), + onDoubleTapDown: (_) => _connect(peer.id), child: Obx(() => peerCardUiType.value == PeerUiType.grid ? _buildPeerCard(context, peer, deco) : _buildPeerTile(context, peer, deco))), @@ -168,109 +168,106 @@ class _PeerCardState extends State<_PeerCard> BuildContext context, Peer peer, Rx deco) { return Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), - child: GestureDetector( - onDoubleTap: () => _connect(peer.id), - child: Obx( - () => Container( - decoration: deco.value, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - child: Container( - decoration: BoxDecoration( - color: str2color('${peer.id}${peer.platform}', 0x7f), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20), - ), - ), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - padding: const EdgeInsets.all(6), - child: _getPlatformImage('${peer.platform}'), - ), - Row( - children: [ - Expanded( - child: FutureBuilder( - future: bind.mainGetPeerOption( - id: peer.id, key: 'alias'), - builder: (_, snapshot) { - if (snapshot.hasData) { - final name = snapshot.data!.isEmpty - ? '${peer.username}@${peer.hostname}' - : snapshot.data!; - return Tooltip( - message: name, - child: Text( - name, - style: TextStyle( - color: Colors.white70, - fontSize: 12), - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - ), - ); - } else { - // alias has not arrived - return Center( - child: Text( - '${peer.username}@${peer.hostname}', - style: TextStyle( - color: Colors.white70, - fontSize: 12), - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - )); - } - }, - ), - ), - ], - ), - ], - ).paddingAll(4.0), - ), - ], - ), + child: Obx( + () => Container( + decoration: deco.value, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + color: str2color('${peer.id}${peer.platform}', 0x7f), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), ), ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: Row( children: [ - Row(children: [ - Padding( - padding: EdgeInsets.fromLTRB(0, 4, 8, 4), - child: CircleAvatar( - radius: 5, - backgroundColor: peer.online - ? Colors.green - : Colors.yellow)), - Text('${peer.id}') - ]), - InkWell( - child: Icon(Icons.more_vert), - onTapDown: (e) { - final x = e.globalPosition.dx; - final y = e.globalPosition.dy; - _menuPos = RelativeRect.fromLTRB(x, y, x, y); - }, - onTap: () { - _showPeerMenu(context, peer.id); - }), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + padding: const EdgeInsets.all(6), + child: _getPlatformImage('${peer.platform}'), + ), + Row( + children: [ + Expanded( + child: FutureBuilder( + future: bind.mainGetPeerOption( + id: peer.id, key: 'alias'), + builder: (_, snapshot) { + if (snapshot.hasData) { + final name = snapshot.data!.isEmpty + ? '${peer.username}@${peer.hostname}' + : snapshot.data!; + return Tooltip( + message: name, + child: Text( + name, + style: TextStyle( + color: Colors.white70, + fontSize: 12), + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + ), + ); + } else { + // alias has not arrived + return Center( + child: Text( + '${peer.username}@${peer.hostname}', + style: TextStyle( + color: Colors.white70, + fontSize: 12), + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + )); + } + }, + ), + ), + ], + ), + ], + ).paddingAll(4.0), + ), ], - ).paddingSymmetric(vertical: 8.0, horizontal: 12.0) - ], + ), + ), ), - ), - )), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row(children: [ + Padding( + padding: EdgeInsets.fromLTRB(0, 4, 8, 4), + child: CircleAvatar( + radius: 5, + backgroundColor: + peer.online ? Colors.green : Colors.yellow)), + Text('${peer.id}') + ]), + InkWell( + child: Icon(Icons.more_vert), + onTapDown: (e) { + final x = e.globalPosition.dx; + final y = e.globalPosition.dy; + _menuPos = RelativeRect.fromLTRB(x, y, x, y); + }, + onTap: () { + _showPeerMenu(context, peer.id); + }), + ], + ).paddingSymmetric(vertical: 8.0, horizontal: 12.0) + ], + ), + ), + ), ); } diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 530696a48..7198a1c3c 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -161,6 +161,7 @@ class DesktopTabBar extends StatelessWidget { } static onAdd(RxList tabs, TabInfo tab) { + if (!isDesktop) return; int index = tabs.indexWhere((e) => e.key == tab.key); if (index >= 0) { selected.value = index; @@ -178,6 +179,7 @@ class DesktopTabBar extends StatelessWidget { } static remove(RxList tabs, int index) { + if (!isDesktop) return; if (index < 0) return; if (index == tabs.length - 1) { selected.value = max(0, selected.value - 1); @@ -189,12 +191,14 @@ class DesktopTabBar extends StatelessWidget { } static void jumpTo(RxList tabs, int index) { + if (!isDesktop) return; if (index < 0 || index >= tabs.length) return; selected.value = index; controller.value.jumpToPage(selected.value); } static void close(String? key) { + if (!isDesktop) return; final tabBar = _tabBarListViewKey.currentWidget as _ListView?; if (tabBar == null) return; final tabs = tabBar.tabs; diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 960bfb667..a1bebbea7 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -27,7 +27,7 @@ Future main(List args) async { print("launch args: $args"); if (!isDesktop) { - runMainApp(false); + runMobileApp(); return; } // main window @@ -72,9 +72,6 @@ Future initEnv(String appType) async { // focus on multi-ffi on desktop first await initGlobalFFI(); // await Firebase.initializeApp(); - if (isAndroid) { - toAndroidChannelInit(); - } refreshCurrentUser(); } @@ -96,6 +93,12 @@ void runMainApp(bool startService) async { runApp(App()); } +void runMobileApp() async { + await initEnv(kAppTypeMain); + if (isAndroid) androidChannelInit(); + runApp(App()); +} + void runRemoteScreen(Map argument) async { await initEnv(kAppTypeDesktopRemote); runApp(GetMaterialApp( @@ -129,7 +132,7 @@ void runConnectionManagerScreen() async { // initialize window WindowOptions windowOptions = getHiddenTitleBarWindowOptions(Size(300, 400)); await Future.wait([ - initEnv(kAppTypeConnectionManager), + initEnv(kAppTypeMain), windowManager.waitUntilReadyToShow(windowOptions, () async { await windowManager.setAlignment(Alignment.topRight); await windowManager.show(); diff --git a/flutter/lib/mobile/pages/server_page.dart b/flutter/lib/mobile/pages/server_page.dart index abbc5aadc..00c433fd8 100644 --- a/flutter/lib/mobile/pages/server_page.dart +++ b/flutter/lib/mobile/pages/server_page.dart @@ -510,7 +510,7 @@ Widget clientInfo(Client client) { ])); } -void toAndroidChannelInit() { +void androidChannelInit() { gFFI.setMethodCallHandler((method, arguments) { debugPrint("flutter got android msg,$method,$arguments"); try { diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index 527cea689..dec13f245 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -465,7 +465,12 @@ class ServerModel with ChangeNotifier { try { final client = Client.fromJson(jsonDecode(evt['client'])); parent.target?.dialogManager.dismissByTag(getLoginDialogTag(client.id)); - _clients.add(client); + final index = _clients.indexWhere((c) => c.id == client.id); + if (index < 0) { + _clients.add(client); + } else { + _clients[index].authorized = true; + } DesktopTabBar.onAdd( tabs, TabInfo( diff --git a/src/flutter.rs b/src/flutter.rs index 5e935642a..3af096494 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -41,7 +41,6 @@ use crate::{client::*, flutter_ffi::EventToUI, make_fd_flutter}; pub(super) const APP_TYPE_MAIN: &str = "main"; pub(super) const APP_TYPE_DESKTOP_REMOTE: &str = "remote"; pub(super) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer"; -pub(super) const APP_TYPE_DESKTOP_CONNECTION_MANAGER: &str = "connection manager"; lazy_static::lazy_static! { // static ref SESSION: Arc>> = Default::default(); @@ -1940,7 +1939,7 @@ pub mod connection_manager { if let Some(s) = GLOBAL_EVENT_STREAM .read() .unwrap() - .get(super::APP_TYPE_DESKTOP_CONNECTION_MANAGER) + .get(super::APP_TYPE_MAIN) { s.add(serde_json::ser::to_string(&h).unwrap_or("".to_owned())); }; diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 060aa59db..aa0282bc2 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -2639,7 +2639,7 @@ impl Interface for Handler { self.lc.write().unwrap().handle_peer_info(username, pi); self.call("updatePrivacyMode", &[]); self.call("updatePi", &make_args!(pi_sciter)); - if self.is_file_transfer() { + if self.is_file_transfer() || self.is_port_forward() { self.call2("closeSuccess", &make_args!()); } else if !self.is_port_forward() { self.msgbox("success", "Successful", "Connected, waiting for image...");