From 034d825b7449b93ab5cbeb2c96ff6e954e2e5ded Mon Sep 17 00:00:00 2001 From: csf Date: Mon, 28 Feb 2022 16:11:21 +0800 Subject: [PATCH] add DialogManager --- lib/common.dart | 66 ++++++------ lib/home_page.dart | 122 +++++++++++----------- lib/model.dart | 8 +- lib/remote_page.dart | 235 +++++++++++++++++++++---------------------- lib/server_page.dart | 30 +++--- 5 files changed, 226 insertions(+), 235 deletions(-) diff --git a/lib/common.dart b/lib/common.dart index afbaa1083..2cf3a9a24 100644 --- a/lib/common.dart +++ b/lib/common.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'dart:async'; import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_hbb/main.dart'; import 'package:tuple/tuple.dart'; typedef F = String Function(String); @@ -32,34 +33,36 @@ final ButtonStyle flatButtonStyle = TextButton.styleFrom( ), ); -void showLoading(String text, BuildContext? context) { - if (_hasDialog && context != null) { - Navigator.pop(context); - _hasDialog = false; - } - dismissLoading(); +void showLoading(String text) { + DialogManager.reset(); + EasyLoading.dismiss(); EasyLoading.show(status: text, maskType: EasyLoadingMaskType.black); } -void dismissLoading() { - EasyLoading.dismiss(); +class DialogManager{ + static BuildContext? _dialogContext; + + static void reset(){ + if(_dialogContext!=null){ + Navigator.pop(_dialogContext!); + } + _dialogContext = null; + } + static void register(BuildContext dialogContext){ + _dialogContext = dialogContext; + } } -bool _hasDialog = false; - -typedef BuildAlertDailog = Tuple3> Function( +typedef BuildAlertDialog = Tuple3> Function( void Function(void Function())); -// ?? -Future showAlertDialog(BuildContext context, BuildAlertDailog build, +// flutter Dialog +Future showAlertDialog(BuildAlertDialog build, [WillPopCallback? onWillPop, bool barrierDismissible = false, double contentPadding = 20]) async { - dismissLoading(); - if (_hasDialog) { - Navigator.pop(context); - } - _hasDialog = true; + EasyLoading.dismiss(); + DialogManager.reset(); var dialog = StatefulBuilder(builder: (context, setState) { var widgets = build(setState); if (onWillPop == null) onWillPop = () async => false; @@ -72,15 +75,20 @@ Future showAlertDialog(BuildContext context, BuildAlertDailog build, actions: widgets.item3, )); }); + if(globalKey.currentContext == null) return null; var res = await showDialog( - context: context, + context: globalKey.currentContext!, barrierDismissible: barrierDismissible, - builder: (context) => dialog); - _hasDialog = false; + builder: (context) { + DialogManager.register(context); + return dialog; + }); + DialogManager.reset(); return res; } -void msgBox(String type, String title, String text, BuildContext context, +// EasyLoading +void msgBox(String type, String title, String text, {bool? hasCancel}) { var wrap = (String text, void Function() onPressed) => ButtonTheme( padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), @@ -95,16 +103,14 @@ void msgBox(String type, String title, String text, BuildContext context, child: Text(Translator.call(text), style: TextStyle(color: MyTheme.accent)))); - dismissLoading(); - if (_hasDialog) { - Navigator.pop(context); - _hasDialog = false; - } + EasyLoading.dismiss(); + DialogManager.reset(); + if(globalKey.currentContext == null) return; final buttons = [ Expanded(child: Container()), wrap(Translator.call('OK'), () { - dismissLoading(); - Navigator.pop(context); + EasyLoading.dismiss(); + Navigator.pop(globalKey.currentContext!); // TODO }) ]; if (hasCancel == null) { @@ -114,7 +120,7 @@ void msgBox(String type, String title, String text, BuildContext context, buttons.insert( 1, wrap(Translator.call('Cancel'), () { - dismissLoading(); + EasyLoading.dismiss(); })); } EasyLoading.show( diff --git a/lib/home_page.dart b/lib/home_page.dart index 96e2c1001..460150a5a 100644 --- a/lib/home_page.dart +++ b/lib/home_page.dart @@ -57,12 +57,10 @@ class _HomePageState extends State { items.add(PopupMenuItem( child: Text(translate('ID Server')), value: 'id_server')); - if (isAndroid){ - items.add( - PopupMenuItem( - child: Text(translate('Share My Screen')), - value: 'server') - ); + if (isAndroid) { + items.add(PopupMenuItem( + child: Text(translate('Share My Screen')), + value: 'server')); } items.add(PopupMenuItem( child: Text(translate('About') + ' RustDesk'), @@ -315,25 +313,22 @@ void showServer(BuildContext context) { var id = ''; var relay = ''; var key = ''; - showAlertDialog( - context, - (setState) => Tuple3( - Text(translate('ID Server')), - Form( - key: formKey, - child: - Column(mainAxisSize: MainAxisSize.min, children: [ - TextFormField( - initialValue: id0, - decoration: InputDecoration( - labelText: translate('ID Server'), - ), - validator: validate, - onSaved: (String? value) { - if (value != null) id = value.trim(); - }, - ), - /* + showAlertDialog((setState) => Tuple3( + Text(translate('ID Server')), + Form( + key: formKey, + child: Column(mainAxisSize: MainAxisSize.min, children: [ + TextFormField( + initialValue: id0, + decoration: InputDecoration( + labelText: translate('ID Server'), + ), + validator: validate, + onSaved: (String? value) { + if (value != null) id = value.trim(); + }, + ), + /* TextFormField( initialValue: relay0, decoration: InputDecoration( @@ -345,52 +340,51 @@ void showServer(BuildContext context) { }, ), */ - TextFormField( - initialValue: key0, - decoration: InputDecoration( - labelText: 'Key', - ), - validator: null, - onSaved: (String? value) { - if (value != null) key = value.trim(); - }, - ), - ])), - [ - TextButton( - style: flatButtonStyle, - onPressed: () { - Navigator.pop(context); + TextFormField( + initialValue: key0, + decoration: InputDecoration( + labelText: 'Key', + ), + validator: null, + onSaved: (String? value) { + if (value != null) key = value.trim(); }, - child: Text(translate('Cancel')), ), - TextButton( - style: flatButtonStyle, - onPressed: () { - if (formKey.currentState != null && formKey.currentState!.validate()) { - formKey.currentState!.save(); - if (id != id0) - FFI.setByName('option', - '{"name": "custom-rendezvous-server", "value": "$id"}'); - if (relay != relay0) - FFI.setByName('option', - '{"name": "relay-server", "value": "$relay"}'); - if (key != key0) - FFI.setByName( - 'option', '{"name": "key", "value": "$key"}'); - Navigator.pop(context); - } - }, - child: Text(translate('OK')), - ), - ], - )); + ])), + [ + TextButton( + style: flatButtonStyle, + onPressed: () { + Navigator.pop(context); + }, + child: Text(translate('Cancel')), + ), + TextButton( + style: flatButtonStyle, + onPressed: () { + if (formKey.currentState != null && + formKey.currentState!.validate()) { + formKey.currentState!.save(); + if (id != id0) + FFI.setByName('option', + '{"name": "custom-rendezvous-server", "value": "$id"}'); + if (relay != relay0) + FFI.setByName( + 'option', '{"name": "relay-server", "value": "$relay"}'); + if (key != key0) + FFI.setByName('option', '{"name": "key", "value": "$key"}'); + Navigator.pop(context); + } + }, + child: Text(translate('OK')), + ), + ], + )); } Future showAbout(BuildContext context) async { var version = await FFI.getVersion(); showAlertDialog( - context, (setState) => Tuple3( SizedBox.shrink(), // TODO test old:null Wrap(direction: Axis.vertical, spacing: 12, children: [ diff --git a/lib/model.dart b/lib/model.dart index 30a6f21c5..bf73ab802 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -1,4 +1,5 @@ import 'package:flutter/services.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:math'; import 'dart:convert'; @@ -96,7 +97,6 @@ class FfiModel with ChangeNotifier { _inputBlocked = false; _permissions.clear(); } - void update(String id, BuildContext context, void Function( @@ -136,7 +136,7 @@ class FfiModel with ChangeNotifier { if (rgba != null) { if (_waitForImage) { _waitForImage = false; - dismissLoading(); + EasyLoading.dismiss(); } _decoding = true; final pid = FFI.id; @@ -170,7 +170,7 @@ class FfiModel with ChangeNotifier { } void handlePeerInfo(Map evt, BuildContext context) { - dismissLoading(); + EasyLoading.dismiss(); _pi.version = evt['version']; _pi.username = evt['username']; _pi.hostname = evt['hostname']; @@ -192,7 +192,7 @@ class FfiModel with ChangeNotifier { _display = _pi.displays[_pi.currentDisplay]; } if (displays.length > 0) { - showLoading(translate('Connected, waiting for image...'), context); + showLoading(translate('Connected, waiting for image...')); _waitForImage = true; } notifyListeners(); diff --git a/lib/remote_page.dart b/lib/remote_page.dart index 7271340a8..128ede27a 100644 --- a/lib/remote_page.dart +++ b/lib/remote_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_hbb/main.dart'; import 'package:flutter_hbb/widgets/gesture_help.dart'; import 'package:provider/provider.dart'; import 'package:flutter/services.dart'; @@ -43,7 +44,7 @@ class _RemotePageState extends State { FFI.connect(widget.id); WidgetsBinding.instance!.addPostFrameCallback((_) { SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); - showLoading(translate('Connecting...'), context); + showLoading(translate('Connecting...')); _interval = Timer.periodic(Duration(milliseconds: 30), (timer) => interval()); }); @@ -57,7 +58,7 @@ class _RemotePageState extends State { FFI.close(); _interval?.cancel(); _timer?.cancel(); - dismissLoading(); + EasyLoading.dismiss(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); Wakelock.disable(); @@ -99,9 +100,9 @@ class _RemotePageState extends State { var title = evt['title']; var text = evt['text']; if (type == 're-input-password') { - wrongPasswordDialog(id, context); + wrongPasswordDialog(id); } else if (type == 'input-password') { - enterPasswordDialog(id, context); + enterPasswordDialog(id); } else { var hasRetry = evt['hasRetry'] == 'true'; print(evt); @@ -110,12 +111,12 @@ class _RemotePageState extends State { } void showMsgBox(String type, String title, String text, bool hasRetry) { - msgBox(type, title, text, context); + msgBox(type, title, text); if (hasRetry) { _timer?.cancel(); _timer = Timer(Duration(seconds: _reconnects), () { FFI.reconnect(); - showLoading(translate('Connecting...'), context); + showLoading(translate('Connecting...')); }); _reconnects *= 2; } else { @@ -530,7 +531,7 @@ class _RemotePageState extends State { FFI.setByName('lock_screen'); } else if (value == 'block-input') { FFI.setByName('toggle_option', - (FFI.ffiModel.inputBlocked ? 'un' : '') + 'block-inpu'); + (FFI.ffiModel.inputBlocked ? 'un' : '') + 'block-input'); FFI.ffiModel.inputBlocked = !FFI.ffiModel.inputBlocked; } else if (value == 'refresh') { FFI.setByName('refresh'); @@ -579,7 +580,7 @@ class _RemotePageState extends State { } void close() { - msgBox('', 'Close', 'Are you sure to close the connection?', context); + msgBox('', 'Close', 'Are you sure to close the connection?'); } Widget getHelpTools() { @@ -776,75 +777,73 @@ class ImagePainter extends CustomPainter { } } -void enterPasswordDialog(String id, BuildContext context) { +void enterPasswordDialog(String id) { final controller = TextEditingController(); var remember = FFI.getByName('remember', id) == 'true'; - showAlertDialog( - context, - (setState) => Tuple3( - Text(translate('Password Required')), - Column(mainAxisSize: MainAxisSize.min, children: [ - PasswordWidget(controller: controller), - CheckboxListTile( - contentPadding: const EdgeInsets.all(0), - dense: true, - controlAffinity: ListTileControlAffinity.leading, - title: Text( - translate('Remember password'), - ), - value: remember, - onChanged: (v) { - if (v != null) { - setState(() => remember = v); - } - }, - ), - ]), - [ - TextButton( - style: flatButtonStyle, - onPressed: () { - Navigator.pop(context); - Navigator.pop(context); - }, - child: Text(translate('Cancel')), - ), - TextButton( - style: flatButtonStyle, - onPressed: () { - var text = controller.text.trim(); - if (text == '') return; - FFI.login(text, remember); - showLoading(translate('Logging in...'), null); - Navigator.pop(context); - }, - child: Text(translate('OK')), - ), - ], - )); + if (globalKey.currentContext == null) return; + showAlertDialog((setState) => Tuple3( + Text(translate('Password Required')), + Column(mainAxisSize: MainAxisSize.min, children: [ + PasswordWidget(controller: controller), + CheckboxListTile( + contentPadding: const EdgeInsets.all(0), + dense: true, + controlAffinity: ListTileControlAffinity.leading, + title: Text( + translate('Remember password'), + ), + value: remember, + onChanged: (v) { + if (v != null) { + setState(() => remember = v); + } + }, + ), + ]), + [ + TextButton( + style: flatButtonStyle, + onPressed: () { + DialogManager.reset(); + Navigator.pop(globalKey.currentContext!); + }, + child: Text(translate('Cancel')), + ), + TextButton( + style: flatButtonStyle, + onPressed: () { + var text = controller.text.trim(); + if (text == '') return; + FFI.login(text, remember); + DialogManager.reset(); + showLoading(translate('Logging in...')); + }, + child: Text(translate('OK')), + ), + ], + )); } -void wrongPasswordDialog(String id, BuildContext context) { - showAlertDialog( - context, - (_) => Tuple3(Text(translate('Wrong Password')), - Text(translate('Do you want to enter again?')), [ - TextButton( - style: flatButtonStyle, - onPressed: () { - Navigator.pop(context); - Navigator.pop(context); - }, - child: Text(translate('Cancel')), - ), - TextButton( - style: flatButtonStyle, - onPressed: () { - enterPasswordDialog(id, context); - }, - child: Text(translate('Retry')), - ), - ])); +void wrongPasswordDialog(String id) { + if (globalKey.currentContext == null) return; + showAlertDialog((_) => Tuple3(Text(translate('Wrong Password')), + Text(translate('Do you want to enter again?')), [ + TextButton( + style: flatButtonStyle, + onPressed: () { + DialogManager.reset(); + Navigator.pop(globalKey.currentContext!); + }, + child: Text(translate('Cancel')), + ), + TextButton( + style: flatButtonStyle, + onPressed: () { + enterPasswordDialog(id); + }, + child: Text(translate('Retry')), + ), + ])); } CheckboxListTile getToggle( @@ -914,7 +913,7 @@ void showOptions(BuildContext context) { displays.add(Divider(color: MyTheme.border)); } final perms = FFI.ffiModel.permissions; - showAlertDialog(context, (setState) { + showAlertDialog((setState) { final more = []; if (perms['audio'] != false) { more.add(getToggle(setState, 'disable-audio', 'Mute')); @@ -977,51 +976,49 @@ void showSetOSPassword(BuildContext context, bool login) { var password = FFI.getByName('peer_option', "os-password"); var autoLogin = FFI.getByName('peer_option', "auto-login") != ""; controller.text = password; - showAlertDialog( - context, - (setState) => Tuple3( - Text(translate('OS Password')), - Column(mainAxisSize: MainAxisSize.min, children: [ - PasswordWidget(controller: controller), - CheckboxListTile( - contentPadding: const EdgeInsets.all(0), - dense: true, - controlAffinity: ListTileControlAffinity.leading, - title: Text( - translate('Auto Login'), - ), - value: autoLogin, - onChanged: (v) { - if (v == null) return; - setState(() => autoLogin = v); - }, - ), - ]), - [ - TextButton( - style: flatButtonStyle, - onPressed: () { - Navigator.pop(context); - }, - child: Text(translate('Cancel')), - ), - TextButton( - style: flatButtonStyle, - onPressed: () { - var text = controller.text.trim(); - FFI.setByName('peer_option', - '{"name": "os-password", "value": "$text"}'); - FFI.setByName('peer_option', - '{"name": "auto-login", "value": "${autoLogin ? 'Y' : ''}"}'); - if (text != "" && login) { - FFI.setByName('input_os_password', text); - } - Navigator.pop(context); - }, - child: Text(translate('OK')), - ), - ], - )); + showAlertDialog((setState) => Tuple3( + Text(translate('OS Password')), + Column(mainAxisSize: MainAxisSize.min, children: [ + PasswordWidget(controller: controller), + CheckboxListTile( + contentPadding: const EdgeInsets.all(0), + dense: true, + controlAffinity: ListTileControlAffinity.leading, + title: Text( + translate('Auto Login'), + ), + value: autoLogin, + onChanged: (v) { + if (v == null) return; + setState(() => autoLogin = v); + }, + ), + ]), + [ + TextButton( + style: flatButtonStyle, + onPressed: () { + Navigator.pop(context); + }, + child: Text(translate('Cancel')), + ), + TextButton( + style: flatButtonStyle, + onPressed: () { + var text = controller.text.trim(); + FFI.setByName( + 'peer_option', '{"name": "os-password", "value": "$text"}'); + FFI.setByName('peer_option', + '{"name": "auto-login", "value": "${autoLogin ? 'Y' : ''}"}'); + if (text != "" && login) { + FFI.setByName('input_os_password', text); + } + Navigator.pop(context); + }, + child: Text(translate('OK')), + ), + ], + )); } void sendPrompt(bool isMac, String key) { diff --git a/lib/server_page.dart b/lib/server_page.dart index e90e3fc2b..eaf6c92a7 100644 --- a/lib/server_page.dart +++ b/lib/server_page.dart @@ -198,15 +198,14 @@ Widget getConnInfo(String name, String peerID) { ); } -BuildContext? loginReqAlertCtx; - void showLoginReqAlert(String peerID, String name) async { if (globalKey.currentContext == null) return; await showDialog( barrierDismissible: false, context: globalKey.currentContext!, builder: (alertContext) { - loginReqAlertCtx = alertContext; + DialogManager.reset(); + DialogManager.register(alertContext); return AlertDialog( title: Text("Control Request"), content: Container( @@ -225,7 +224,7 @@ void showLoginReqAlert(String peerID, String name) async { child: Text(translate("Dismiss")), onPressed: () { FFI.setByName("login_res", "false"); - Navigator.of(alertContext).pop(); + DialogManager.reset(); }), ElevatedButton( child: Text(translate("Accept")), @@ -235,20 +234,12 @@ void showLoginReqAlert(String peerID, String name) async { _toAndroidStartCapture(); } FFI.serverModel.setPeer(true); - Navigator.of(alertContext).pop(); + DialogManager.reset(); }), ], ); }); - loginReqAlertCtx = null; -} - -clearLoginReqAlert() { - if (loginReqAlertCtx != null) { - Navigator.of(loginReqAlertCtx!).pop(); - FFI.serverModel.updateClientState(); - loginReqAlertCtx = null; - } + DialogManager.reset(); } class PermissionRow extends StatelessWidget { @@ -376,10 +367,12 @@ Future _toAndroidInitInput() async { showInputWarnAlert() async { if (globalKey.currentContext == null) return; + DialogManager.reset(); await showDialog( context: globalKey.currentContext!, builder: (alertContext) { // TODO t + DialogManager.register(alertContext); return AlertDialog( title: Text("获取输入权限引导"), // content: Text("请在接下来的系统设置页面 \n进入 [服务] 配置页面\n将[RustDesk Input]服务开启"), @@ -396,17 +389,18 @@ showInputWarnAlert() async { TextButton( child: Text(translate("Do nothing")), onPressed: () { - Navigator.of(alertContext).pop(); + DialogManager.reset(); }), ElevatedButton( child: Text(translate("Go System Setting")), onPressed: () { _toAndroidInitInput(); - Navigator.of(alertContext).pop(); + DialogManager.reset(); }), ], ); }); + DialogManager.reset(); } void toAndroidChannelInit() { @@ -425,14 +419,14 @@ void toAndroidChannelInit() { } case "start_capture": { - clearLoginReqAlert(); + DialogManager.reset(); FFI.serverModel.updateClientState(); break; } case "stop_capture": { + DialogManager.reset(); FFI.serverModel.setPeer(false); - clearLoginReqAlert(); break; } case "on_permission_changed":