From b93e59df21abf70595c92ec67cd559b0e512aa6c Mon Sep 17 00:00:00 2001 From: csf Date: Thu, 8 Sep 2022 19:26:55 +0800 Subject: [PATCH 1/6] confirm connection tab close --- .../desktop/pages/connection_tab_page.dart | 14 ++++++++- .../desktop/pages/file_manager_tab_page.dart | 4 +-- .../desktop/pages/port_forward_tab_page.dart | 3 +- .../lib/desktop/widgets/tabbar_widget.dart | 29 ++++++++++++++----- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_tab_page.dart b/flutter/lib/desktop/pages/connection_tab_page.dart index 8f5350792..bf12f443c 100644 --- a/flutter/lib/desktop/pages/connection_tab_page.dart +++ b/flutter/lib/desktop/pages/connection_tab_page.dart @@ -10,6 +10,8 @@ import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:get/get.dart'; +import '../../mobile/widgets/dialog.dart'; + class ConnectionTabPage extends StatefulWidget { final Map params; @@ -37,6 +39,11 @@ class _ConnectionTabPageState extends State { label: peerId, selectedIcon: selectedIcon, unselectedIcon: unselectedIcon, + onTabCloseButton: () { + debugPrint("onTabCloseButton"); + tabController.jumpBy(peerId); + clientClose(ffi(peerId).dialogManager); + }, page: Obx(() => RemotePage( key: ValueKey(peerId), id: peerId, @@ -69,6 +76,11 @@ class _ConnectionTabPageState extends State { label: id, selectedIcon: selectedIcon, unselectedIcon: unselectedIcon, + onTabCloseButton: () { + debugPrint("onTabCloseButton"); + tabController.jumpBy(id); + clientClose(ffi(id).dialogManager); + }, page: Obx(() => RemotePage( key: ValueKey(id), id: id, @@ -95,7 +107,7 @@ class _ConnectionTabPageState extends State { body: Obx(() => DesktopTab( controller: tabController, showTabBar: fullscreen.isFalse, - onClose: () { + onWindowCloseButton: () { tabController.clear(); }, tail: AddButton().paddingOnly(left: 10), diff --git a/flutter/lib/desktop/pages/file_manager_tab_page.dart b/flutter/lib/desktop/pages/file_manager_tab_page.dart index d6f01e55f..d33c0084c 100644 --- a/flutter/lib/desktop/pages/file_manager_tab_page.dart +++ b/flutter/lib/desktop/pages/file_manager_tab_page.dart @@ -71,10 +71,10 @@ class _FileManagerTabPageState extends State { backgroundColor: MyTheme.color(context).bg, body: DesktopTab( controller: tabController, - onClose: () { + onWindowCloseButton: () { tabController.clear(); }, - tail: AddButton().paddingOnly(left: 10), + tail: const AddButton().paddingOnly(left: 10), )), ), ); diff --git a/flutter/lib/desktop/pages/port_forward_tab_page.dart b/flutter/lib/desktop/pages/port_forward_tab_page.dart index e0384b614..5dd69e8eb 100644 --- a/flutter/lib/desktop/pages/port_forward_tab_page.dart +++ b/flutter/lib/desktop/pages/port_forward_tab_page.dart @@ -78,7 +78,7 @@ class _PortForwardTabPageState extends State { backgroundColor: MyTheme.color(context).bg, body: DesktopTab( controller: tabController, - onClose: () { + onWindowCloseButton: () { tabController.clear(); }, tail: AddButton().paddingOnly(left: 10), @@ -88,7 +88,6 @@ class _PortForwardTabPageState extends State { } void onRemoveId(String id) { - ffi("pf_$id").close(); if (tabController.state.value.tabs.isEmpty) { WindowController.fromWindowId(windowId()).hide(); } diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 5daa1aeb6..f2fc5f8ca 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -24,7 +24,8 @@ class TabInfo { final String label; final IconData? selectedIcon; final IconData? unselectedIcon; - final bool closable; + final bool closable; // + final VoidCallback? onTabCloseButton; final Widget page; TabInfo( @@ -33,6 +34,7 @@ class TabInfo { this.selectedIcon, this.unselectedIcon, this.closable = true, + this.onTabCloseButton, required this.page}); } @@ -137,16 +139,23 @@ class DesktopTabController { } } + void jumpBy(String key) { + if (!isDesktop) return; + final index = state.value.tabs.indexWhere((tab) => tab.key == key); + jumpTo(index); + } + void closeBy(String? key) { if (!isDesktop) return; + debugPrint("closeBy: $key"); assert(onRemove != null); if (key == null) { if (state.value.selected < state.value.tabs.length) { remove(state.value.selected); } } else { - state.value.tabs.indexWhere((tab) => tab.key == key); - remove(state.value.selected); + final index = state.value.tabs.indexWhere((tab) => tab.key == key); + remove(index); } } @@ -175,7 +184,7 @@ class DesktopTab extends StatelessWidget { final bool showClose; final Widget Function(Widget pageView)? pageViewBuilder; final Widget? tail; - final VoidCallback? onClose; + final VoidCallback? onWindowCloseButton; final TabBuilder? tabBuilder; final LabelGetter? labelGetter; @@ -196,7 +205,7 @@ class DesktopTab extends StatelessWidget { this.showClose = true, this.pageViewBuilder, this.tail, - this.onClose, + this.onWindowCloseButton, this.tabBuilder, this.labelGetter, }) : super(key: key) { @@ -333,7 +342,7 @@ class DesktopTab extends StatelessWidget { showMinimize: showMinimize, showMaximize: showMaximize, showClose: showClose, - onClose: onClose, + onClose: onWindowCloseButton, ) ], ); @@ -511,7 +520,13 @@ class _ListView extends StatelessWidget { unselectedIcon: tab.unselectedIcon, closable: tab.closable, selected: state.value.selected, - onClose: () => controller.remove(index), + onClose: () { + if (tab.onTabCloseButton != null) { + tab.onTabCloseButton!(); + } else { + controller.remove(index); + } + }, onSelected: () => controller.jumpTo(index), tabBuilder: tabBuilder == null ? null From 63cb816b7de0cd7685fb7c3a91760f839acb3feb Mon Sep 17 00:00:00 2001 From: csf Date: Thu, 8 Sep 2022 20:43:27 +0800 Subject: [PATCH 2/6] fix: close one connection tab will dispose all tabs (Obx) --- .../desktop/pages/connection_tab_page.dart | 122 +++++++++--------- 1 file changed, 59 insertions(+), 63 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_tab_page.dart b/flutter/lib/desktop/pages/connection_tab_page.dart index bf12f443c..3dd825f36 100644 --- a/flutter/lib/desktop/pages/connection_tab_page.dart +++ b/flutter/lib/desktop/pages/connection_tab_page.dart @@ -44,12 +44,11 @@ class _ConnectionTabPageState extends State { tabController.jumpBy(peerId); clientClose(ffi(peerId).dialogManager); }, - page: Obx(() => RemotePage( - key: ValueKey(peerId), - id: peerId, - tabBarHeight: - fullscreen.isTrue ? 0 : kDesktopRemoteTabBarHeight, - )))); + page: RemotePage( + key: ValueKey(peerId), + id: peerId, + tabBarHeight: fullscreen.isTrue ? 0 : kDesktopRemoteTabBarHeight, + ))); } } @@ -81,12 +80,11 @@ class _ConnectionTabPageState extends State { tabController.jumpBy(id); clientClose(ffi(id).dialogManager); }, - page: Obx(() => RemotePage( - key: ValueKey(id), - id: id, - tabBarHeight: - fullscreen.isTrue ? 0 : kDesktopRemoteTabBarHeight, - )))); + page: RemotePage( + key: ValueKey(id), + id: id, + tabBarHeight: fullscreen.isTrue ? 0 : kDesktopRemoteTabBarHeight, + ))); } else if (call.method == "onDestroy") { tabController.clear(); } @@ -104,57 +102,55 @@ class _ConnectionTabPageState extends State { border: Border.all(color: MyTheme.color(context).border!)), child: Scaffold( backgroundColor: MyTheme.color(context).bg, - body: Obx(() => DesktopTab( - controller: tabController, - showTabBar: fullscreen.isFalse, - onWindowCloseButton: () { - tabController.clear(); - }, - tail: AddButton().paddingOnly(left: 10), - pageViewBuilder: (pageView) { - WindowController.fromWindowId(windowId()) - .setFullscreen(fullscreen.isTrue); - return pageView; - }, - tabBuilder: (key, icon, label, themeConf) => Obx(() { - final connectionType = ConnectionTypeState.find(key); - if (!connectionType.isValid()) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - icon, - label, - ], - ); - } else { - final msgDirect = translate( - connectionType.direct.value == - ConnectionType.strDirect - ? 'Direct Connection' - : 'Relay Connection'); - final msgSecure = translate( - connectionType.secure.value == - ConnectionType.strSecure - ? 'Secure Connection' - : 'Insecure Connection'); - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - icon, - Tooltip( - message: '$msgDirect\n$msgSecure', - child: Image.asset( - 'assets/${connectionType.secure.value}${connectionType.direct.value}.png', - width: themeConf.iconSize, - height: themeConf.iconSize, - ).paddingOnly(right: 5), - ), - label, - ], - ); - } - }), - ))), + body: DesktopTab( + controller: tabController, + showTabBar: fullscreen.isFalse, + onWindowCloseButton: () { + tabController.clear(); + }, + tail: AddButton().paddingOnly(left: 10), + pageViewBuilder: (pageView) { + WindowController.fromWindowId(windowId()) + .setFullscreen(fullscreen.isTrue); + return pageView; + }, + tabBuilder: (key, icon, label, themeConf) => Obx(() { + final connectionType = ConnectionTypeState.find(key); + if (!connectionType.isValid()) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + icon, + label, + ], + ); + } else { + final msgDirect = translate(connectionType.direct.value == + ConnectionType.strDirect + ? 'Direct Connection' + : 'Relay Connection'); + final msgSecure = translate(connectionType.secure.value == + ConnectionType.strSecure + ? 'Secure Connection' + : 'Insecure Connection'); + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + icon, + Tooltip( + message: '$msgDirect\n$msgSecure', + child: Image.asset( + 'assets/${connectionType.secure.value}${connectionType.direct.value}.png', + width: themeConf.iconSize, + height: themeConf.iconSize, + ).paddingOnly(right: 5), + ), + label, + ], + ); + } + }), + )), ), )); } From 30156c694b6535fbe854f6ceaa35081cb5b31a7d Mon Sep 17 00:00:00 2001 From: csf Date: Thu, 8 Sep 2022 21:03:20 +0800 Subject: [PATCH 3/6] add file_transfer confirm close --- .../desktop/pages/connection_tab_page.dart | 22 ++++++++++--------- .../desktop/pages/file_manager_tab_page.dart | 14 ++++++++++++ .../lib/desktop/widgets/tabbar_widget.dart | 3 +-- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_tab_page.dart b/flutter/lib/desktop/pages/connection_tab_page.dart index 3dd825f36..e5caccd71 100644 --- a/flutter/lib/desktop/pages/connection_tab_page.dart +++ b/flutter/lib/desktop/pages/connection_tab_page.dart @@ -39,11 +39,7 @@ class _ConnectionTabPageState extends State { label: peerId, selectedIcon: selectedIcon, unselectedIcon: unselectedIcon, - onTabCloseButton: () { - debugPrint("onTabCloseButton"); - tabController.jumpBy(peerId); - clientClose(ffi(peerId).dialogManager); - }, + onTabCloseButton: () => handleTabCloseButton(peerId), page: RemotePage( key: ValueKey(peerId), id: peerId, @@ -75,11 +71,7 @@ class _ConnectionTabPageState extends State { label: id, selectedIcon: selectedIcon, unselectedIcon: unselectedIcon, - onTabCloseButton: () { - debugPrint("onTabCloseButton"); - tabController.jumpBy(id); - clientClose(ffi(id).dialogManager); - }, + onTabCloseButton: () => handleTabCloseButton(id), page: RemotePage( key: ValueKey(id), id: id, @@ -165,4 +157,14 @@ class _ConnectionTabPageState extends State { int windowId() { return widget.params["windowId"]; } + + void handleTabCloseButton(String peerId) { + final session = ffi(peerId); + if (session.ffiModel.pi.hostname.isNotEmpty) { + tabController.jumpBy(peerId); + clientClose(session.dialogManager); + } else { + tabController.closeBy(peerId); + } + } } diff --git a/flutter/lib/desktop/pages/file_manager_tab_page.dart b/flutter/lib/desktop/pages/file_manager_tab_page.dart index d33c0084c..42c50b927 100644 --- a/flutter/lib/desktop/pages/file_manager_tab_page.dart +++ b/flutter/lib/desktop/pages/file_manager_tab_page.dart @@ -8,6 +8,8 @@ import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:get/get.dart'; +import '../../mobile/widgets/dialog.dart'; + /// File Transfer for multi tabs class FileManagerTabPage extends StatefulWidget { final Map params; @@ -31,6 +33,7 @@ class _FileManagerTabPageState extends State { label: params['id'], selectedIcon: selectedIcon, unselectedIcon: unselectedIcon, + onTabCloseButton: () => handleTabCloseButton(params['id']), page: FileManagerPage(key: ValueKey(params['id']), id: params['id']))); } @@ -53,6 +56,7 @@ class _FileManagerTabPageState extends State { label: id, selectedIcon: selectedIcon, unselectedIcon: unselectedIcon, + onTabCloseButton: () => handleTabCloseButton(id), page: FileManagerPage(key: ValueKey(id), id: id))); } else if (call.method == "onDestroy") { tabController.clear(); @@ -89,4 +93,14 @@ class _FileManagerTabPageState extends State { int windowId() { return widget.params["windowId"]; } + + void handleTabCloseButton(String peerId) { + final session = ffi('ft_$peerId'); + if (session.ffiModel.pi.hostname.isNotEmpty) { + tabController.jumpBy(peerId); + clientClose(session.dialogManager); + } else { + tabController.closeBy(peerId); + } + } } diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index f2fc5f8ca..fef5fbf1f 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -24,7 +24,7 @@ class TabInfo { final String label; final IconData? selectedIcon; final IconData? unselectedIcon; - final bool closable; // + final bool closable; final VoidCallback? onTabCloseButton; final Widget page; @@ -147,7 +147,6 @@ class DesktopTabController { void closeBy(String? key) { if (!isDesktop) return; - debugPrint("closeBy: $key"); assert(onRemove != null); if (key == null) { if (state.value.selected < state.value.tabs.length) { From 36143c08807ef269ccea9414d812303da647c84a Mon Sep 17 00:00:00 2001 From: csf Date: Thu, 8 Sep 2022 21:12:35 +0800 Subject: [PATCH 4/6] update Cargo.lock pubspec.lock & rename connection_tab_page.dart -> remote_tab_page.dart --- Cargo.lock | 2 +- .../{connection_tab_page.dart => remote_tab_page.dart} | 0 flutter/lib/desktop/screen/desktop_remote_screen.dart | 2 +- flutter/pubspec.lock | 9 +++++++++ 4 files changed, 11 insertions(+), 2 deletions(-) rename flutter/lib/desktop/pages/{connection_tab_page.dart => remote_tab_page.dart} (100%) diff --git a/Cargo.lock b/Cargo.lock index 303d18f1e..5c3313336 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4201,7 +4201,7 @@ dependencies = [ [[package]] name = "rustdesk" -version = "1.1.10" +version = "1.2.0" dependencies = [ "android_logger 0.11.1", "arboard", diff --git a/flutter/lib/desktop/pages/connection_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart similarity index 100% rename from flutter/lib/desktop/pages/connection_tab_page.dart rename to flutter/lib/desktop/pages/remote_tab_page.dart diff --git a/flutter/lib/desktop/screen/desktop_remote_screen.dart b/flutter/lib/desktop/screen/desktop_remote_screen.dart index 5b5dd07c2..1dcb426df 100644 --- a/flutter/lib/desktop/screen/desktop_remote_screen.dart +++ b/flutter/lib/desktop/screen/desktop_remote_screen.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; -import 'package:flutter_hbb/desktop/pages/connection_tab_page.dart'; +import 'package:flutter_hbb/desktop/pages/remote_tab_page.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index 586187be2..e6fa83b1d 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -414,6 +414,15 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.3.0" + flutter_custom_cursor: + dependency: "direct main" + description: + path: "." + ref: "9021e21de36c84edf01d5034f38eda580463163b" + resolved-ref: "9021e21de36c84edf01d5034f38eda580463163b" + url: "https://github.com/Kingtous/rustdesk_flutter_custom_cursor" + source: git + version: "0.0.1" flutter_launcher_icons: dependency: "direct dev" description: From d0c438268d3863cddc795d08ddc68f0ab46b12b0 Mon Sep 17 00:00:00 2001 From: csf Date: Thu, 8 Sep 2022 22:18:02 +0800 Subject: [PATCH 5/6] update overlay widgets on flutter desktop 1. add mobile actions 2. disable showChatIcon --- flutter/lib/common.dart | 59 ++++++++- flutter/lib/desktop/pages/remote_page.dart | 4 +- .../lib/desktop/widgets/remote_menubar.dart | 26 ++-- flutter/lib/mobile/pages/remote_page.dart | 19 +-- flutter/lib/mobile/widgets/overlay.dart | 121 ++++++------------ flutter/lib/models/chat_model.dart | 7 +- flutter/lib/models/model.dart | 7 +- 7 files changed, 126 insertions(+), 117 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 92ae17f9a..249b45a0c 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -14,6 +14,7 @@ import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:window_manager/window_manager.dart'; +import 'mobile/widgets/overlay.dart'; import 'models/model.dart'; import 'models/platform_model.dart'; @@ -294,9 +295,11 @@ class Dialog { class OverlayDialogManager { OverlayState? _overlayState; - Map _dialogs = Map(); + final Map _dialogs = {}; int _tagCount = 0; + OverlayEntry? _mobileActionsOverlayEntry; + /// By default OverlayDialogManager use global overlay OverlayDialogManager() { _overlayState = globalKey.currentState?.overlay; @@ -418,6 +421,60 @@ class OverlayDialogManager { ); }); } + + void resetMobileActionsOverlay({FFI? ffi}) { + if (_mobileActionsOverlayEntry == null) return; + hideMobileActionsOverlay(); + showMobileActionsOverlay(ffi: ffi); + } + + void showMobileActionsOverlay({FFI? ffi}) { + if (_mobileActionsOverlayEntry != null) return; + if (_overlayState == null) return; + + // compute overlay position + final screenW = MediaQuery.of(globalKey.currentContext!).size.width; + final screenH = MediaQuery.of(globalKey.currentContext!).size.height; + const double overlayW = 200; + const double overlayH = 45; + final left = (screenW - overlayW) / 2; + final top = screenH - overlayH - 80; + + final overlay = OverlayEntry(builder: (context) { + final session = ffi ?? gFFI; + return DraggableMobileActions( + position: Offset(left, top), + width: overlayW, + height: overlayH, + onBackPressed: () => session.tap(MouseButtons.right), + onHomePressed: () => session.tap(MouseButtons.wheel), + onRecentPressed: () async { + session.sendMouse('down', MouseButtons.wheel); + await Future.delayed(const Duration(milliseconds: 500)); + session.sendMouse('up', MouseButtons.wheel); + }, + onHidePressed: () => hideMobileActionsOverlay(), + ); + }); + _overlayState!.insert(overlay); + _mobileActionsOverlayEntry = overlay; + } + + void hideMobileActionsOverlay() { + if (_mobileActionsOverlayEntry != null) { + _mobileActionsOverlayEntry!.remove(); + _mobileActionsOverlayEntry = null; + return; + } + } + + void toggleMobileActionsOverlay({FFI? ffi}) { + if (_mobileActionsOverlayEntry == null) { + showMobileActionsOverlay(ffi: ffi); + } else { + hideMobileActionsOverlay(); + } + } } void showToast(String text, {Duration timeout = const Duration(seconds: 2)}) { diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 158028ab3..c03c2f3d4 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:io'; -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/gestures.dart'; @@ -16,7 +15,6 @@ import 'package:flutter_custom_cursor/flutter_custom_cursor.dart'; import '../widgets/remote_menubar.dart'; import '../../common.dart'; import '../../mobile/widgets/dialog.dart'; -import '../../mobile/widgets/overlay.dart'; import '../../models/model.dart'; import '../../models/platform_model.dart'; import '../../common/shared_state.dart'; @@ -107,7 +105,7 @@ class _RemotePageState extends State @override void dispose() { debugPrint("REMOTE PAGE dispose ${widget.id}"); - hideMobileActionsOverlay(); + _ffi.dialogManager.hideMobileActionsOverlay(); _ffi.listenToMouse(false); _mobileFocusNode.dispose(); _physicalFocusNode.dispose(); diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index 28085246f..c5e74be12 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -6,7 +6,6 @@ import 'package:rxdart/rxdart.dart' as rxdart; import '../../common.dart'; import '../../mobile/widgets/dialog.dart'; -import '../../mobile/widgets/overlay.dart'; import '../../models/model.dart'; import '../../models/platform_model.dart'; import '../../common/shared_state.dart'; @@ -75,20 +74,17 @@ class _RemoteMenubarState extends State { final List menubarItems = []; if (!isWebDesktop) { menubarItems.add(_buildFullscreen(context)); - //if (widget.ffi.ffiModel.isPeerAndroid) { - menubarItems.add(IconButton( - tooltip: translate('Mobile Actions'), - color: _MenubarTheme.commonColor, - icon: const Icon(Icons.build), - onPressed: () { - if (mobileActionsOverlayEntry == null) { - showMobileActionsOverlay(); - } else { - hideMobileActionsOverlay(); - } - }, - )); - //} + if (widget.ffi.ffiModel.isPeerAndroid) { + menubarItems.add(IconButton( + tooltip: translate('Mobile Actions'), + color: _MenubarTheme.commonColor, + icon: const Icon(Icons.build), + onPressed: () { + widget.ffi.dialogManager + .toggleMobileActionsOverlay(ffi: widget.ffi); + }, + )); + } } menubarItems.add(_buildMonitor(context)); menubarItems.add(_buildControl(context)); diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index ceb3df0ff..419a98f3a 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -14,7 +14,6 @@ import '../../models/model.dart'; import '../../models/platform_model.dart'; import '../widgets/dialog.dart'; import '../widgets/gestures.dart'; -import '../widgets/overlay.dart'; final initText = '\1' * 1024; @@ -64,7 +63,7 @@ class _RemotePageState extends State { @override void dispose() { - hideMobileActionsOverlay(); + gFFI.dialogManager.hideMobileActionsOverlay(); gFFI.listenToMouse(false); gFFI.invokeMethod("enable_soft_keyboard", true); _mobileFocusNode.dispose(); @@ -266,8 +265,9 @@ class _RemotePageState extends State { : SafeArea(child: OrientationBuilder(builder: (ctx, orientation) { if (_currentOrientation != orientation) { - Timer(Duration(milliseconds: 200), () { - resetMobileActionsOverlay(); + Timer(const Duration(milliseconds: 200), () { + gFFI.dialogManager + .resetMobileActionsOverlay(ffi: gFFI); _currentOrientation = orientation; gFFI.canvasModel.updateViewStyle(); }); @@ -422,14 +422,9 @@ class _RemotePageState extends State { ? [ IconButton( color: Colors.white, - icon: Icon(Icons.build), - onPressed: () { - if (mobileActionsOverlayEntry == null) { - showMobileActionsOverlay(); - } else { - hideMobileActionsOverlay(); - } - }, + icon: const Icon(Icons.build), + onPressed: () => gFFI.dialogManager + .toggleMobileActionsOverlay(ffi: gFFI), ) ] : [ diff --git a/flutter/lib/mobile/widgets/overlay.dart b/flutter/lib/mobile/widgets/overlay.dart index 976d9bb73..b8fd8f653 100644 --- a/flutter/lib/mobile/widgets/overlay.dart +++ b/flutter/lib/mobile/widgets/overlay.dart @@ -2,11 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import '../../models/chat_model.dart'; -import '../../models/model.dart'; import '../pages/chat_page.dart'; -OverlayEntry? mobileActionsOverlayEntry; - class DraggableChatWindow extends StatelessWidget { DraggableChatWindow( {this.position = Offset.zero, @@ -99,6 +96,7 @@ class DraggableMobileActions extends StatelessWidget { this.onBackPressed, this.onRecentPressed, this.onHomePressed, + this.onHidePressed, required this.width, required this.height}); @@ -108,6 +106,7 @@ class DraggableMobileActions extends StatelessWidget { final VoidCallback? onBackPressed; final VoidCallback? onHomePressed; final VoidCallback? onRecentPressed; + final VoidCallback? onHidePressed; @override Widget build(BuildContext context) { @@ -118,89 +117,49 @@ class DraggableMobileActions extends StatelessWidget { builder: (_, onPanUpdate) { return GestureDetector( onPanUpdate: onPanUpdate, - child: Container( - decoration: BoxDecoration( - color: MyTheme.accent.withOpacity(0.4), - borderRadius: BorderRadius.all(Radius.circular(15))), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - IconButton( - color: MyTheme.white, - onPressed: onBackPressed, - icon: Icon(Icons.arrow_back)), - IconButton( - color: MyTheme.white, - onPressed: onHomePressed, - icon: Icon(Icons.home)), - IconButton( - color: MyTheme.white, - onPressed: onRecentPressed, - icon: Icon(Icons.more_horiz)), - VerticalDivider( - width: 0, - thickness: 2, - indent: 10, - endIndent: 10, + child: Card( + color: Colors.transparent, + shadowColor: Colors.transparent, + child: Container( + decoration: BoxDecoration( + color: MyTheme.accent.withOpacity(0.4), + borderRadius: BorderRadius.all(Radius.circular(15))), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + IconButton( + color: MyTheme.white, + onPressed: onBackPressed, + splashRadius: 20, + icon: const Icon(Icons.arrow_back)), + IconButton( + color: MyTheme.white, + onPressed: onHomePressed, + splashRadius: 20, + icon: const Icon(Icons.home)), + IconButton( + color: MyTheme.white, + onPressed: onRecentPressed, + splashRadius: 20, + icon: const Icon(Icons.more_horiz)), + const VerticalDivider( + width: 0, + thickness: 2, + indent: 10, + endIndent: 10, + ), + IconButton( + color: MyTheme.white, + onPressed: onHidePressed, + splashRadius: 20, + icon: const Icon(Icons.keyboard_arrow_down)), + ], ), - IconButton( - color: MyTheme.white, - onPressed: hideMobileActionsOverlay, - icon: Icon(Icons.keyboard_arrow_down)), - ], - ), - )); + ))); }); } } -resetMobileActionsOverlay() { - if (mobileActionsOverlayEntry == null) return; - hideMobileActionsOverlay(); - showMobileActionsOverlay(); -} - -showMobileActionsOverlay() { - if (mobileActionsOverlayEntry != null) return; - if (globalKey.currentContext == null || - globalKey.currentState == null || - globalKey.currentState!.overlay == null) return; - final globalOverlayState = globalKey.currentState!.overlay!; - - // compute overlay position - final screenW = MediaQuery.of(globalKey.currentContext!).size.width; - final screenH = MediaQuery.of(globalKey.currentContext!).size.height; - final double overlayW = 200; - final double overlayH = 45; - final left = (screenW - overlayW) / 2; - final top = screenH - overlayH - 80; - - final overlay = OverlayEntry(builder: (context) { - return DraggableMobileActions( - position: Offset(left, top), - width: overlayW, - height: overlayH, - onBackPressed: () => gFFI.tap(MouseButtons.right), - onHomePressed: () => gFFI.tap(MouseButtons.wheel), - onRecentPressed: () async { - gFFI.sendMouse('down', MouseButtons.wheel); - await Future.delayed(Duration(milliseconds: 500)); - gFFI.sendMouse('up', MouseButtons.wheel); - }, - ); - }); - globalOverlayState.insert(overlay); - mobileActionsOverlayEntry = overlay; -} - -hideMobileActionsOverlay() { - if (mobileActionsOverlayEntry != null) { - mobileActionsOverlayEntry!.remove(); - mobileActionsOverlayEntry = null; - return; - } -} - class Draggable extends StatefulWidget { Draggable( {this.checkKeyboard = false, diff --git a/flutter/lib/models/chat_model.dart b/flutter/lib/models/chat_model.dart index a9c791ef7..4bdf5826a 100644 --- a/flutter/lib/models/chat_model.dart +++ b/flutter/lib/models/chat_model.dart @@ -143,9 +143,12 @@ class ChatModel with ChangeNotifier { } toggleChatOverlay() { - if (chatIconOverlayEntry == null || chatWindowOverlayEntry == null) { + if ((!isDesktop && chatIconOverlayEntry == null) || + chatWindowOverlayEntry == null) { gFFI.invokeMethod("enable_soft_keyboard", true); - showChatIconOverlay(); + if (!isDesktop) { + showChatIconOverlay(); + } showChatWindowOverlay(); } else { hideChatIconOverlay(); diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index e96eb35a3..e907f3ded 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -22,7 +22,6 @@ import 'package:flutter_custom_cursor/flutter_custom_cursor.dart'; import '../common.dart'; import '../common/shared_state.dart'; import '../mobile/widgets/dialog.dart'; -import '../mobile/widgets/overlay.dart'; import 'peer_model.dart'; import 'platform_model.dart'; @@ -267,8 +266,10 @@ class FfiModel with ChangeNotifier { if (isPeerAndroid) { _touchMode = true; - if (parent.target?.ffiModel.permissions['keyboard'] != false) { - Timer(const Duration(milliseconds: 100), showMobileActionsOverlay); + if (parent.target != null && + parent.target!.ffiModel.permissions['keyboard'] != false) { + Timer(const Duration(milliseconds: 100), + parent.target!.dialogManager.showMobileActionsOverlay); } } else { _touchMode = From 121111b8648994c94d81cc03a91c445f2e1a45e5 Mon Sep 17 00:00:00 2001 From: csf Date: Wed, 7 Sep 2022 20:08:12 +0800 Subject: [PATCH 6/6] add flutter start_server & fix cm user environment from linux service --- src/core_main.rs | 12 ++++++++++-- src/platform/linux.rs | 27 +++++++++++++++++---------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/core_main.rs b/src/core_main.rs index c780a1cb0..02ac5e646 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -1,6 +1,6 @@ use hbb_common::log; -use crate::{start_os_service, flutter::connection_manager}; +use crate::{start_os_service, flutter::connection_manager, start_server}; /// Main entry of the RustDesk Core. /// Return true if the app should continue running with UI(possibly Flutter), false if the app should exit. @@ -20,7 +20,15 @@ pub fn core_main() -> bool { return false; } if args[1] == "--server" { - // TODO: server + log::info!("start --server"); + #[cfg(not(target_os = "macos"))] + { + start_server(true); + } + #[cfg(target_os = "macos")] + { + std::thread::spawn(move || start_server(true)); + } return false; } } diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 0ead52f31..fe2673832 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -525,20 +525,27 @@ pub fn is_root() -> bool { crate::username() == "root" } +fn is_opensuse() -> bool { + if let Ok(res) = run_cmds("cat /etc/os-release | grep opensuse".to_owned()) { + if !res.is_empty() { + return true; + } + } + false +} + pub fn run_as_user(arg: &str) -> ResultType> { let uid = get_active_userid(); let cmd = std::env::current_exe()?; + let xdg = &format!("XDG_RUNTIME_DIR=/run/user/{}", uid) as &str; + let username = &get_active_username(); + let mut args = vec![xdg, "-u", username, cmd.to_str().unwrap_or(""), arg]; // -E required for opensuse - let task = std::process::Command::new("sudo") - .args(vec![ - "-E", - &format!("XDG_RUNTIME_DIR=/run/user/{}", uid) as &str, - "-u", - &get_active_username(), - cmd.to_str().unwrap_or(""), - arg, - ]) - .spawn()?; + if is_opensuse() { + args.insert(0, "-E"); + } + + let task = std::process::Command::new("sudo").args(args).spawn()?; Ok(Some(task)) }