add DialogManager

This commit is contained in:
csf 2022-02-28 16:11:21 +08:00
parent 31ff6923d2
commit 034d825b74
5 changed files with 226 additions and 235 deletions

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:async'; import 'dart:async';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_hbb/main.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
typedef F = String Function(String); typedef F = String Function(String);
@ -32,34 +33,36 @@ final ButtonStyle flatButtonStyle = TextButton.styleFrom(
), ),
); );
void showLoading(String text, BuildContext? context) { void showLoading(String text) {
if (_hasDialog && context != null) { DialogManager.reset();
Navigator.pop(context); EasyLoading.dismiss();
_hasDialog = false;
}
dismissLoading();
EasyLoading.show(status: text, maskType: EasyLoadingMaskType.black); EasyLoading.show(status: text, maskType: EasyLoadingMaskType.black);
} }
void dismissLoading() { class DialogManager{
EasyLoading.dismiss(); 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 BuildAlertDialog = Tuple3<Widget, Widget, List<Widget>> Function(
typedef BuildAlertDailog = Tuple3<Widget, Widget, List<Widget>> Function(
void Function(void Function())); void Function(void Function()));
// ?? // flutter Dialog
Future<T?> showAlertDialog<T>(BuildContext context, BuildAlertDailog build, Future<T?> showAlertDialog<T>(BuildAlertDialog build,
[WillPopCallback? onWillPop, [WillPopCallback? onWillPop,
bool barrierDismissible = false, bool barrierDismissible = false,
double contentPadding = 20]) async { double contentPadding = 20]) async {
dismissLoading(); EasyLoading.dismiss();
if (_hasDialog) { DialogManager.reset();
Navigator.pop(context);
}
_hasDialog = true;
var dialog = StatefulBuilder(builder: (context, setState) { var dialog = StatefulBuilder(builder: (context, setState) {
var widgets = build(setState); var widgets = build(setState);
if (onWillPop == null) onWillPop = () async => false; if (onWillPop == null) onWillPop = () async => false;
@ -72,15 +75,20 @@ Future<T?> showAlertDialog<T>(BuildContext context, BuildAlertDailog build,
actions: widgets.item3, actions: widgets.item3,
)); ));
}); });
if(globalKey.currentContext == null) return null;
var res = await showDialog<T>( var res = await showDialog<T>(
context: context, context: globalKey.currentContext!,
barrierDismissible: barrierDismissible, barrierDismissible: barrierDismissible,
builder: (context) => dialog); builder: (context) {
_hasDialog = false; DialogManager.register(context);
return dialog;
});
DialogManager.reset();
return res; return res;
} }
void msgBox(String type, String title, String text, BuildContext context, // EasyLoading
void msgBox(String type, String title, String text,
{bool? hasCancel}) { {bool? hasCancel}) {
var wrap = (String text, void Function() onPressed) => ButtonTheme( var wrap = (String text, void Function() onPressed) => ButtonTheme(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), 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), child: Text(Translator.call(text),
style: TextStyle(color: MyTheme.accent)))); style: TextStyle(color: MyTheme.accent))));
dismissLoading(); EasyLoading.dismiss();
if (_hasDialog) { DialogManager.reset();
Navigator.pop(context); if(globalKey.currentContext == null) return;
_hasDialog = false;
}
final buttons = [ final buttons = [
Expanded(child: Container()), Expanded(child: Container()),
wrap(Translator.call('OK'), () { wrap(Translator.call('OK'), () {
dismissLoading(); EasyLoading.dismiss();
Navigator.pop(context); Navigator.pop(globalKey.currentContext!); // TODO
}) })
]; ];
if (hasCancel == null) { if (hasCancel == null) {
@ -114,7 +120,7 @@ void msgBox(String type, String title, String text, BuildContext context,
buttons.insert( buttons.insert(
1, 1,
wrap(Translator.call('Cancel'), () { wrap(Translator.call('Cancel'), () {
dismissLoading(); EasyLoading.dismiss();
})); }));
} }
EasyLoading.show( EasyLoading.show(

View File

@ -58,11 +58,9 @@ class _HomePageState extends State<HomePage> {
child: Text(translate('ID Server')), child: Text(translate('ID Server')),
value: 'id_server')); value: 'id_server'));
if (isAndroid) { if (isAndroid) {
items.add( items.add(PopupMenuItem<String>(
PopupMenuItem<String>(
child: Text(translate('Share My Screen')), child: Text(translate('Share My Screen')),
value: 'server') value: 'server'));
);
} }
items.add(PopupMenuItem<String>( items.add(PopupMenuItem<String>(
child: Text(translate('About') + ' RustDesk'), child: Text(translate('About') + ' RustDesk'),
@ -315,14 +313,11 @@ void showServer(BuildContext context) {
var id = ''; var id = '';
var relay = ''; var relay = '';
var key = ''; var key = '';
showAlertDialog( showAlertDialog((setState) => Tuple3(
context,
(setState) => Tuple3(
Text(translate('ID Server')), Text(translate('ID Server')),
Form( Form(
key: formKey, key: formKey,
child: child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
TextFormField( TextFormField(
initialValue: id0, initialValue: id0,
decoration: InputDecoration( decoration: InputDecoration(
@ -367,17 +362,17 @@ void showServer(BuildContext context) {
TextButton( TextButton(
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
if (formKey.currentState != null && formKey.currentState!.validate()) { if (formKey.currentState != null &&
formKey.currentState!.validate()) {
formKey.currentState!.save(); formKey.currentState!.save();
if (id != id0) if (id != id0)
FFI.setByName('option', FFI.setByName('option',
'{"name": "custom-rendezvous-server", "value": "$id"}'); '{"name": "custom-rendezvous-server", "value": "$id"}');
if (relay != relay0) if (relay != relay0)
FFI.setByName('option',
'{"name": "relay-server", "value": "$relay"}');
if (key != key0)
FFI.setByName( FFI.setByName(
'option', '{"name": "key", "value": "$key"}'); 'option', '{"name": "relay-server", "value": "$relay"}');
if (key != key0)
FFI.setByName('option', '{"name": "key", "value": "$key"}');
Navigator.pop(context); Navigator.pop(context);
} }
}, },
@ -390,7 +385,6 @@ void showServer(BuildContext context) {
Future<Null> showAbout(BuildContext context) async { Future<Null> showAbout(BuildContext context) async {
var version = await FFI.getVersion(); var version = await FFI.getVersion();
showAlertDialog( showAlertDialog(
context,
(setState) => Tuple3( (setState) => Tuple3(
SizedBox.shrink(), // TODO test old:null SizedBox.shrink(), // TODO test old:null
Wrap(direction: Axis.vertical, spacing: 12, children: [ Wrap(direction: Axis.vertical, spacing: 12, children: [

View File

@ -1,4 +1,5 @@
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'dart:math'; import 'dart:math';
import 'dart:convert'; import 'dart:convert';
@ -96,7 +97,6 @@ class FfiModel with ChangeNotifier {
_inputBlocked = false; _inputBlocked = false;
_permissions.clear(); _permissions.clear();
} }
void update(String id, void update(String id,
BuildContext context, BuildContext context,
void Function( void Function(
@ -136,7 +136,7 @@ class FfiModel with ChangeNotifier {
if (rgba != null) { if (rgba != null) {
if (_waitForImage) { if (_waitForImage) {
_waitForImage = false; _waitForImage = false;
dismissLoading(); EasyLoading.dismiss();
} }
_decoding = true; _decoding = true;
final pid = FFI.id; final pid = FFI.id;
@ -170,7 +170,7 @@ class FfiModel with ChangeNotifier {
} }
void handlePeerInfo(Map<String, dynamic> evt, BuildContext context) { void handlePeerInfo(Map<String, dynamic> evt, BuildContext context) {
dismissLoading(); EasyLoading.dismiss();
_pi.version = evt['version']; _pi.version = evt['version'];
_pi.username = evt['username']; _pi.username = evt['username'];
_pi.hostname = evt['hostname']; _pi.hostname = evt['hostname'];
@ -192,7 +192,7 @@ class FfiModel with ChangeNotifier {
_display = _pi.displays[_pi.currentDisplay]; _display = _pi.displays[_pi.currentDisplay];
} }
if (displays.length > 0) { if (displays.length > 0) {
showLoading(translate('Connected, waiting for image...'), context); showLoading(translate('Connected, waiting for image...'));
_waitForImage = true; _waitForImage = true;
} }
notifyListeners(); notifyListeners();

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_hbb/main.dart';
import 'package:flutter_hbb/widgets/gesture_help.dart'; import 'package:flutter_hbb/widgets/gesture_help.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -43,7 +44,7 @@ class _RemotePageState extends State<RemotePage> {
FFI.connect(widget.id); FFI.connect(widget.id);
WidgetsBinding.instance!.addPostFrameCallback((_) { WidgetsBinding.instance!.addPostFrameCallback((_) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
showLoading(translate('Connecting...'), context); showLoading(translate('Connecting...'));
_interval = _interval =
Timer.periodic(Duration(milliseconds: 30), (timer) => interval()); Timer.periodic(Duration(milliseconds: 30), (timer) => interval());
}); });
@ -57,7 +58,7 @@ class _RemotePageState extends State<RemotePage> {
FFI.close(); FFI.close();
_interval?.cancel(); _interval?.cancel();
_timer?.cancel(); _timer?.cancel();
dismissLoading(); EasyLoading.dismiss();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values); overlays: SystemUiOverlay.values);
Wakelock.disable(); Wakelock.disable();
@ -99,9 +100,9 @@ class _RemotePageState extends State<RemotePage> {
var title = evt['title']; var title = evt['title'];
var text = evt['text']; var text = evt['text'];
if (type == 're-input-password') { if (type == 're-input-password') {
wrongPasswordDialog(id, context); wrongPasswordDialog(id);
} else if (type == 'input-password') { } else if (type == 'input-password') {
enterPasswordDialog(id, context); enterPasswordDialog(id);
} else { } else {
var hasRetry = evt['hasRetry'] == 'true'; var hasRetry = evt['hasRetry'] == 'true';
print(evt); print(evt);
@ -110,12 +111,12 @@ class _RemotePageState extends State<RemotePage> {
} }
void showMsgBox(String type, String title, String text, bool hasRetry) { void showMsgBox(String type, String title, String text, bool hasRetry) {
msgBox(type, title, text, context); msgBox(type, title, text);
if (hasRetry) { if (hasRetry) {
_timer?.cancel(); _timer?.cancel();
_timer = Timer(Duration(seconds: _reconnects), () { _timer = Timer(Duration(seconds: _reconnects), () {
FFI.reconnect(); FFI.reconnect();
showLoading(translate('Connecting...'), context); showLoading(translate('Connecting...'));
}); });
_reconnects *= 2; _reconnects *= 2;
} else { } else {
@ -530,7 +531,7 @@ class _RemotePageState extends State<RemotePage> {
FFI.setByName('lock_screen'); FFI.setByName('lock_screen');
} else if (value == 'block-input') { } else if (value == 'block-input') {
FFI.setByName('toggle_option', FFI.setByName('toggle_option',
(FFI.ffiModel.inputBlocked ? 'un' : '') + 'block-inpu'); (FFI.ffiModel.inputBlocked ? 'un' : '') + 'block-input');
FFI.ffiModel.inputBlocked = !FFI.ffiModel.inputBlocked; FFI.ffiModel.inputBlocked = !FFI.ffiModel.inputBlocked;
} else if (value == 'refresh') { } else if (value == 'refresh') {
FFI.setByName('refresh'); FFI.setByName('refresh');
@ -579,7 +580,7 @@ class _RemotePageState extends State<RemotePage> {
} }
void close() { void close() {
msgBox('', 'Close', 'Are you sure to close the connection?', context); msgBox('', 'Close', 'Are you sure to close the connection?');
} }
Widget getHelpTools() { Widget getHelpTools() {
@ -776,12 +777,11 @@ class ImagePainter extends CustomPainter {
} }
} }
void enterPasswordDialog(String id, BuildContext context) { void enterPasswordDialog(String id) {
final controller = TextEditingController(); final controller = TextEditingController();
var remember = FFI.getByName('remember', id) == 'true'; var remember = FFI.getByName('remember', id) == 'true';
showAlertDialog( if (globalKey.currentContext == null) return;
context, showAlertDialog((setState) => Tuple3(
(setState) => Tuple3(
Text(translate('Password Required')), Text(translate('Password Required')),
Column(mainAxisSize: MainAxisSize.min, children: [ Column(mainAxisSize: MainAxisSize.min, children: [
PasswordWidget(controller: controller), PasswordWidget(controller: controller),
@ -804,8 +804,8 @@ void enterPasswordDialog(String id, BuildContext context) {
TextButton( TextButton(
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
Navigator.pop(context); DialogManager.reset();
Navigator.pop(context); Navigator.pop(globalKey.currentContext!);
}, },
child: Text(translate('Cancel')), child: Text(translate('Cancel')),
), ),
@ -815,8 +815,8 @@ void enterPasswordDialog(String id, BuildContext context) {
var text = controller.text.trim(); var text = controller.text.trim();
if (text == '') return; if (text == '') return;
FFI.login(text, remember); FFI.login(text, remember);
showLoading(translate('Logging in...'), null); DialogManager.reset();
Navigator.pop(context); showLoading(translate('Logging in...'));
}, },
child: Text(translate('OK')), child: Text(translate('OK')),
), ),
@ -824,23 +824,22 @@ void enterPasswordDialog(String id, BuildContext context) {
)); ));
} }
void wrongPasswordDialog(String id, BuildContext context) { void wrongPasswordDialog(String id) {
showAlertDialog( if (globalKey.currentContext == null) return;
context, showAlertDialog((_) => Tuple3(Text(translate('Wrong Password')),
(_) => Tuple3(Text(translate('Wrong Password')),
Text(translate('Do you want to enter again?')), [ Text(translate('Do you want to enter again?')), [
TextButton( TextButton(
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
Navigator.pop(context); DialogManager.reset();
Navigator.pop(context); Navigator.pop(globalKey.currentContext!);
}, },
child: Text(translate('Cancel')), child: Text(translate('Cancel')),
), ),
TextButton( TextButton(
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
enterPasswordDialog(id, context); enterPasswordDialog(id);
}, },
child: Text(translate('Retry')), child: Text(translate('Retry')),
), ),
@ -914,7 +913,7 @@ void showOptions(BuildContext context) {
displays.add(Divider(color: MyTheme.border)); displays.add(Divider(color: MyTheme.border));
} }
final perms = FFI.ffiModel.permissions; final perms = FFI.ffiModel.permissions;
showAlertDialog(context, (setState) { showAlertDialog((setState) {
final more = <Widget>[]; final more = <Widget>[];
if (perms['audio'] != false) { if (perms['audio'] != false) {
more.add(getToggle(setState, 'disable-audio', 'Mute')); more.add(getToggle(setState, 'disable-audio', 'Mute'));
@ -977,9 +976,7 @@ void showSetOSPassword(BuildContext context, bool login) {
var password = FFI.getByName('peer_option', "os-password"); var password = FFI.getByName('peer_option', "os-password");
var autoLogin = FFI.getByName('peer_option', "auto-login") != ""; var autoLogin = FFI.getByName('peer_option', "auto-login") != "";
controller.text = password; controller.text = password;
showAlertDialog( showAlertDialog((setState) => Tuple3(
context,
(setState) => Tuple3(
Text(translate('OS Password')), Text(translate('OS Password')),
Column(mainAxisSize: MainAxisSize.min, children: [ Column(mainAxisSize: MainAxisSize.min, children: [
PasswordWidget(controller: controller), PasswordWidget(controller: controller),
@ -1009,8 +1006,8 @@ void showSetOSPassword(BuildContext context, bool login) {
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
var text = controller.text.trim(); var text = controller.text.trim();
FFI.setByName('peer_option', FFI.setByName(
'{"name": "os-password", "value": "$text"}'); 'peer_option', '{"name": "os-password", "value": "$text"}');
FFI.setByName('peer_option', FFI.setByName('peer_option',
'{"name": "auto-login", "value": "${autoLogin ? 'Y' : ''}"}'); '{"name": "auto-login", "value": "${autoLogin ? 'Y' : ''}"}');
if (text != "" && login) { if (text != "" && login) {

View File

@ -198,15 +198,14 @@ Widget getConnInfo(String name, String peerID) {
); );
} }
BuildContext? loginReqAlertCtx;
void showLoginReqAlert(String peerID, String name) async { void showLoginReqAlert(String peerID, String name) async {
if (globalKey.currentContext == null) return; if (globalKey.currentContext == null) return;
await showDialog( await showDialog(
barrierDismissible: false, barrierDismissible: false,
context: globalKey.currentContext!, context: globalKey.currentContext!,
builder: (alertContext) { builder: (alertContext) {
loginReqAlertCtx = alertContext; DialogManager.reset();
DialogManager.register(alertContext);
return AlertDialog( return AlertDialog(
title: Text("Control Request"), title: Text("Control Request"),
content: Container( content: Container(
@ -225,7 +224,7 @@ void showLoginReqAlert(String peerID, String name) async {
child: Text(translate("Dismiss")), child: Text(translate("Dismiss")),
onPressed: () { onPressed: () {
FFI.setByName("login_res", "false"); FFI.setByName("login_res", "false");
Navigator.of(alertContext).pop(); DialogManager.reset();
}), }),
ElevatedButton( ElevatedButton(
child: Text(translate("Accept")), child: Text(translate("Accept")),
@ -235,20 +234,12 @@ void showLoginReqAlert(String peerID, String name) async {
_toAndroidStartCapture(); _toAndroidStartCapture();
} }
FFI.serverModel.setPeer(true); FFI.serverModel.setPeer(true);
Navigator.of(alertContext).pop(); DialogManager.reset();
}), }),
], ],
); );
}); });
loginReqAlertCtx = null; DialogManager.reset();
}
clearLoginReqAlert() {
if (loginReqAlertCtx != null) {
Navigator.of(loginReqAlertCtx!).pop();
FFI.serverModel.updateClientState();
loginReqAlertCtx = null;
}
} }
class PermissionRow extends StatelessWidget { class PermissionRow extends StatelessWidget {
@ -376,10 +367,12 @@ Future<Null> _toAndroidInitInput() async {
showInputWarnAlert() async { showInputWarnAlert() async {
if (globalKey.currentContext == null) return; if (globalKey.currentContext == null) return;
DialogManager.reset();
await showDialog<bool>( await showDialog<bool>(
context: globalKey.currentContext!, context: globalKey.currentContext!,
builder: (alertContext) { builder: (alertContext) {
// TODO t // TODO t
DialogManager.register(alertContext);
return AlertDialog( return AlertDialog(
title: Text("获取输入权限引导"), title: Text("获取输入权限引导"),
// content: Text("请在接下来的系统设置页面 \n进入 [服务] 配置页面\n将[RustDesk Input]服务开启"), // content: Text("请在接下来的系统设置页面 \n进入 [服务] 配置页面\n将[RustDesk Input]服务开启"),
@ -396,17 +389,18 @@ showInputWarnAlert() async {
TextButton( TextButton(
child: Text(translate("Do nothing")), child: Text(translate("Do nothing")),
onPressed: () { onPressed: () {
Navigator.of(alertContext).pop(); DialogManager.reset();
}), }),
ElevatedButton( ElevatedButton(
child: Text(translate("Go System Setting")), child: Text(translate("Go System Setting")),
onPressed: () { onPressed: () {
_toAndroidInitInput(); _toAndroidInitInput();
Navigator.of(alertContext).pop(); DialogManager.reset();
}), }),
], ],
); );
}); });
DialogManager.reset();
} }
void toAndroidChannelInit() { void toAndroidChannelInit() {
@ -425,14 +419,14 @@ void toAndroidChannelInit() {
} }
case "start_capture": case "start_capture":
{ {
clearLoginReqAlert(); DialogManager.reset();
FFI.serverModel.updateClientState(); FFI.serverModel.updateClientState();
break; break;
} }
case "stop_capture": case "stop_capture":
{ {
DialogManager.reset();
FFI.serverModel.setPeer(false); FFI.serverModel.setPeer(false);
clearLoginReqAlert();
break; break;
} }
case "on_permission_changed": case "on_permission_changed":