From 2301d093030abdb1ba6b7671e2c89974918dea44 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Wed, 26 Oct 2022 14:39:13 +0800 Subject: [PATCH] feat: replace forceAppUpdate with customed reloadWindow --- flutter/lib/common.dart | 28 ++ flutter/lib/consts.dart | 2 + .../lib/desktop/pages/desktop_home_page.dart | 3 + .../desktop/pages/desktop_setting_page.dart | 2 +- .../desktop/pages/file_manager_tab_page.dart | 4 +- .../desktop/pages/port_forward_tab_page.dart | 2 + .../lib/desktop/pages/remote_tab_page.dart | 2 + .../screen/desktop_file_transfer_screen.dart | 1 + .../screen/desktop_port_forward_screen.dart | 1 + .../desktop/screen/desktop_remote_screen.dart | 1 + .../lib/desktop/widgets/refresh_wrapper.dart | 41 +++ flutter/lib/main.dart | 241 +++++++++--------- flutter/lib/mobile/widgets/dialog.dart | 3 +- 13 files changed, 214 insertions(+), 117 deletions(-) create mode 100644 flutter/lib/desktop/widgets/refresh_wrapper.dart diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 8544fc240..8c927e8a1 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -9,6 +9,7 @@ import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart'; import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; import 'package:flutter_hbb/main.dart'; import 'package:flutter_hbb/models/peer_model.dart'; @@ -1338,3 +1339,30 @@ class SimpleWrapper { T get value => t; set value(T t) => this.t = t; } + +/// call this to reload current window. +/// +/// [Note] +/// Must have [RefreshWrapper] on the top of widget tree. +void reloadCurrentWindow() { + if (Get.context != null) { + // reload self window + RefreshWrapper.of(Get.context!)?.rebuild(); + } else { + debugPrint( + "reload current window failed, global BuildContext does not exist"); + } +} + +/// call this to reload all windows, including main + all sub windows. +Future reloadAllWindows() async { + reloadCurrentWindow(); + try { + final ids = await DesktopMultiWindow.getAllSubWindowIds(); + for (final id in ids) { + DesktopMultiWindow.invokeMethod(id, kWindowActionRebuild); + } + } on AssertionError { + // ignore + } +} diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 726ae24be..66aef10c0 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -9,6 +9,8 @@ const String kAppTypeDesktopRemote = "remote"; const String kAppTypeDesktopFileTransfer = "file transfer"; const String kAppTypeDesktopPortForward = "port forward"; +const String kWindowActionRebuild = "rebuild"; + const String kUniLinksPrefix = "rustdesk://"; const String kActionNewConnection = "connection/new/"; diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 7d2690626..b65525159 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -5,6 +5,7 @@ import 'dart:convert'; import 'package:flutter/material.dart' hide MenuItem; import 'package:flutter/services.dart'; import 'package:flutter_hbb/common.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/desktop/pages/connection_page.dart'; import 'package:flutter_hbb/desktop/pages/desktop_setting_page.dart'; import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart'; @@ -452,6 +453,8 @@ class _DesktopHomePageState extends State 'scaleFactor': screen.scaleFactor, }); } + } else if (call.method == kWindowActionRebuild) { + reloadCurrentWindow(); } }); Future.delayed(Duration.zero, () { diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 22247c033..709d4deda 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -406,7 +406,7 @@ class _GeneralState extends State<_General> { initialKey: currentKey, onChanged: (key) async { await bind.mainSetLocalOption(key: "lang", value: key); - Get.forceAppUpdate(); + reloadAllWindows(); bind.mainChangeLanguage(lang: key); }, ).marginOnly(left: _kContentHMargin); diff --git a/flutter/lib/desktop/pages/file_manager_tab_page.dart b/flutter/lib/desktop/pages/file_manager_tab_page.dart index 85a2ab197..68ad2529c 100644 --- a/flutter/lib/desktop/pages/file_manager_tab_page.dart +++ b/flutter/lib/desktop/pages/file_manager_tab_page.dart @@ -47,7 +47,7 @@ class _FileManagerTabPageState extends State { rustDeskWinManager.setMethodHandler((call, fromWindowId) async { print( - "call ${call.method} with args ${call.arguments} from window ${fromWindowId} to ${windowId()}"); + "[FileTransfer] call ${call.method} with args ${call.arguments} from window ${fromWindowId} to ${windowId()}"); // for simplify, just replace connectionId if (call.method == "new_file_transfer") { final args = jsonDecode(call.arguments); @@ -62,6 +62,8 @@ class _FileManagerTabPageState extends State { page: FileManagerPage(key: ValueKey(id), id: id))); } else if (call.method == "onDestroy") { tabController.clear(); + } else if (call.method == kWindowActionRebuild) { + reloadCurrentWindow(); } }); Future.delayed(Duration.zero, () { diff --git a/flutter/lib/desktop/pages/port_forward_tab_page.dart b/flutter/lib/desktop/pages/port_forward_tab_page.dart index 64a67121b..6d7390493 100644 --- a/flutter/lib/desktop/pages/port_forward_tab_page.dart +++ b/flutter/lib/desktop/pages/port_forward_tab_page.dart @@ -70,6 +70,8 @@ class _PortForwardTabPageState extends State { page: PortForwardPage(id: id, isRDP: isRDP))); } else if (call.method == "onDestroy") { tabController.clear(); + } else if (call.method == kWindowActionRebuild) { + reloadCurrentWindow(); } }); Future.delayed(Duration.zero, () { diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index ea0658b6e..b73dacec2 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -89,6 +89,8 @@ class _ConnectionTabPageState extends State { )))); } else if (call.method == "onDestroy") { tabController.clear(); + } else if (call.method == kWindowActionRebuild) { + reloadCurrentWindow(); } _update_remote_count(); }); diff --git a/flutter/lib/desktop/screen/desktop_file_transfer_screen.dart b/flutter/lib/desktop/screen/desktop_file_transfer_screen.dart index 694f18ace..74764a803 100644 --- a/flutter/lib/desktop/screen/desktop_file_transfer_screen.dart +++ b/flutter/lib/desktop/screen/desktop_file_transfer_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/desktop/pages/file_manager_tab_page.dart'; +import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart'; import 'package:provider/provider.dart'; /// multi-tab file transfer remote screen diff --git a/flutter/lib/desktop/screen/desktop_port_forward_screen.dart b/flutter/lib/desktop/screen/desktop_port_forward_screen.dart index c7c163a57..5cec10f86 100644 --- a/flutter/lib/desktop/screen/desktop_port_forward_screen.dart +++ b/flutter/lib/desktop/screen/desktop_port_forward_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/desktop/pages/port_forward_tab_page.dart'; +import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart'; import 'package:provider/provider.dart'; /// multi-tab file port forward screen diff --git a/flutter/lib/desktop/screen/desktop_remote_screen.dart b/flutter/lib/desktop/screen/desktop_remote_screen.dart index 1dcb426df..4d045d02b 100644 --- a/flutter/lib/desktop/screen/desktop_remote_screen.dart +++ b/flutter/lib/desktop/screen/desktop_remote_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/desktop/pages/remote_tab_page.dart'; +import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; diff --git a/flutter/lib/desktop/widgets/refresh_wrapper.dart b/flutter/lib/desktop/widgets/refresh_wrapper.dart new file mode 100644 index 000000000..4f2795d71 --- /dev/null +++ b/flutter/lib/desktop/widgets/refresh_wrapper.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hbb/main.dart'; +import 'package:get/get.dart'; + +class RefreshWrapper extends StatefulWidget { + final Widget Function(BuildContext context) builder; + const RefreshWrapper({super.key, required this.builder}); + + @override + State createState() => RefreshWrapperState(); + + static RefreshWrapperState? of(BuildContext context) { + final state = context.findAncestorStateOfType(); + if (state == null) { + debugPrint( + "RefreshWrapperState not exists in this context, perhaps RefreshWrapper is not exists?"); + } + return state; + } +} + +class RefreshWrapperState extends State { + @override + Widget build(BuildContext context) { + return widget.builder(context); + } + + rebuild() { + debugPrint("=====Global State Rebuild (win-${windowId ?? 'main'})====="); + if (Get.context != null) { + (context as Element).visitChildren(_rebuildElement); + } + setState(() {}); + } + + /// set root tree dirty to trigger global rebuild + void _rebuildElement(Element el) { + el.markNeedsBuild(); + el.visitChildren(_rebuildElement); + } +} diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 1b896c781..b3f74f930 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -9,6 +9,7 @@ import 'package:flutter_hbb/desktop/pages/install_page.dart'; import 'package:flutter_hbb/desktop/screen/desktop_file_transfer_screen.dart'; import 'package:flutter_hbb/desktop/screen/desktop_port_forward_screen.dart'; import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart'; +import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:get/get.dart'; @@ -121,40 +122,17 @@ void runMobileApp() async { void runRemoteScreen(Map argument) async { await initEnv(kAppTypeDesktopRemote); - runApp(GetMaterialApp( - navigatorKey: globalKey, - debugShowCheckedModeBanner: false, - title: 'RustDesk - Remote Desktop', - theme: MyTheme.lightTheme, - darkTheme: MyTheme.darkTheme, - themeMode: MyTheme.currentThemeMode(), - home: DesktopRemoteScreen( - params: argument, - ), - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: supportedLocales, - navigatorObservers: const [ - // FirebaseAnalyticsObserver(analytics: analytics), - ], - builder: _keepScaleBuilder(), - )); -} - -void runFileTransferScreen(Map argument) async { - await initEnv(kAppTypeDesktopFileTransfer); - runApp( - GetMaterialApp( + runApp(RefreshWrapper( + builder: (context) => GetMaterialApp( navigatorKey: globalKey, debugShowCheckedModeBanner: false, - title: 'RustDesk - File Transfer', + title: 'RustDesk - Remote Desktop', theme: MyTheme.lightTheme, darkTheme: MyTheme.darkTheme, themeMode: MyTheme.currentThemeMode(), - home: DesktopFileTransferScreen(params: argument), + home: DesktopRemoteScreen( + params: argument, + ), localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, @@ -166,31 +144,60 @@ void runFileTransferScreen(Map argument) async { ], builder: _keepScaleBuilder(), ), + )); +} + +void runFileTransferScreen(Map argument) async { + await initEnv(kAppTypeDesktopFileTransfer); + runApp( + RefreshWrapper( + builder: (context) => GetMaterialApp( + navigatorKey: globalKey, + debugShowCheckedModeBanner: false, + title: 'RustDesk - File Transfer', + theme: MyTheme.lightTheme, + darkTheme: MyTheme.darkTheme, + themeMode: MyTheme.currentThemeMode(), + home: DesktopFileTransferScreen(params: argument), + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: supportedLocales, + navigatorObservers: const [ + // FirebaseAnalyticsObserver(analytics: analytics), + ], + builder: _keepScaleBuilder(), + ), + ), ); } void runPortForwardScreen(Map argument) async { await initEnv(kAppTypeDesktopPortForward); runApp( - GetMaterialApp( - navigatorKey: globalKey, - debugShowCheckedModeBanner: false, - title: 'RustDesk - Port Forward', - theme: MyTheme.lightTheme, - darkTheme: MyTheme.darkTheme, - themeMode: MyTheme.currentThemeMode(), - home: DesktopPortForwardScreen(params: argument), - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: supportedLocales, - navigatorObservers: const [ - // FirebaseAnalyticsObserver(analytics: analytics), - ], - builder: _keepScaleBuilder(), - ), + RefreshWrapper(builder: (context) { + return GetMaterialApp( + navigatorKey: globalKey, + debugShowCheckedModeBanner: false, + title: 'RustDesk - Port Forward', + theme: MyTheme.lightTheme, + darkTheme: MyTheme.darkTheme, + themeMode: MyTheme.currentThemeMode(), + home: DesktopPortForwardScreen(params: argument), + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: supportedLocales, + navigatorObservers: const [ + // FirebaseAnalyticsObserver(analytics: analytics), + ], + builder: _keepScaleBuilder(), + ); + }), ); } @@ -199,19 +206,21 @@ void runConnectionManagerScreen() async { // initialize window WindowOptions windowOptions = getHiddenTitleBarWindowOptions(size: kConnectionManagerWindowSize); - runApp(GetMaterialApp( - debugShowCheckedModeBanner: false, - theme: MyTheme.lightTheme, - darkTheme: MyTheme.darkTheme, - themeMode: MyTheme.currentThemeMode(), - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: supportedLocales, - home: const DesktopServerPage(), - builder: _keepScaleBuilder())); + runApp(RefreshWrapper(builder: (context) { + return GetMaterialApp( + debugShowCheckedModeBanner: false, + theme: MyTheme.lightTheme, + darkTheme: MyTheme.darkTheme, + themeMode: MyTheme.currentThemeMode(), + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: supportedLocales, + home: const DesktopServerPage(), + builder: _keepScaleBuilder()); + })); windowManager.waitUntilReadyToShow(windowOptions, () async { await windowManager.show(); // ensure initial window size to be changed @@ -229,18 +238,20 @@ void runConnectionManagerScreen() async { void runInstallPage() async { await windowManager.ensureInitialized(); await initEnv(kAppTypeMain); - runApp(GetMaterialApp( - debugShowCheckedModeBanner: false, - theme: MyTheme.lightTheme, - themeMode: ThemeMode.light, - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: supportedLocales, - home: const InstallPage(), - builder: _keepScaleBuilder())); + runApp(RefreshWrapper( + builder: (context) => GetMaterialApp( + debugShowCheckedModeBanner: false, + theme: MyTheme.lightTheme, + themeMode: ThemeMode.light, + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: supportedLocales, + home: const InstallPage(), + builder: _keepScaleBuilder()), + )); windowManager.waitUntilReadyToShow( WindowOptions(size: Size(800, 600), center: true), () async { windowManager.show(); @@ -292,48 +303,50 @@ class _AppState extends State { @override Widget build(BuildContext context) { // final analytics = FirebaseAnalytics.instance; - return MultiProvider( - providers: [ - // global configuration - // use session related FFI when in remote control or file transfer page - ChangeNotifierProvider.value(value: gFFI.ffiModel), - ChangeNotifierProvider.value(value: gFFI.imageModel), - ChangeNotifierProvider.value(value: gFFI.cursorModel), - ChangeNotifierProvider.value(value: gFFI.canvasModel), - ], - child: GetMaterialApp( - navigatorKey: globalKey, - debugShowCheckedModeBanner: false, - title: 'RustDesk', - theme: MyTheme.lightTheme, - darkTheme: MyTheme.darkTheme, - themeMode: MyTheme.currentThemeMode(), - home: isDesktop - ? const DesktopTabPage() - : !isAndroid - ? WebHomePage() - : HomePage(), - navigatorObservers: const [ - // FirebaseAnalyticsObserver(analytics: analytics), + return RefreshWrapper(builder: (context) { + return MultiProvider( + providers: [ + // global configuration + // use session related FFI when in remote control or file transfer page + ChangeNotifierProvider.value(value: gFFI.ffiModel), + ChangeNotifierProvider.value(value: gFFI.imageModel), + ChangeNotifierProvider.value(value: gFFI.cursorModel), + ChangeNotifierProvider.value(value: gFFI.canvasModel), ], - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: supportedLocales, - builder: isAndroid - ? (context, child) => AccessibilityListener( - child: MediaQuery( - data: MediaQuery.of(context).copyWith( - textScaleFactor: 1.0, + child: GetMaterialApp( + navigatorKey: globalKey, + debugShowCheckedModeBanner: false, + title: 'RustDesk', + theme: MyTheme.lightTheme, + darkTheme: MyTheme.darkTheme, + themeMode: MyTheme.currentThemeMode(), + home: isDesktop + ? const DesktopTabPage() + : !isAndroid + ? WebHomePage() + : HomePage(), + navigatorObservers: const [ + // FirebaseAnalyticsObserver(analytics: analytics), + ], + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: supportedLocales, + builder: isAndroid + ? (context, child) => AccessibilityListener( + child: MediaQuery( + data: MediaQuery.of(context).copyWith( + textScaleFactor: 1.0, + ), + child: child ?? Container(), ), - child: child ?? Container(), - ), - ) - : _keepScaleBuilder(), - ), - ); + ) + : _keepScaleBuilder(), + ), + ); + }); } } @@ -357,7 +370,7 @@ _registerEventHandler() { } }); platformFFI.registerEventHandler('language', 'language', (_) async { - Get.forceAppUpdate(); + reloadAllWindows(); }); } } diff --git a/flutter/lib/mobile/widgets/dialog.dart b/flutter/lib/mobile/widgets/dialog.dart index ca82cbed9..03b36ecf3 100644 --- a/flutter/lib/mobile/widgets/dialog.dart +++ b/flutter/lib/mobile/widgets/dialog.dart @@ -6,7 +6,8 @@ import '../../models/model.dart'; import '../../models/platform_model.dart'; void clientClose(OverlayDialogManager dialogManager) { - msgBox('', 'Close', 'Are you sure to close the connection?', '', dialogManager); + msgBox( + '', 'Close', 'Are you sure to close the connection?', '', dialogManager); } void showSuccess() {