diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 3b026141d..cabd91b9e 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -4,10 +4,10 @@ import 'dart:io'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/instance_manager.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:window_manager/window_manager.dart'; +import 'package:back_button_interceptor/back_button_interceptor.dart'; import 'models/model.dart'; import 'models/platform_model.dart'; @@ -26,10 +26,6 @@ int androidVersion = 0; typedef F = String Function(String); typedef FMethod = String Function(String, dynamic); -class Translator { - static late F call; -} - class MyTheme { MyTheme._(); @@ -71,44 +67,12 @@ final ButtonStyle flatButtonStyle = TextButton.styleFrom( ), ); -void showToast(String text, {Duration? duration}) { - SmartDialog.showToast(text, displayTime: duration); -} - -void showLoading(String text, {bool clickMaskDismiss = false}) { - SmartDialog.dismiss(); - SmartDialog.showLoading( - clickMaskDismiss: false, - builder: (context) { - return Container( - color: MyTheme.white, - constraints: BoxConstraints(maxWidth: 240), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox(height: 30), - Center(child: CircularProgressIndicator()), - SizedBox(height: 20), - Center( - child: Text(Translator.call(text), - style: TextStyle(fontSize: 15))), - SizedBox(height: 20), - Center( - child: TextButton( - style: flatButtonStyle, - onPressed: () { - SmartDialog.dismiss(); - backToHome(); - }, - child: Text(Translator.call('Cancel'), - style: TextStyle(color: MyTheme.accent)))) - ])); - }); -} - -backToHome() { - Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/")); +backToHomePage() { + if (isAndroid || isIOS) { + Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/")); + } else { + // TODO desktop + } } void window_on_top(int? id) { @@ -127,51 +91,140 @@ void window_on_top(int? id) { typedef DialogBuilder = CustomAlertDialog Function( StateSetter setState, void Function([dynamic]) close); -class DialogManager { - static int _tag = 0; +class Dialog { + OverlayEntry? entry; + Completer completer = Completer(); - static dismissByTag(String tag, [result]) { - SmartDialog.dismiss(tag: tag, result: result); + Dialog(); + + void complete(T? res) { + try { + if (!completer.isCompleted) { + completer.complete(res); + } + entry?.remove(); + } catch (e) { + debugPrint("Dialog complete catch error: $e"); + } + } +} + +class OverlayDialogManager { + OverlayState? _overlayState; + Map _dialogs = Map(); + int _tagCount = 0; + + /// By default OverlayDialogManager use global overlay + OverlayDialogManager() { + _overlayState = globalKey.currentState?.overlay; } - static Future show(DialogBuilder builder, + void setOverlayState(OverlayState? overlayState) { + _overlayState = overlayState; + } + + void dismissAll() { + _dialogs.forEach((key, value) { + value.complete(null); + BackButtonInterceptor.removeByName(key); + }); + _dialogs.clear(); + } + + void dismissByTag(String tag) { + _dialogs[tag]?.complete(null); + _dialogs.remove(tag); + BackButtonInterceptor.removeByName(tag); + } + + // TODO clickMaskDismiss + Future show(DialogBuilder builder, {bool clickMaskDismiss = false, bool backDismiss = false, String? tag, - bool useAnimation = true}) async { - final t; - if (tag != null) { - t = tag; - } else { - _tag += 1; - t = _tag.toString(); + bool useAnimation = true, + bool forceGlobal = false}) { + final overlayState = + forceGlobal ? globalKey.currentState?.overlay : _overlayState; + + if (overlayState == null) { + return Future.error( + "[OverlayDialogManager] Failed to show dialog, _overlayState is null, call [setOverlayState] first"); } - SmartDialog.dismiss(status: SmartStatus.allToast); - SmartDialog.dismiss(status: SmartStatus.loading); + + final _tag; + if (tag != null) { + _tag = tag; + } else { + _tag = _tagCount.toString(); + _tagCount++; + } + + final dialog = Dialog(); + _dialogs[_tag] = dialog; + final close = ([res]) { - SmartDialog.dismiss(tag: t, result: res); + _dialogs.remove(_tag); + dialog.complete(res); + BackButtonInterceptor.removeByName(_tag); }; - final res = await SmartDialog.show( - tag: t, - clickMaskDismiss: clickMaskDismiss, - backDismiss: backDismiss, - useAnimation: useAnimation, - builder: (_) => StatefulBuilder( - builder: (_, setState) => builder(setState, close))); - return res; + dialog.entry = OverlayEntry(builder: (_) { + return Container( + color: Colors.transparent, + child: StatefulBuilder( + builder: (_, setState) => builder(setState, close))); + }); + overlayState.insert(dialog.entry!); + BackButtonInterceptor.add((stopDefaultButtonEvent, routeInfo) { + if (backDismiss) { + close(); + } + return true; + }, name: _tag); + return dialog.completer.future; + } + + void showLoading(String text, + {bool clickMaskDismiss = false, bool cancelToClose = false}) { + show((setState, close) => CustomAlertDialog( + content: Container( + color: MyTheme.white, + constraints: BoxConstraints(maxWidth: 240), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 30), + Center(child: CircularProgressIndicator()), + SizedBox(height: 20), + Center( + child: Text(translate(text), + style: TextStyle(fontSize: 15))), + SizedBox(height: 20), + Center( + child: TextButton( + style: flatButtonStyle, + onPressed: () { + dismissAll(); + if (cancelToClose) backToHomePage(); + }, + child: Text(translate('Cancel'), + style: TextStyle(color: MyTheme.accent)))) + ])))); + } + + void showToast(String text) { + // TODO } } class CustomAlertDialog extends StatelessWidget { CustomAlertDialog( - {required this.title, - required this.content, - required this.actions, - this.contentPadding}); + {this.title, required this.content, this.actions, this.contentPadding}); - final Widget title; + final Widget? title; final Widget content; - final List actions; + final List? actions; final double? contentPadding; @override @@ -187,7 +240,9 @@ class CustomAlertDialog extends StatelessWidget { } } -void msgBox(String type, String title, String text, {bool? hasCancel}) { +void msgBox( + String type, String title, String text, OverlayDialogManager dialogManager, + {bool? hasCancel}) { var wrap = (String text, void Function() onPressed) => ButtonTheme( padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -198,17 +253,17 @@ void msgBox(String type, String title, String text, {bool? hasCancel}) { child: TextButton( style: flatButtonStyle, onPressed: onPressed, - child: Text(Translator.call(text), - style: TextStyle(color: MyTheme.accent)))); + child: + Text(translate(text), style: TextStyle(color: MyTheme.accent)))); - SmartDialog.dismiss(); + dialogManager.dismissAll(); List buttons = []; if (type != "connecting" && type != "success" && type.indexOf("nook") < 0) { buttons.insert( 0, - wrap(Translator.call('OK'), () { - SmartDialog.dismiss(); - backToHome(); + wrap(translate('OK'), () { + dialogManager.dismissAll(); + backToHomePage(); })); } if (hasCancel == null) { @@ -220,21 +275,21 @@ void msgBox(String type, String title, String text, {bool? hasCancel}) { if (hasCancel) { buttons.insert( 0, - wrap(Translator.call('Cancel'), () { - SmartDialog.dismiss(); + wrap(translate('Cancel'), () { + dialogManager.dismissAll(); })); } // TODO: test this button if (type.indexOf("hasclose") >= 0) { buttons.insert( 0, - wrap(Translator.call('Close'), () { - SmartDialog.dismiss(); + wrap(translate('Close'), () { + dialogManager.dismissAll(); })); } - DialogManager.show((setState, close) => CustomAlertDialog( + dialogManager.show((setState, close) => CustomAlertDialog( title: Text(translate(title), style: TextStyle(fontSize: 21)), - content: Text(Translator.call(text), style: TextStyle(fontSize: 15)), + content: Text(translate(text), style: TextStyle(fontSize: 15)), actions: buttons)); } diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 182f1d0b4..c07df87e9 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -625,7 +625,7 @@ class _ConnectionPageState extends State { var field = ""; var msg = ""; var isInProgress = false; - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate("Add ID")), content: Column( @@ -698,7 +698,7 @@ class _ConnectionPageState extends State { var field = ""; var msg = ""; var isInProgress = false; - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate("Add Tag")), content: Column( @@ -769,7 +769,7 @@ class _ConnectionPageState extends State { final tags = List.of(gFFI.abModel.tags); var selectedTag = gFFI.abModel.getPeerTags(id).obs; - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate("Edit Tag")), content: Column( @@ -884,16 +884,16 @@ class _WebMenuState extends State { }, onSelected: (value) { if (value == 'server') { - showServerSettings(); + showServerSettings(gFFI.dialogManager); } if (value == 'about') { - showAbout(); + showAbout(gFFI.dialogManager); } if (value == 'login') { if (username == null) { - showLogin(); + showLogin(gFFI.dialogManager); } else { - logout(); + logout(gFFI.dialogManager); } } if (value == 'scan') { diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 9c4e84391..f68cdac94 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -116,7 +116,7 @@ class _DesktopHomePageState extends State onDoubleTap: () { Clipboard.setData( ClipboardData(text: model.serverId.text)); - showToast(translate("Copied")); + gFFI.dialogManager.showToast(translate("Copied")); }, child: TextFormField( controller: model.serverId, @@ -253,7 +253,7 @@ class _DesktopHomePageState extends State kUsePermanentPassword) { Clipboard.setData( ClipboardData(text: model.serverPasswd.text)); - showToast(translate("Copied")); + gFFI.dialogManager.showToast(translate("Copied")); } }, child: TextFormField( @@ -604,7 +604,7 @@ class _DesktopHomePageState extends State var newId = ""; var msg = ""; var isInProgress = false; - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate("Change ID")), content: Column( @@ -690,7 +690,7 @@ class _DesktopHomePageState extends State var key = oldOptions['key'] ?? ""; var isInProgress = false; - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate("ID/Relay Server")), content: ConstrainedBox( @@ -891,7 +891,7 @@ class _DesktopHomePageState extends State var newWhiteListField = newWhiteList.join('\n'); var msg = ""; var isInProgress = false; - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate("IP Whitelisting")), content: Column( @@ -980,7 +980,7 @@ class _DesktopHomePageState extends State } var isInProgress = false; - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate("Socks5 Proxy")), content: ConstrainedBox( @@ -1117,7 +1117,7 @@ class _DesktopHomePageState extends State final license = await bind.mainGetLicense(); final version = await bind.mainGetVersion(); final linkStyle = TextStyle(decoration: TextDecoration.underline); - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text("About $appName"), content: ConstrainedBox( @@ -1208,7 +1208,7 @@ Future loginDialog() async { var isInProgress = false; var completer = Completer(); - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate("Login")), content: ConstrainedBox( @@ -1339,7 +1339,7 @@ void setPasswordDialog() async { var errMsg0 = ""; var errMsg1 = ""; - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate("Set Password")), content: ConstrainedBox( diff --git a/flutter/lib/desktop/pages/file_manager_page.dart b/flutter/lib/desktop/pages/file_manager_page.dart index 22d46c146..e5279a7e2 100644 --- a/flutter/lib/desktop/pages/file_manager_page.dart +++ b/flutter/lib/desktop/pages/file_manager_page.dart @@ -4,7 +4,6 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/mobile/pages/file_manager_page.dart'; import 'package:flutter_hbb/models/file_model.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; import 'package:wakelock/wakelock.dart'; @@ -26,8 +25,7 @@ class _FileManagerPageState extends State final _localSelectedItems = SelectedItems(); final _remoteSelectedItems = SelectedItems(); - /// FFI with name file_transfer_id - FFI get _ffi => ffi('ft_${widget.id}'); + late FFI _ffi; FileModel get model => _ffi.fileModel; @@ -38,8 +36,9 @@ class _FileManagerPageState extends State @override void initState() { super.initState(); - Get.put(FFI()..connect(widget.id, isFileTransfer: true), - tag: 'ft_${widget.id}'); + _ffi = FFI(); + _ffi.connect(widget.id, isFileTransfer: true); + Get.put(_ffi, tag: 'ft_${widget.id}'); // _ffi.ffiModel.updateEventListener(widget.id); if (!Platform.isLinux) { Wakelock.enable(); @@ -51,7 +50,7 @@ class _FileManagerPageState extends State void dispose() { model.onClose(); _ffi.close(); - SmartDialog.dismiss(); + _ffi.dialogManager.dismissAll(); if (!Platform.isLinux) { Wakelock.disable(); } @@ -552,7 +551,7 @@ class _FileManagerPageState extends State IconButton( onPressed: () { final name = TextEditingController(); - DialogManager.show((setState, close) => + _ffi.dialogManager.show((setState, close) => CustomAlertDialog( title: Text(translate("Create Folder")), content: Column( diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 01744e8e7..d81adb3d9 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -7,9 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/mobile/widgets/gesture_help.dart'; import 'package:flutter_hbb/models/chat_model.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -import 'package:get/route_manager.dart'; import 'package:provider/provider.dart'; import 'package:wakelock/wakelock.dart'; @@ -51,18 +49,19 @@ class _RemotePageState extends State var _showEdit = false; // use soft keyboard var _isPhysicalMouse = false; - FFI get _ffi => ffi(widget.id); + late FFI _ffi; @override void initState() { super.initState(); - var ffitmp = FFI(); - ffitmp.canvasModel.tabBarHeight = super.widget.tabBarHeight; - final ffi = Get.put(ffitmp, tag: widget.id); - ffi.connect(widget.id, tabBarHeight: super.widget.tabBarHeight); + _ffi = FFI(); + _ffi.canvasModel.tabBarHeight = super.widget.tabBarHeight; + Get.put(_ffi, tag: widget.id); + _ffi.connect(widget.id, tabBarHeight: super.widget.tabBarHeight); WidgetsBinding.instance.addPostFrameCallback((_) { SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); - showLoading(translate('Connecting...')); + _ffi.dialogManager + .showLoading(translate('Connecting...'), cancelToClose: true); _interval = Timer.periodic(Duration(milliseconds: 30), (timer) => interval()); }); @@ -70,8 +69,8 @@ class _RemotePageState extends State Wakelock.enable(); } _physicalFocusNode.requestFocus(); - ffi.ffiModel.updateEventListener(widget.id); - ffi.listenToMouse(true); + _ffi.ffiModel.updateEventListener(widget.id); + _ffi.listenToMouse(true); // WindowManager.instance.addListener(this); } @@ -86,7 +85,7 @@ class _RemotePageState extends State _ffi.close(); _interval?.cancel(); _timer?.cancel(); - SmartDialog.dismiss(); + _ffi.dialogManager.dismissAll(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); if (!Platform.isLinux) { @@ -262,8 +261,11 @@ class _RemotePageState extends State initialEntries: [ OverlayEntry(builder: (context) { _ffi.chatModel.setOverlayState(Overlay.of(context)); + _ffi.dialogManager.setOverlayState(Overlay.of(context)); return Container( - child: getRawPointerAndKeyBody(getBodyForDesktop(keyboard))); + color: Colors.black, + child: getRawPointerAndKeyBody( + getBodyForDesktop(context, keyboard))); }) ], )); @@ -275,7 +277,7 @@ class _RemotePageState extends State _ffi.canvasModel.tabBarHeight = super.widget.tabBarHeight; return WillPopScope( onWillPop: () async { - clientClose(); + clientClose(_ffi.dialogManager); return false; }, child: MultiProvider( @@ -410,7 +412,7 @@ class _RemotePageState extends State color: Colors.white, icon: Icon(Icons.clear), onPressed: () { - clientClose(); + clientClose(_ffi.dialogManager); }, ) ] + @@ -420,7 +422,7 @@ class _RemotePageState extends State icon: Icon(Icons.tv), onPressed: () { setState(() => _showEdit = false); - showOptions(widget.id); + showOptions(widget.id, _ffi.dialogManager); }, ) ] + @@ -497,7 +499,7 @@ class _RemotePageState extends State /// DoubleFiner -> right click /// HoldDrag -> left drag - Widget getBodyForDesktop(bool keyboard) { + Widget getBodyForDesktop(BuildContext context, bool keyboard) { var paints = [ MouseRegion(onEnter: (evt) { bind.hostStopSystemKeyPropagate(stopped: false); @@ -567,7 +569,7 @@ class _RemotePageState extends State style: flatButtonStyle, onPressed: () { Navigator.pop(context); - showSetOSPassword(widget.id, false); + showSetOSPassword(widget.id, false, _ffi.dialogManager); }, child: Icon(Icons.edit, color: MyTheme.accent), ) @@ -632,7 +634,7 @@ class _RemotePageState extends State if (password != null) { bind.sessionInputOsPassword(id: widget.id, value: password); } else { - showSetOSPassword(widget.id, true); + showSetOSPassword(widget.id, true, _ffi.dialogManager); } } else if (value == 'reset_canvas') { _ffi.cursorModel.reset(); @@ -889,7 +891,7 @@ class ImagePainter extends CustomPainter { } } -void showOptions(String id) async { +void showOptions(String id, OverlayDialogManager dialogManager) async { String quality = await bind.getSessionImageQuality(id: id) ?? 'balanced'; if (quality == '') quality = 'balanced'; String viewStyle = @@ -907,7 +909,7 @@ void showOptions(String id) async { onTap: () { if (i == cur) return; bind.sessionSwitchDisplay(id: id, value: i); - SmartDialog.dismiss(); + dialogManager.dismissAll(); }, child: Ink( width: 40, @@ -932,7 +934,7 @@ void showOptions(String id) async { } final perms = ffi(id).ffiModel.permissions; - DialogManager.show((setState, close) { + dialogManager.show((setState, close) { final more = []; if (perms['audio'] != false) { more.add(getToggle(id, setState, 'disable-audio', 'Mute')); @@ -990,12 +992,13 @@ void showOptions(String id) async { }, clickMaskDismiss: true, backDismiss: true); } -void showSetOSPassword(String id, bool login) async { +void showSetOSPassword( + String id, bool login, OverlayDialogManager dialogManager) async { final controller = TextEditingController(); var password = await bind.getSessionOption(id: id, arg: "os-password") ?? ""; var autoLogin = await bind.getSessionOption(id: id, arg: "auto-login") != ""; controller.text = password; - DialogManager.show((setState, close) { + dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate('OS Password')), content: Column(mainAxisSize: MainAxisSize.min, children: [ diff --git a/flutter/lib/desktop/screen/desktop_file_transfer_screen.dart b/flutter/lib/desktop/screen/desktop_file_transfer_screen.dart index 03230b0b0..694f18ace 100644 --- a/flutter/lib/desktop/screen/desktop_file_transfer_screen.dart +++ b/flutter/lib/desktop/screen/desktop_file_transfer_screen.dart @@ -1,7 +1,6 @@ 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_smart_dialog/flutter_smart_dialog.dart'; import 'package:provider/provider.dart'; /// multi-tab file transfer remote screen diff --git a/flutter/lib/desktop/screen/desktop_remote_screen.dart b/flutter/lib/desktop/screen/desktop_remote_screen.dart index 95f6abed5..4e941ed7c 100644 --- a/flutter/lib/desktop/screen/desktop_remote_screen.dart +++ b/flutter/lib/desktop/screen/desktop_remote_screen.dart @@ -1,7 +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_smart_dialog/flutter_smart_dialog.dart'; import 'package:provider/provider.dart'; /// multi-tab desktop remote screen diff --git a/flutter/lib/desktop/widgets/peercard_widget.dart b/flutter/lib/desktop/widgets/peercard_widget.dart index 87cfa2a59..85e6e20e6 100644 --- a/flutter/lib/desktop/widgets/peercard_widget.dart +++ b/flutter/lib/desktop/widgets/peercard_widget.dart @@ -258,7 +258,7 @@ class _PeerCardState extends State<_PeerCard> final tags = List.of(gFFI.abModel.tags); var selectedTag = gFFI.abModel.getPeerTags(id).obs; - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate("Edit Tag")), content: Column( @@ -314,7 +314,7 @@ class _PeerCardState extends State<_PeerCard> } } final k = GlobalKey(); - DialogManager.show((setState, close) { + gFFI.dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate("Rename")), content: Column( diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 000202f65..dd6ccd31d 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -5,7 +5,6 @@ import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart'; import 'package:flutter_hbb/desktop/screen/desktop_file_transfer_screen.dart'; import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:get/route_manager.dart'; import 'package:provider/provider.dart'; @@ -95,14 +94,7 @@ void runRemoteScreen(Map argument) async { ), navigatorObservers: [ // FirebaseAnalyticsObserver(analytics: analytics), - FlutterSmartDialog.observer ], - builder: FlutterSmartDialog.init( - builder: isAndroid - ? (_, child) => AccessibilityListener( - child: child, - ) - : null), )); } @@ -116,14 +108,7 @@ void runFileTransferScreen(Map argument) async { home: DesktopFileTransferScreen(params: argument), navigatorObservers: [ // FirebaseAnalyticsObserver(analytics: analytics), - FlutterSmartDialog.observer - ], - builder: FlutterSmartDialog.init( - builder: isAndroid - ? (_, child) => AccessibilityListener( - child: child, - ) - : null))); + ])); } class App extends StatelessWidget { @@ -153,14 +138,12 @@ class App extends StatelessWidget { : HomePage(), navigatorObservers: [ // FirebaseAnalyticsObserver(analytics: analytics), - FlutterSmartDialog.observer ], - builder: FlutterSmartDialog.init( - builder: isAndroid - ? (_, child) => AccessibilityListener( - child: child, - ) - : null)), + builder: isAndroid + ? (_, child) => AccessibilityListener( + child: child, + ) + : null), ); } } diff --git a/flutter/lib/mobile/pages/connection_page.dart b/flutter/lib/mobile/pages/connection_page.dart index 227bfb630..ba34b31e8 100644 --- a/flutter/lib/mobile/pages/connection_page.dart +++ b/flutter/lib/mobile/pages/connection_page.dart @@ -380,16 +380,16 @@ class _WebMenuState extends State { }, onSelected: (value) { if (value == 'server') { - showServerSettings(); + showServerSettings(gFFI.dialogManager); } if (value == 'about') { - showAbout(); + showAbout(gFFI.dialogManager); } if (value == 'login') { if (username == null) { - showLogin(); + showLogin(gFFI.dialogManager); } else { - logout(); + logout(gFFI.dialogManager); } } if (value == 'scan') { diff --git a/flutter/lib/mobile/pages/file_manager_page.dart b/flutter/lib/mobile/pages/file_manager_page.dart index 9a8d0088a..9c8fd92c4 100644 --- a/flutter/lib/mobile/pages/file_manager_page.dart +++ b/flutter/lib/mobile/pages/file_manager_page.dart @@ -3,13 +3,11 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_breadcrumb/flutter_breadcrumb.dart'; import 'package:flutter_hbb/models/file_model.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:provider/provider.dart'; import 'package:toggle_switch/toggle_switch.dart'; import 'package:wakelock/wakelock.dart'; import '../../common.dart'; -import '../../models/model.dart'; import '../widgets/dialog.dart'; class FileManagerPage extends StatefulWidget { @@ -29,7 +27,10 @@ class _FileManagerPageState extends State { void initState() { super.initState(); gFFI.connect(widget.id, isFileTransfer: true); - showLoading(translate('Connecting...')); + WidgetsBinding.instance.addPostFrameCallback((_) { + gFFI.dialogManager + .showLoading(translate('Connecting...'), cancelToClose: true); + }); gFFI.ffiModel.updateEventListener(widget.id); Wakelock.enable(); } @@ -38,7 +39,7 @@ class _FileManagerPageState extends State { void dispose() { model.onClose(); gFFI.close(); - SmartDialog.dismiss(); + gFFI.dialogManager.dismissAll(); Wakelock.disable(); super.dispose(); } @@ -60,7 +61,9 @@ class _FileManagerPageState extends State { backgroundColor: MyTheme.grayBg, appBar: AppBar( leading: Row(children: [ - IconButton(icon: Icon(Icons.close), onPressed: clientClose), + IconButton( + icon: Icon(Icons.close), + onPressed: () => clientClose(gFFI.dialogManager)), ]), centerTitle: true, title: ToggleSwitch( @@ -141,8 +144,8 @@ class _FileManagerPageState extends State { model.toggleSelectMode(); } else if (v == "folder") { final name = TextEditingController(); - DialogManager.show( - (setState, close) => CustomAlertDialog( + gFFI.dialogManager + .show((setState, close) => CustomAlertDialog( title: Text(translate("Create Folder")), content: Column( mainAxisSize: MainAxisSize.min, diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 69bf11de0..14bdfa833 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/mobile/widgets/gesture_help.dart'; import 'package:flutter_hbb/models/chat_model.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:provider/provider.dart'; import 'package:wakelock/wakelock.dart'; @@ -51,7 +50,8 @@ class _RemotePageState extends State { gFFI.connect(widget.id); WidgetsBinding.instance.addPostFrameCallback((_) { SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); - showLoading(translate('Connecting...')); + gFFI.dialogManager + .showLoading(translate('Connecting...'), cancelToClose: true); _interval = Timer.periodic(Duration(milliseconds: 30), (timer) => interval()); }); @@ -71,7 +71,7 @@ class _RemotePageState extends State { gFFI.close(); _interval?.cancel(); _timer?.cancel(); - SmartDialog.dismiss(); + gFFI.dialogManager.dismissAll(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); Wakelock.disable(); @@ -226,7 +226,7 @@ class _RemotePageState extends State { return WillPopScope( onWillPop: () async { - clientClose(); + clientClose(gFFI.dialogManager); return false; }, child: getRawPointerAndKeyBody( @@ -401,7 +401,7 @@ class _RemotePageState extends State { color: Colors.white, icon: Icon(Icons.clear), onPressed: () { - clientClose(); + clientClose(gFFI.dialogManager); }, ) ] + @@ -411,7 +411,7 @@ class _RemotePageState extends State { icon: Icon(Icons.tv), onPressed: () { setState(() => _showEdit = false); - showOptions(widget.id); + showOptions(widget.id, gFFI.dialogManager); }, ) ] + @@ -671,7 +671,7 @@ class _RemotePageState extends State { style: flatButtonStyle, onPressed: () { Navigator.pop(context); - showSetOSPassword(id, false); + showSetOSPassword(id, false, gFFI.dialogManager); }, child: Icon(Icons.edit, color: MyTheme.accent), ) @@ -739,12 +739,12 @@ class _RemotePageState extends State { if (password != null) { bind.sessionInputOsPassword(id: widget.id, value: password); } else { - showSetOSPassword(id, true); + showSetOSPassword(id, true, gFFI.dialogManager); } } else if (value == 'reset_canvas') { gFFI.cursorModel.reset(); } else if (value == 'restart') { - showRestartRemoteDevice(pi, widget.id); + showRestartRemoteDevice(pi, widget.id, gFFI.dialogManager); } }(); } @@ -1008,7 +1008,7 @@ class QualityMonitor extends StatelessWidget { : SizedBox.shrink()))); } -void showOptions(String id) async { +void showOptions(String id, OverlayDialogManager dialogManager) async { String quality = await bind.getSessionImageQuality(id: id) ?? 'balanced'; if (quality == '') quality = 'balanced'; String viewStyle = @@ -1026,7 +1026,7 @@ void showOptions(String id) async { onTap: () { if (i == cur) return; bind.sessionSwitchDisplay(id: id, value: i); - SmartDialog.dismiss(); + gFFI.dialogManager.dismissAll(); }, child: Ink( width: 40, @@ -1051,7 +1051,7 @@ void showOptions(String id) async { } final perms = gFFI.ffiModel.permissions; - DialogManager.show((setState, close) { + dialogManager.show((setState, close) { final more = []; if (perms['audio'] != false) { more.add(getToggle(id, setState, 'disable-audio', 'Mute')); @@ -1107,9 +1107,10 @@ void showOptions(String id) async { }, clickMaskDismiss: true, backDismiss: true); } -void showRestartRemoteDevice(PeerInfo pi, String id) async { +void showRestartRemoteDevice( + PeerInfo pi, String id, OverlayDialogManager dialogManager) async { final res = - await DialogManager.show((setState, close) => CustomAlertDialog( + await dialogManager.show((setState, close) => CustomAlertDialog( title: Row(children: [ Icon(Icons.warning_amber_sharp, color: Colors.redAccent, size: 28), @@ -1128,12 +1129,13 @@ void showRestartRemoteDevice(PeerInfo pi, String id) async { if (res == true) bind.sessionRestartRemoteDevice(id: id); } -void showSetOSPassword(String id, bool login) async { +void showSetOSPassword( + String id, bool login, OverlayDialogManager dialogManager) async { final controller = TextEditingController(); var password = await bind.getSessionOption(id: id, arg: "os-password") ?? ""; var autoLogin = await bind.getSessionOption(id: id, arg: "auto-login") != ""; controller.text = password; - DialogManager.show((setState, close) { + dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate('OS Password')), content: Column(mainAxisSize: MainAxisSize.min, children: [ diff --git a/flutter/lib/mobile/pages/scan_page.dart b/flutter/lib/mobile/pages/scan_page.dart index 54ba44892..4325d0570 100644 --- a/flutter/lib/mobile/pages/scan_page.dart +++ b/flutter/lib/mobile/pages/scan_page.dart @@ -63,7 +63,7 @@ class _ScanPageState extends State { var result = reader.decode(bitmap); showServerSettingFromQr(result.text); } catch (e) { - showToast('No QR code found'); + gFFI.dialogManager.showToast('No QR code found'); } } }), @@ -121,7 +121,7 @@ class _ScanPageState extends State { void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) { if (!p) { - showToast('No permisssion'); + gFFI.dialogManager.showToast('No permisssion'); } } @@ -132,10 +132,10 @@ class _ScanPageState extends State { } void showServerSettingFromQr(String data) async { - backToHome(); + backToHomePage(); await controller?.pauseCamera(); if (!data.startsWith('config=')) { - showToast('Invalid QR code'); + gFFI.dialogManager.showToast('Invalid QR code'); return; } try { @@ -144,16 +144,16 @@ class _ScanPageState extends State { var key = values['key'] != null ? values['key'] as String : ''; var api = values['api'] != null ? values['api'] as String : ''; Timer(Duration(milliseconds: 60), () { - showServerSettingsWithValue(host, '', key, api); + showServerSettingsWithValue(host, '', key, api, gFFI.dialogManager); }); } catch (e) { - showToast('Invalid QR code'); + gFFI.dialogManager.showToast('Invalid QR code'); } } } -void showServerSettingsWithValue( - String id, String relay, String key, String api) async { +void showServerSettingsWithValue(String id, String relay, String key, + String api, OverlayDialogManager dialogManager) async { Map oldOptions = jsonDecode(await bind.mainGetOptions()); String id0 = oldOptions['custom-rendezvous-server'] ?? ""; String relay0 = oldOptions['relay-server'] ?? ""; @@ -168,7 +168,7 @@ void showServerSettingsWithValue( String? relayServerMsg; String? apiServerMsg; - DialogManager.show((setState, close) { + dialogManager.show((setState, close) { Future validate() async { if (idController.text != id) { final res = await validateAsync(idController.text); diff --git a/flutter/lib/mobile/pages/server_page.dart b/flutter/lib/mobile/pages/server_page.dart index d3dc4109d..f19a011b6 100644 --- a/flutter/lib/mobile/pages/server_page.dart +++ b/flutter/lib/mobile/pages/server_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_hbb/mobile/widgets/dialog.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:provider/provider.dart'; import '../../common.dart'; @@ -90,9 +89,9 @@ class ServerPage extends StatefulWidget implements PageShape { if (value == "changeID") { // TODO } else if (value == "setPermanentPassword") { - setPermanentPasswordDialog(); + setPermanentPasswordDialog(gFFI.dialogManager); } else if (value == "setTemporaryPasswordLength") { - setTemporaryPasswordLengthDialog(); + setTemporaryPasswordLengthDialog(gFFI.dialogManager); } else if (value == kUsePermanentPassword || value == kUseTemporaryPassword || value == kUseBothPasswords) { @@ -522,7 +521,7 @@ void toAndroidChannelInit() { switch (method) { case "start_capture": { - SmartDialog.dismiss(); + gFFI.dialogManager.dismissAll(); gFFI.serverModel.updateClientState(); break; } diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index 4b8760413..3a1f8b352 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -119,8 +119,8 @@ class _SettingsState extends State with WidgetsBindingObserver { if (v) { PermissionManager.request("ignore_battery_optimizations"); } else { - final res = await DialogManager.show( - (setState, close) => CustomAlertDialog( + final res = await gFFI.dialogManager + .show((setState, close) => CustomAlertDialog( title: Text(translate("Open System Setting")), content: Text(translate( "android_open_battery_optimizations_tip")), @@ -153,9 +153,9 @@ class _SettingsState extends State with WidgetsBindingObserver { leading: Icon(Icons.person), onPressed: (context) { if (username == null) { - showLogin(); + showLogin(gFFI.dialogManager); } else { - logout(); + logout(gFFI.dialogManager); } }, ), @@ -166,13 +166,13 @@ class _SettingsState extends State with WidgetsBindingObserver { title: Text(translate('ID/Relay Server')), leading: Icon(Icons.cloud), onPressed: (context) { - showServerSettings(); + showServerSettings(gFFI.dialogManager); }), SettingsTile.navigation( title: Text(translate('Language')), leading: Icon(Icons.translate), onPressed: (context) { - showLanguageSettings(); + showLanguageSettings(gFFI.dialogManager); }) ]), SettingsSection( @@ -204,20 +204,20 @@ class _SettingsState extends State with WidgetsBindingObserver { } } -void showServerSettings() async { +void showServerSettings(OverlayDialogManager dialogManager) async { Map options = jsonDecode(await bind.mainGetOptions()); String id = options['custom-rendezvous-server'] ?? ""; String relay = options['relay-server'] ?? ""; String api = options['api-server'] ?? ""; String key = options['key'] ?? ""; - showServerSettingsWithValue(id, relay, key, api); + showServerSettingsWithValue(id, relay, key, api, dialogManager); } -void showLanguageSettings() async { +void showLanguageSettings(OverlayDialogManager dialogManager) async { try { final langs = json.decode(await bind.mainGetLangs()) as List; var lang = await bind.mainGetLocalOption(key: "lang"); - DialogManager.show((setState, close) { + dialogManager.show((setState, close) { final setLang = (v) { if (lang != v) { setState(() { @@ -246,8 +246,8 @@ void showLanguageSettings() async { } catch (_e) {} } -void showAbout() { - DialogManager.show((setState, close) { +void showAbout(OverlayDialogManager dialogManager) { + dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate('About') + ' RustDesk'), content: Wrap(direction: Axis.vertical, spacing: 12, children: [ @@ -350,7 +350,7 @@ void refreshCurrentUser() async { } } -void logout() async { +void logout(OverlayDialogManager dialogManager) async { final token = await bind.mainGetOption(key: "access_token"); if (token == '') return; final url = getUrl(); @@ -363,7 +363,7 @@ void logout() async { }, body: json.encode(body)); } catch (e) { - showToast('Failed to access $url'); + dialogManager.showToast('Failed to access $url'); } resetToken(); } @@ -396,12 +396,12 @@ Future getUrl() async { return url; } -void showLogin() { +void showLogin(OverlayDialogManager dialogManager) { final passwordController = TextEditingController(); final nameController = TextEditingController(); var loading = false; var error = ''; - DialogManager.show((setState, close) { + dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate('Login')), content: Column(mainAxisSize: MainAxisSize.min, children: [ diff --git a/flutter/lib/mobile/widgets/dialog.dart b/flutter/lib/mobile/widgets/dialog.dart index ddd6816fb..075fa5bd9 100644 --- a/flutter/lib/mobile/widgets/dialog.dart +++ b/flutter/lib/mobile/widgets/dialog.dart @@ -1,32 +1,31 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import '../../common.dart'; import '../../models/platform_model.dart'; -void clientClose() { - msgBox('', 'Close', 'Are you sure to close the connection?'); +void clientClose(OverlayDialogManager dialogManager) { + msgBox('', 'Close', 'Are you sure to close the connection?', dialogManager); } const SEC1 = Duration(seconds: 1); void showSuccess({Duration duration = SEC1}) { - SmartDialog.dismiss(); - showToast(translate("Successful"), duration: SEC1); + // TODO + // showToast(translate("Successful"), duration: SEC1); } void showError({Duration duration = SEC1}) { - SmartDialog.dismiss(); - showToast(translate("Error"), duration: SEC1); + // TODO + // showToast(translate("Error"), duration: SEC1); } -void setPermanentPasswordDialog() async { +void setPermanentPasswordDialog(OverlayDialogManager dialogManager) async { final pw = await bind.mainGetPermanentPassword(); final p0 = TextEditingController(text: pw); final p1 = TextEditingController(text: pw); var validateLength = false; var validateSame = false; - DialogManager.show((setState, close) { + dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate('Set your own password')), content: Form( @@ -86,7 +85,7 @@ void setPermanentPasswordDialog() async { onPressed: (validateLength && validateSame) ? () async { close(); - showLoading(translate("Waiting")); + dialogManager.showLoading(translate("Waiting")); if (await gFFI.serverModel.setPermanentPassword(p0.text)) { showSuccess(); } else { @@ -101,13 +100,14 @@ void setPermanentPasswordDialog() async { }); } -void setTemporaryPasswordLengthDialog() async { +void setTemporaryPasswordLengthDialog( + OverlayDialogManager dialogManager) async { List lengths = ['6', '8', '10']; String length = await bind.mainGetOption(key: "temporary-password-length"); var index = lengths.indexOf(length); if (index < 0) index = 0; length = lengths[index]; - DialogManager.show((setState, close) { + dialogManager.show((setState, close) { final setLength = (newValue) { final oldValue = length; if (oldValue == newValue) return; @@ -133,10 +133,11 @@ void setTemporaryPasswordLengthDialog() async { }, backDismiss: true, clickMaskDismiss: true); } -void enterPasswordDialog(String id) async { +void enterPasswordDialog(String id, OverlayDialogManager dialogManager) async { final controller = TextEditingController(); var remember = await bind.getSessionRemember(id: id) ?? false; - DialogManager.show((setState, close) { + dialogManager.dismissAll(); + dialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate('Password Required')), content: Column(mainAxisSize: MainAxisSize.min, children: [ @@ -161,7 +162,7 @@ void enterPasswordDialog(String id) async { style: flatButtonStyle, onPressed: () { close(); - backToHome(); + backToHomePage(); }, child: Text(translate('Cancel')), ), @@ -172,7 +173,8 @@ void enterPasswordDialog(String id) async { if (text == '') return; gFFI.login(id, text, remember); close(); - showLoading(translate('Logging in...')); + dialogManager.showLoading(translate('Logging in...'), + cancelToClose: true); }, child: Text(translate('OK')), ), @@ -181,8 +183,8 @@ void enterPasswordDialog(String id) async { }); } -void wrongPasswordDialog(String id) { - DialogManager.show((setState, close) => CustomAlertDialog( +void wrongPasswordDialog(String id, OverlayDialogManager dialogManager) { + dialogManager.show((setState, close) => CustomAlertDialog( title: Text(translate('Wrong Password')), content: Text(translate('Do you want to enter again?')), actions: [ @@ -190,14 +192,14 @@ void wrongPasswordDialog(String id) { style: flatButtonStyle, onPressed: () { close(); - backToHome(); + backToHomePage(); }, child: Text(translate('Cancel')), ), TextButton( style: flatButtonStyle, onPressed: () { - enterPasswordDialog(id); + enterPasswordDialog(id, dialogManager); }, child: Text(translate('Retry')), ), @@ -239,8 +241,8 @@ class _PasswordWidgetState extends State { //This will obscure text dynamically keyboardType: TextInputType.visiblePassword, decoration: InputDecoration( - labelText: Translator.call('Password'), - hintText: Translator.call('Enter your password'), + labelText: translate('Password'), + hintText: translate('Enter your password'), // Here is key idea suffixIcon: IconButton( icon: Icon( diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index 75f3f8045..74be258a0 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -4,7 +4,6 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/mobile/pages/file_manager_page.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:path/path.dart' as Path; @@ -126,9 +125,9 @@ class FileModel extends ChangeNotifier { final _jobResultListener = JobResultListener>(); - final WeakReference _ffi; + final WeakReference parent; - FileModel(this._ffi); + FileModel(this.parent); toggleSelectMode() { if (jobState == JobState.inProgress) { @@ -275,7 +274,7 @@ class FileModel extends ChangeNotifier { need_override = true; } bind.sessionSetConfirmOverrideFile( - id: _ffi.target?.id ?? "", + id: parent.target?.id ?? "", actId: id, fileNum: int.parse(evt['file_num']), needOverride: need_override, @@ -292,22 +291,22 @@ class FileModel extends ChangeNotifier { onReady() async { _localOption.home = await bind.mainGetHomeDir(); _localOption.showHidden = (await bind.sessionGetPeerOption( - id: _ffi.target?.id ?? "", name: "local_show_hidden")) + id: parent.target?.id ?? "", name: "local_show_hidden")) .isNotEmpty; _remoteOption.showHidden = (await bind.sessionGetPeerOption( - id: _ffi.target?.id ?? "", name: "remote_show_hidden")) + id: parent.target?.id ?? "", name: "remote_show_hidden")) .isNotEmpty; - _remoteOption.isWindows = _ffi.target?.ffiModel.pi.platform == "Windows"; + _remoteOption.isWindows = parent.target?.ffiModel.pi.platform == "Windows"; - debugPrint("remote platform: ${_ffi.target?.ffiModel.pi.platform}"); + debugPrint("remote platform: ${parent.target?.ffiModel.pi.platform}"); await Future.delayed(Duration(milliseconds: 100)); final local = (await bind.sessionGetPeerOption( - id: _ffi.target?.id ?? "", name: "local_dir")); + id: parent.target?.id ?? "", name: "local_dir")); final remote = (await bind.sessionGetPeerOption( - id: _ffi.target?.id ?? "", name: "remote_dir")); + id: parent.target?.id ?? "", name: "remote_dir")); openDirectory(local.isEmpty ? _localOption.home : local, isLocal: true); openDirectory(remote.isEmpty ? _remoteOption.home : remote, isLocal: false); await Future.delayed(Duration(seconds: 1)); @@ -318,11 +317,11 @@ class FileModel extends ChangeNotifier { openDirectory(_remoteOption.home, isLocal: false); } // load last transfer jobs - await bind.sessionLoadLastTransferJobs(id: '${_ffi.target?.id}'); + await bind.sessionLoadLastTransferJobs(id: '${parent.target?.id}'); } onClose() { - SmartDialog.dismiss(); + parent.target?.dialogManager.dismissAll(); jobReset(); // save config @@ -332,7 +331,7 @@ class FileModel extends ChangeNotifier { msgMap["local_show_hidden"] = _localOption.showHidden ? "Y" : ""; msgMap["remote_dir"] = _currentRemoteDir.path; msgMap["remote_show_hidden"] = _remoteOption.showHidden ? "Y" : ""; - final id = _ffi.target?.id ?? ""; + final id = parent.target?.id ?? ""; for (final msg in msgMap.entries) { bind.sessionPeerOption(id: id, name: msg.key, value: msg.value); } @@ -419,7 +418,7 @@ class FileModel extends ChangeNotifier { ..id = jobId ..isRemote = isRemote); bind.sessionSendFiles( - id: '${_ffi.target?.id}', + id: '${parent.target?.id}', actId: _jobId, path: from.path, to: PathUtil.join(toPath, from.name, isWindows), @@ -477,14 +476,14 @@ class FileModel extends ChangeNotifier { entries = [item]; } else if (item.isDirectory) { title = translate("Not an empty directory"); - showLoading(translate("Waiting")); + parent.target?.dialogManager.showLoading(translate("Waiting")); final fd = await _fileFetcher.fetchDirectoryRecursive( _jobId, item.path, items.isLocal!, true); if (fd.path.isEmpty) { fd.path = item.path; } fd.format(isWindows); - SmartDialog.dismiss(); + parent.target?.dialogManager.dismissAll(); if (fd.entries.isEmpty) { final confirm = await showRemoveDialog( translate( @@ -543,7 +542,7 @@ class FileModel extends ChangeNotifier { Future showRemoveDialog( String title, String content, bool showCheckbox) async { - return await DialogManager.show( + return await parent.target?.dialogManager.show( (setState, Function(bool v) close) => CustomAlertDialog( title: Row( children: [ @@ -594,7 +593,7 @@ class FileModel extends ChangeNotifier { Future showFileConfirmDialog( String title, String content, bool showCheckbox) async { fileConfirmCheckboxRemember = false; - return await DialogManager.show( + return await parent.target?.dialogManager.show( (setState, Function(bool? v) close) => CustomAlertDialog( title: Row( children: [ @@ -648,7 +647,7 @@ class FileModel extends ChangeNotifier { sendRemoveFile(String path, int fileNum, bool isLocal) { bind.sessionRemoveFile( - id: '${_ffi.target?.id}', + id: '${parent.target?.id}', actId: _jobId, path: path, isRemote: !isLocal, @@ -657,7 +656,7 @@ class FileModel extends ChangeNotifier { sendRemoveEmptyDir(String path, int fileNum, bool isLocal) { bind.sessionRemoveAllEmptyDirs( - id: '${_ffi.target?.id}', + id: '${parent.target?.id}', actId: _jobId, path: path, isRemote: !isLocal); @@ -667,14 +666,14 @@ class FileModel extends ChangeNotifier { isLocal = isLocal ?? this.isLocal; _jobId++; bind.sessionCreateDir( - id: '${_ffi.target?.id}', + id: '${parent.target?.id}', actId: _jobId, path: path, isRemote: !isLocal); } cancelJob(int id) async { - bind.sessionCancelJob(id: '${_ffi.target?.id}', actId: id); + bind.sessionCancelJob(id: '${parent.target?.id}', actId: id); jobReset(); } @@ -701,7 +700,7 @@ class FileModel extends ChangeNotifier { } initFileFetcher() { - _fileFetcher.id = _ffi.target?.id; + _fileFetcher.id = parent.target?.id; } void updateFolderFiles(Map evt) { @@ -742,7 +741,7 @@ class FileModel extends ChangeNotifier { ..state = JobState.paused; jobTable.add(jobProgress); bind.sessionAddJob( - id: '${_ffi.target?.id}', + id: '${parent.target?.id}', isRemote: isRemote, includeHidden: showHidden, actId: currJobId, @@ -757,7 +756,7 @@ class FileModel extends ChangeNotifier { if (jobIndex != -1) { final job = jobTable[jobIndex]; bind.sessionResumeJob( - id: '${_ffi.target?.id}', actId: job.id, isRemote: job.isRemote); + id: '${parent.target?.id}', actId: job.id, isRemote: job.isRemote); job.state = JobState.inProgress; } else { debugPrint("jobId ${jobId} is not exists"); diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 4f295e377..a52947c74 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -13,7 +13,6 @@ import 'package:flutter_hbb/models/chat_model.dart'; import 'package:flutter_hbb/models/file_model.dart'; import 'package:flutter_hbb/models/server_model.dart'; import 'package:flutter_hbb/models/user_model.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tuple/tuple.dart'; @@ -60,7 +59,6 @@ class FfiModel with ChangeNotifier { } FfiModel(this.parent) { - Translator.call = translate; clear(); } @@ -261,32 +259,35 @@ class FfiModel with ChangeNotifier { /// Handle the message box event based on [evt] and [id]. void handleMsgBox(Map evt, String id) { + if (parent.target == null) return; + final dialogManager = parent.target!.dialogManager; var type = evt['type']; var title = evt['title']; var text = evt['text']; if (type == 're-input-password') { - wrongPasswordDialog(id); + wrongPasswordDialog(id, dialogManager); } else if (type == 'input-password') { - enterPasswordDialog(id); + enterPasswordDialog(id, dialogManager); } else if (type == 'restarting') { - showMsgBox(id, type, title, text, false, hasCancel: false); + showMsgBox(id, type, title, text, false, dialogManager, hasCancel: false); } else { var hasRetry = evt['hasRetry'] == 'true'; - showMsgBox(id, type, title, text, hasRetry); + showMsgBox(id, type, title, text, hasRetry, dialogManager); } } /// Show a message box with [type], [title] and [text]. - void showMsgBox( - String id, String type, String title, String text, bool hasRetry, + void showMsgBox(String id, String type, String title, String text, + bool hasRetry, OverlayDialogManager dialogManager, {bool? hasCancel}) { - msgBox(type, title, text, hasCancel: hasCancel); + msgBox(type, title, text, dialogManager, hasCancel: hasCancel); _timer?.cancel(); if (hasRetry) { _timer = Timer(Duration(seconds: _reconnects), () { bind.sessionReconnect(id: id); clearPermissions(); - showLoading(translate('Connecting...')); + dialogManager.showLoading(translate('Connecting...'), + cancelToClose: true); }); _reconnects *= 2; } else { @@ -296,7 +297,7 @@ class FfiModel with ChangeNotifier { /// Handle the peer info event based on [evt]. void handlePeerInfo(Map evt, String peerId) async { - SmartDialog.dismiss(); + parent.target?.dialogManager.dismissAll(); _pi.version = evt['version']; _pi.username = evt['username']; _pi.hostname = evt['hostname']; @@ -332,7 +333,9 @@ class FfiModel with ChangeNotifier { _display = _pi.displays[_pi.currentDisplay]; } if (displays.length > 0) { - showLoading(translate('Connected, waiting for image...')); + parent.target?.dialogManager.showLoading( + translate('Connected, waiting for image...'), + cancelToClose: true); _waitForImage = true; _reconnects = 1; } @@ -364,7 +367,7 @@ class ImageModel with ChangeNotifier { void onRgba(Uint8List rgba, double tabBarHeight) { if (_waitForImage) { _waitForImage = false; - SmartDialog.dismiss(); + parent.target?.dialogManager.dismissAll(); } final pid = parent.target?.id; ui.decodeImageFromPixels( @@ -874,16 +877,20 @@ class FFI { var alt = false; var command = false; var version = ""; - late final ImageModel imageModel; - late final FfiModel ffiModel; - late final CursorModel cursorModel; - late final CanvasModel canvasModel; - late final ServerModel serverModel; - late final ChatModel chatModel; - late final FileModel fileModel; - late final AbModel abModel; - late final UserModel userModel; - late final QualityMonitorModel qualityMonitorModel; + + /// dialogManager use late to ensure init after main page binding [globalKey] + late final dialogManager = OverlayDialogManager(); + + late final ImageModel imageModel; // session + late final FfiModel ffiModel; // session + late final CursorModel cursorModel; // session + late final CanvasModel canvasModel; // session + late final ServerModel serverModel; // global + late final ChatModel chatModel; // session + late final FileModel fileModel; // session + late final AbModel abModel; // global + late final UserModel userModel; // global + late final QualityMonitorModel qualityMonitorModel; // session FFI() { this.imageModel = ImageModel(WeakReference(this)); diff --git a/flutter/lib/models/native_model.dart b/flutter/lib/models/native_model.dart index a55ed1d29..55f2d0e79 100644 --- a/flutter/lib/models/native_model.dart +++ b/flutter/lib/models/native_model.dart @@ -75,7 +75,7 @@ class PlatformFFI { } String translate(String name, String locale) { - if (_translate == null) return ''; + if (_translate == null) return name; var a = name.toNativeUtf8(); var b = locale.toNativeUtf8(); var p = _translate!(a, b); diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index d59ad49c2..6ed048dd4 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -10,7 +10,7 @@ import '../common.dart'; import '../mobile/pages/server_page.dart'; import 'model.dart'; -const loginDialogTag = "LOGIN"; +const KLoginDialogTag = "LOGIN"; const kUseTemporaryPassword = "use-temporary-password"; const kUsePermanentPassword = "use-permanent-password"; @@ -206,8 +206,8 @@ class ServerModel with ChangeNotifier { /// Toggle the screen sharing service. toggleService() async { if (_isStart) { - final res = - await DialogManager.show((setState, close) => CustomAlertDialog( + final res = await parent.target?.dialogManager + .show((setState, close) => CustomAlertDialog( title: Row(children: [ Icon(Icons.warning_amber_sharp, color: Colors.redAccent, size: 28), @@ -228,8 +228,8 @@ class ServerModel with ChangeNotifier { stopService(); } } else { - final res = - await DialogManager.show((setState, close) => CustomAlertDialog( + final res = await parent.target?.dialogManager + .show((setState, close) => CustomAlertDialog( title: Row(children: [ Icon(Icons.warning_amber_sharp, color: Colors.redAccent, size: 28), @@ -272,7 +272,7 @@ class ServerModel with ChangeNotifier { Future stopService() async { _isStart = false; // TODO - parent.target?.serverModel.closeAll(); + closeAll(); await parent.target?.invokeMethod("stop_service"); await bind.mainStopService(); notifyListeners(); @@ -370,7 +370,7 @@ class ServerModel with ChangeNotifier { } void showLoginDialog(Client client) { - DialogManager.show( + parent.target?.dialogManager.show( (setState, close) => CustomAlertDialog( title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -442,7 +442,7 @@ class ServerModel with ChangeNotifier { void onClientAuthorized(Map evt) { try { final client = Client.fromJson(jsonDecode(evt['client'])); - DialogManager.dismissByTag(getLoginDialogTag(client.id)); + parent.target?.dialogManager.dismissByTag(getLoginDialogTag(client.id)); _clients[client.id] = client; scrollToBottom(); notifyListeners(); @@ -454,7 +454,7 @@ class ServerModel with ChangeNotifier { final id = int.parse(evt['id'] as String); if (_clients.containsKey(id)) { _clients.remove(id); - DialogManager.dismissByTag(getLoginDialogTag(id)); + parent.target?.dialogManager.dismissByTag(getLoginDialogTag(id)); parent.target?.invokeMethod("cancel_notification", id); } notifyListeners(); @@ -510,11 +510,11 @@ class Client { } String getLoginDialogTag(int id) { - return loginDialogTag + id.toString(); + return KLoginDialogTag + id.toString(); } showInputWarnAlert(FFI ffi) { - DialogManager.show((setState, close) => CustomAlertDialog( + ffi.dialogManager.show((setState, close) => CustomAlertDialog( title: Text(translate("How to get Android input permission?")), content: Column( mainAxisSize: MainAxisSize.min, diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index 6bcf5a159..e0a7aa8eb 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -5,239 +5,246 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "44.0.0" after_layout: dependency: transitive description: name: after_layout - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.2.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "4.4.0" animations: dependency: transitive description: name: animations - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.3" archive: dependency: transitive description: name: archive - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.3.1" args: dependency: transitive description: name: args - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.3.1" async: dependency: transitive description: name: async - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.8.2" + back_button_interceptor: + dependency: "direct main" + description: + name: back_button_interceptor + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.1" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" build: dependency: transitive description: name: build - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.3.0" build_config: dependency: transitive description: name: build_config - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.1.0" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.1.0" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.9" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.2.0" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "7.2.3" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "8.4.0" cached_network_image: dependency: transitive description: name: cached_network_image - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.2.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" characters: dependency: transitive description: name: characters - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.2.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.3.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.1" clock: dependency: transitive description: name: clock - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.1.0" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "4.2.0" collection: dependency: transitive description: name: collection - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.16.0" contextmenu: dependency: "direct main" description: name: contextmenu - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.0.0" convert: dependency: transitive description: name: convert - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.0.2" cross_file: dependency: transitive description: name: cross_file - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.3.3+1" crypto: dependency: transitive description: name: crypto - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.0.2" csslib: dependency: transitive description: name: csslib - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.17.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.5" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.2.3" dash_chat_2: dependency: "direct main" description: name: dash_chat_2 - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.0.12" desktop_multi_window: dependency: "direct main" description: path: "." - ref: bbe24b8af079a756f2d39158dd2034127f0e1c73 - resolved-ref: bbe24b8af079a756f2d39158dd2034127f0e1c73 + ref: c53879e9ce4ed038af393a02bf2c7084ad4b53aa + resolved-ref: c53879e9ce4ed038af393a02bf2c7084ad4b53aa url: "https://github.com/Kingtous/rustdesk_desktop_multi_window" source: git version: "0.1.0" @@ -245,133 +252,133 @@ packages: dependency: "direct main" description: name: device_info_plus - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "4.0.2" device_info_plus_linux: dependency: transitive description: name: device_info_plus_linux - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.1" device_info_plus_macos: dependency: transitive description: name: device_info_plus_macos - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.2.3" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.4.0" device_info_plus_web: dependency: transitive description: name: device_info_plus_web - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" device_info_plus_windows: dependency: transitive description: name: device_info_plus_windows - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.0.2" draggable_float_widget: dependency: "direct main" description: name: draggable_float_widget - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.0.2" event_bus: dependency: transitive description: name: event_bus - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.0" external_path: dependency: "direct main" description: name: external_path - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.3.0" ffi: dependency: "direct main" description: name: ffi - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.1" file: dependency: transitive description: name: file - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "6.1.2" firebase_analytics: dependency: "direct main" description: name: firebase_analytics - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "9.3.0" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.3.0" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.4.2" firebase_core: dependency: transitive description: name: firebase_core - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.20.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "4.5.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.7.1" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" flutter: @@ -383,42 +390,42 @@ packages: dependency: transitive description: name: flutter_blurhash - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.7.0" flutter_breadcrumb: dependency: "direct main" description: name: flutter_breadcrumb - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" flutter_cache_manager: dependency: transitive description: name: flutter_cache_manager - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.3.0" flutter_launcher_icons: dependency: "direct dev" description: name: flutter_launcher_icons - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.9.3" flutter_parsed_text: dependency: transitive description: name: flutter_parsed_text - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.2.1" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.7" flutter_rust_bridge: @@ -430,13 +437,6 @@ packages: url: "https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge" source: git version: "1.32.0" - flutter_smart_dialog: - dependency: "direct main" - description: - name: flutter_smart_dialog - url: "https://pub.flutter-io.cn" - source: hosted - version: "4.5.4+1" flutter_test: dependency: "direct dev" description: flutter @@ -451,476 +451,476 @@ packages: dependency: "direct dev" description: name: freezed - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0+1" freezed_annotation: dependency: "direct main" description: name: freezed_annotation - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.3" get: dependency: "direct main" description: name: get - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "4.6.5" glob: dependency: transitive description: name: glob - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" graphs: dependency: transitive description: name: graphs - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" html: dependency: transitive description: name: html - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.15.0" http: dependency: "direct main" description: name: http - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.13.5" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "4.0.1" image: dependency: "direct main" description: name: image - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.2.0" image_picker: dependency: "direct main" description: name: image_picker - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.8.5+3" image_picker_android: dependency: transitive description: name: image_picker_android - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.8.5+2" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.8" image_picker_ios: dependency: transitive description: name: image_picker_ios - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.8.5+6" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.6.1" intl: dependency: transitive description: name: intl - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.17.0" io: dependency: transitive description: name: io - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.3" js: dependency: transitive description: name: js - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.6.4" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "4.6.0" logging: dependency: transitive description: name: logging - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.2" matcher: dependency: transitive description: name: matcher - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.12.11" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.1.4" menu_base: dependency: transitive description: name: menu_base - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.1.1" meta: dependency: transitive description: name: meta - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.7.0" mime: dependency: transitive description: name: mime - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.2" nested: dependency: transitive description: name: nested - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.0" octo_image: dependency: transitive description: name: octo_image - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.2" package_config: dependency: transitive description: name: package_config - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" package_info_plus: dependency: "direct main" description: name: package_info_plus - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.4.3" package_info_plus_linux: dependency: transitive description: name: package_info_plus_linux - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.5" package_info_plus_macos: dependency: transitive description: name: package_info_plus_macos - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.3.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.2" package_info_plus_web: dependency: transitive description: name: package_info_plus_web - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.5" package_info_plus_windows: dependency: transitive description: name: package_info_plus_windows - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.0" path: dependency: transitive description: name: path - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.8.1" path_provider: dependency: "direct main" description: name: path_provider - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.11" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.17" path_provider_ios: dependency: transitive description: name: path_provider_ios - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.11" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.7" path_provider_macos: dependency: transitive description: name: path_provider_macos - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.6" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.4" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.2" pedantic: dependency: transitive description: name: pedantic - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.11.1" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "5.0.0" platform: dependency: transitive description: name: platform - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.2" pool: dependency: transitive description: name: pool - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.5.1" process: dependency: transitive description: name: process - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "4.2.4" provider: dependency: "direct main" description: name: provider - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "6.0.3" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.1" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.2.0" qr_code_scanner: dependency: "direct main" description: name: qr_code_scanner - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.0" quiver: dependency: transitive description: name: quiver - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.1.0" rxdart: dependency: transitive description: name: rxdart - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.27.5" screen_retriever: dependency: transitive description: name: screen_retriever - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.1.2" settings_ui: dependency: "direct main" description: name: settings_ui - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.2" shared_preferences: dependency: "direct main" description: name: shared_preferences - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.15" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.12" shared_preferences_ios: dependency: transitive description: name: shared_preferences_ios - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.1" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.1" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.4" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.4" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.1" shelf: dependency: transitive description: name: shelf - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.3.2" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.2" shortid: dependency: transitive description: name: shortid - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.1.2" sky_engine: @@ -932,280 +932,280 @@ packages: dependency: transitive description: name: source_gen - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.2.2" source_span: dependency: transitive description: name: source_span - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.8.2" sqflite: dependency: transitive description: name: sqflite - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.3+1" sqflite_common: dependency: transitive description: name: sqflite_common - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.2.1+1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.1.0" synchronized: dependency: transitive description: name: synchronized - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.0.0+2" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.2.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.4.9" timing: dependency: transitive description: name: timing - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.0" toggle_switch: dependency: "direct main" description: name: toggle_switch - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.4.0" tray_manager: dependency: "direct main" description: name: tray_manager - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.1.7" tuple: dependency: "direct main" description: name: tuple - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.0" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.3.1" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "6.1.5" url_launcher_android: dependency: transitive description: name: url_launcher_android - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "6.0.17" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "6.0.17" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.0.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.0.1" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" url_launcher_web: dependency: transitive description: name: url_launcher_web - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.13" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.0.1" uuid: dependency: transitive description: name: uuid - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.0.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.2" video_player: dependency: transitive description: name: video_player - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.4.6" video_player_android: dependency: transitive description: name: video_player_android - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.3.8" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.3.5" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "5.1.4" video_player_web: dependency: transitive description: name: video_player_web - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.12" visibility_detector: dependency: "direct main" description: name: visibility_detector - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.3.3" wakelock: dependency: "direct main" description: name: wakelock - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.5.6" wakelock_macos: dependency: transitive description: name: wakelock_macos - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.4.0" wakelock_platform_interface: dependency: transitive description: name: wakelock_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.3.0" wakelock_web: dependency: transitive description: name: wakelock_web - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.4.0" wakelock_windows: dependency: transitive description: name: wakelock_windows - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.2.0" watcher: dependency: transitive description: name: watcher - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.2.0" win32: dependency: transitive description: name: win32 - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.7.0" window_manager: @@ -1221,28 +1221,28 @@ packages: dependency: transitive description: name: xdg_directories - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.2.0+1" xml: dependency: transitive description: name: xml - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "6.1.0" yaml: dependency: transitive description: name: yaml - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.1.1" zxing2: dependency: "direct main" description: name: zxing2 - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.1.0" sdks: diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 4ecce228a..b8b9580fb 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -49,7 +49,7 @@ dependencies: zxing2: ^0.1.0 image_picker: ^0.8.5 image: ^3.1.3 - flutter_smart_dialog: ^4.3.1 + back_button_interceptor: ^6.0.1 flutter_rust_bridge: git: url: https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge