new dialog impl based on Overlay

This commit is contained in:
csf 2022-08-12 18:42:02 +08:00
parent 2e9a6ed4f6
commit e6329dc7eb
22 changed files with 526 additions and 476 deletions

View File

@ -4,10 +4,10 @@ import 'dart:io';
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/instance_manager.dart'; import 'package:get/instance_manager.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
import 'package:back_button_interceptor/back_button_interceptor.dart';
import 'models/model.dart'; import 'models/model.dart';
import 'models/platform_model.dart'; import 'models/platform_model.dart';
@ -26,10 +26,6 @@ int androidVersion = 0;
typedef F = String Function(String); typedef F = String Function(String);
typedef FMethod = String Function(String, dynamic); typedef FMethod = String Function(String, dynamic);
class Translator {
static late F call;
}
class MyTheme { class MyTheme {
MyTheme._(); MyTheme._();
@ -71,44 +67,12 @@ final ButtonStyle flatButtonStyle = TextButton.styleFrom(
), ),
); );
void showToast(String text, {Duration? duration}) { backToHomePage() {
SmartDialog.showToast(text, displayTime: duration); if (isAndroid || isIOS) {
} Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/"));
} else {
void showLoading(String text, {bool clickMaskDismiss = false}) { // TODO desktop
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("/"));
} }
void window_on_top(int? id) { void window_on_top(int? id) {
@ -127,51 +91,140 @@ void window_on_top(int? id) {
typedef DialogBuilder = CustomAlertDialog Function( typedef DialogBuilder = CustomAlertDialog Function(
StateSetter setState, void Function([dynamic]) close); StateSetter setState, void Function([dynamic]) close);
class DialogManager { class Dialog<T> {
static int _tag = 0; OverlayEntry? entry;
Completer<T?> completer = Completer<T>();
static dismissByTag(String tag, [result]) { Dialog();
SmartDialog.dismiss(tag: tag, result: result);
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<String, Dialog> _dialogs = Map();
int _tagCount = 0;
/// By default OverlayDialogManager use global overlay
OverlayDialogManager() {
_overlayState = globalKey.currentState?.overlay;
} }
static Future<T?> show<T>(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<T?> show<T>(DialogBuilder builder,
{bool clickMaskDismiss = false, {bool clickMaskDismiss = false,
bool backDismiss = false, bool backDismiss = false,
String? tag, String? tag,
bool useAnimation = true}) async { bool useAnimation = true,
final t; bool forceGlobal = false}) {
if (tag != null) { final overlayState =
t = tag; forceGlobal ? globalKey.currentState?.overlay : _overlayState;
} else {
_tag += 1; if (overlayState == null) {
t = _tag.toString(); 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<T>();
_dialogs[_tag] = dialog;
final close = ([res]) { final close = ([res]) {
SmartDialog.dismiss(tag: t, result: res); _dialogs.remove(_tag);
dialog.complete(res);
BackButtonInterceptor.removeByName(_tag);
}; };
final res = await SmartDialog.show<T>( dialog.entry = OverlayEntry(builder: (_) {
tag: t, return Container(
clickMaskDismiss: clickMaskDismiss, color: Colors.transparent,
backDismiss: backDismiss, child: StatefulBuilder(
useAnimation: useAnimation, builder: (_, setState) => builder(setState, close)));
builder: (_) => StatefulBuilder( });
builder: (_, setState) => builder(setState, close))); overlayState.insert(dialog.entry!);
return res; 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 { class CustomAlertDialog extends StatelessWidget {
CustomAlertDialog( CustomAlertDialog(
{required this.title, {this.title, required this.content, this.actions, this.contentPadding});
required this.content,
required this.actions,
this.contentPadding});
final Widget title; final Widget? title;
final Widget content; final Widget content;
final List<Widget> actions; final List<Widget>? actions;
final double? contentPadding; final double? contentPadding;
@override @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( var wrap = (String text, void Function() onPressed) => ButtonTheme(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
@ -198,17 +253,17 @@ void msgBox(String type, String title, String text, {bool? hasCancel}) {
child: TextButton( child: TextButton(
style: flatButtonStyle, style: flatButtonStyle,
onPressed: onPressed, onPressed: onPressed,
child: Text(Translator.call(text), child:
style: TextStyle(color: MyTheme.accent)))); Text(translate(text), style: TextStyle(color: MyTheme.accent))));
SmartDialog.dismiss(); dialogManager.dismissAll();
List<Widget> buttons = []; List<Widget> buttons = [];
if (type != "connecting" && type != "success" && type.indexOf("nook") < 0) { if (type != "connecting" && type != "success" && type.indexOf("nook") < 0) {
buttons.insert( buttons.insert(
0, 0,
wrap(Translator.call('OK'), () { wrap(translate('OK'), () {
SmartDialog.dismiss(); dialogManager.dismissAll();
backToHome(); backToHomePage();
})); }));
} }
if (hasCancel == null) { if (hasCancel == null) {
@ -220,21 +275,21 @@ void msgBox(String type, String title, String text, {bool? hasCancel}) {
if (hasCancel) { if (hasCancel) {
buttons.insert( buttons.insert(
0, 0,
wrap(Translator.call('Cancel'), () { wrap(translate('Cancel'), () {
SmartDialog.dismiss(); dialogManager.dismissAll();
})); }));
} }
// TODO: test this button // TODO: test this button
if (type.indexOf("hasclose") >= 0) { if (type.indexOf("hasclose") >= 0) {
buttons.insert( buttons.insert(
0, 0,
wrap(Translator.call('Close'), () { wrap(translate('Close'), () {
SmartDialog.dismiss(); dialogManager.dismissAll();
})); }));
} }
DialogManager.show((setState, close) => CustomAlertDialog( dialogManager.show((setState, close) => CustomAlertDialog(
title: Text(translate(title), style: TextStyle(fontSize: 21)), 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)); actions: buttons));
} }

View File

@ -625,7 +625,7 @@ class _ConnectionPageState extends State<ConnectionPage> {
var field = ""; var field = "";
var msg = ""; var msg = "";
var isInProgress = false; var isInProgress = false;
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate("Add ID")), title: Text(translate("Add ID")),
content: Column( content: Column(
@ -698,7 +698,7 @@ class _ConnectionPageState extends State<ConnectionPage> {
var field = ""; var field = "";
var msg = ""; var msg = "";
var isInProgress = false; var isInProgress = false;
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate("Add Tag")), title: Text(translate("Add Tag")),
content: Column( content: Column(
@ -769,7 +769,7 @@ class _ConnectionPageState extends State<ConnectionPage> {
final tags = List.of(gFFI.abModel.tags); final tags = List.of(gFFI.abModel.tags);
var selectedTag = gFFI.abModel.getPeerTags(id).obs; var selectedTag = gFFI.abModel.getPeerTags(id).obs;
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate("Edit Tag")), title: Text(translate("Edit Tag")),
content: Column( content: Column(
@ -884,16 +884,16 @@ class _WebMenuState extends State<WebMenu> {
}, },
onSelected: (value) { onSelected: (value) {
if (value == 'server') { if (value == 'server') {
showServerSettings(); showServerSettings(gFFI.dialogManager);
} }
if (value == 'about') { if (value == 'about') {
showAbout(); showAbout(gFFI.dialogManager);
} }
if (value == 'login') { if (value == 'login') {
if (username == null) { if (username == null) {
showLogin(); showLogin(gFFI.dialogManager);
} else { } else {
logout(); logout(gFFI.dialogManager);
} }
} }
if (value == 'scan') { if (value == 'scan') {

View File

@ -116,7 +116,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
onDoubleTap: () { onDoubleTap: () {
Clipboard.setData( Clipboard.setData(
ClipboardData(text: model.serverId.text)); ClipboardData(text: model.serverId.text));
showToast(translate("Copied")); gFFI.dialogManager.showToast(translate("Copied"));
}, },
child: TextFormField( child: TextFormField(
controller: model.serverId, controller: model.serverId,
@ -253,7 +253,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
kUsePermanentPassword) { kUsePermanentPassword) {
Clipboard.setData( Clipboard.setData(
ClipboardData(text: model.serverPasswd.text)); ClipboardData(text: model.serverPasswd.text));
showToast(translate("Copied")); gFFI.dialogManager.showToast(translate("Copied"));
} }
}, },
child: TextFormField( child: TextFormField(
@ -604,7 +604,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
var newId = ""; var newId = "";
var msg = ""; var msg = "";
var isInProgress = false; var isInProgress = false;
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate("Change ID")), title: Text(translate("Change ID")),
content: Column( content: Column(
@ -690,7 +690,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
var key = oldOptions['key'] ?? ""; var key = oldOptions['key'] ?? "";
var isInProgress = false; var isInProgress = false;
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate("ID/Relay Server")), title: Text(translate("ID/Relay Server")),
content: ConstrainedBox( content: ConstrainedBox(
@ -891,7 +891,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
var newWhiteListField = newWhiteList.join('\n'); var newWhiteListField = newWhiteList.join('\n');
var msg = ""; var msg = "";
var isInProgress = false; var isInProgress = false;
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate("IP Whitelisting")), title: Text(translate("IP Whitelisting")),
content: Column( content: Column(
@ -980,7 +980,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
} }
var isInProgress = false; var isInProgress = false;
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate("Socks5 Proxy")), title: Text(translate("Socks5 Proxy")),
content: ConstrainedBox( content: ConstrainedBox(
@ -1117,7 +1117,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
final license = await bind.mainGetLicense(); final license = await bind.mainGetLicense();
final version = await bind.mainGetVersion(); final version = await bind.mainGetVersion();
final linkStyle = TextStyle(decoration: TextDecoration.underline); final linkStyle = TextStyle(decoration: TextDecoration.underline);
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text("About $appName"), title: Text("About $appName"),
content: ConstrainedBox( content: ConstrainedBox(
@ -1208,7 +1208,7 @@ Future<bool> loginDialog() async {
var isInProgress = false; var isInProgress = false;
var completer = Completer<bool>(); var completer = Completer<bool>();
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate("Login")), title: Text(translate("Login")),
content: ConstrainedBox( content: ConstrainedBox(
@ -1339,7 +1339,7 @@ void setPasswordDialog() async {
var errMsg0 = ""; var errMsg0 = "";
var errMsg1 = ""; var errMsg1 = "";
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate("Set Password")), title: Text(translate("Set Password")),
content: ConstrainedBox( content: ConstrainedBox(

View File

@ -4,7 +4,6 @@ import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/mobile/pages/file_manager_page.dart'; import 'package:flutter_hbb/mobile/pages/file_manager_page.dart';
import 'package:flutter_hbb/models/file_model.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:get/get.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wakelock/wakelock.dart'; import 'package:wakelock/wakelock.dart';
@ -26,8 +25,7 @@ class _FileManagerPageState extends State<FileManagerPage>
final _localSelectedItems = SelectedItems(); final _localSelectedItems = SelectedItems();
final _remoteSelectedItems = SelectedItems(); final _remoteSelectedItems = SelectedItems();
/// FFI with name file_transfer_id late FFI _ffi;
FFI get _ffi => ffi('ft_${widget.id}');
FileModel get model => _ffi.fileModel; FileModel get model => _ffi.fileModel;
@ -38,8 +36,9 @@ class _FileManagerPageState extends State<FileManagerPage>
@override @override
void initState() { void initState() {
super.initState(); super.initState();
Get.put(FFI()..connect(widget.id, isFileTransfer: true), _ffi = FFI();
tag: 'ft_${widget.id}'); _ffi.connect(widget.id, isFileTransfer: true);
Get.put(_ffi, tag: 'ft_${widget.id}');
// _ffi.ffiModel.updateEventListener(widget.id); // _ffi.ffiModel.updateEventListener(widget.id);
if (!Platform.isLinux) { if (!Platform.isLinux) {
Wakelock.enable(); Wakelock.enable();
@ -51,7 +50,7 @@ class _FileManagerPageState extends State<FileManagerPage>
void dispose() { void dispose() {
model.onClose(); model.onClose();
_ffi.close(); _ffi.close();
SmartDialog.dismiss(); _ffi.dialogManager.dismissAll();
if (!Platform.isLinux) { if (!Platform.isLinux) {
Wakelock.disable(); Wakelock.disable();
} }
@ -552,7 +551,7 @@ class _FileManagerPageState extends State<FileManagerPage>
IconButton( IconButton(
onPressed: () { onPressed: () {
final name = TextEditingController(); final name = TextEditingController();
DialogManager.show((setState, close) => _ffi.dialogManager.show((setState, close) =>
CustomAlertDialog( CustomAlertDialog(
title: Text(translate("Create Folder")), title: Text(translate("Create Folder")),
content: Column( content: Column(

View File

@ -7,9 +7,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hbb/mobile/widgets/gesture_help.dart'; import 'package:flutter_hbb/mobile/widgets/gesture_help.dart';
import 'package:flutter_hbb/models/chat_model.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/get.dart';
import 'package:get/route_manager.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wakelock/wakelock.dart'; import 'package:wakelock/wakelock.dart';
@ -51,18 +49,19 @@ class _RemotePageState extends State<RemotePage>
var _showEdit = false; // use soft keyboard var _showEdit = false; // use soft keyboard
var _isPhysicalMouse = false; var _isPhysicalMouse = false;
FFI get _ffi => ffi(widget.id); late FFI _ffi;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
var ffitmp = FFI(); _ffi = FFI();
ffitmp.canvasModel.tabBarHeight = super.widget.tabBarHeight; _ffi.canvasModel.tabBarHeight = super.widget.tabBarHeight;
final ffi = Get.put(ffitmp, tag: widget.id); Get.put(_ffi, tag: widget.id);
ffi.connect(widget.id, tabBarHeight: super.widget.tabBarHeight); _ffi.connect(widget.id, tabBarHeight: super.widget.tabBarHeight);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
showLoading(translate('Connecting...')); _ffi.dialogManager
.showLoading(translate('Connecting...'), cancelToClose: true);
_interval = _interval =
Timer.periodic(Duration(milliseconds: 30), (timer) => interval()); Timer.periodic(Duration(milliseconds: 30), (timer) => interval());
}); });
@ -70,8 +69,8 @@ class _RemotePageState extends State<RemotePage>
Wakelock.enable(); Wakelock.enable();
} }
_physicalFocusNode.requestFocus(); _physicalFocusNode.requestFocus();
ffi.ffiModel.updateEventListener(widget.id); _ffi.ffiModel.updateEventListener(widget.id);
ffi.listenToMouse(true); _ffi.listenToMouse(true);
// WindowManager.instance.addListener(this); // WindowManager.instance.addListener(this);
} }
@ -86,7 +85,7 @@ class _RemotePageState extends State<RemotePage>
_ffi.close(); _ffi.close();
_interval?.cancel(); _interval?.cancel();
_timer?.cancel(); _timer?.cancel();
SmartDialog.dismiss(); _ffi.dialogManager.dismissAll();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values); overlays: SystemUiOverlay.values);
if (!Platform.isLinux) { if (!Platform.isLinux) {
@ -262,8 +261,11 @@ class _RemotePageState extends State<RemotePage>
initialEntries: [ initialEntries: [
OverlayEntry(builder: (context) { OverlayEntry(builder: (context) {
_ffi.chatModel.setOverlayState(Overlay.of(context)); _ffi.chatModel.setOverlayState(Overlay.of(context));
_ffi.dialogManager.setOverlayState(Overlay.of(context));
return Container( return Container(
child: getRawPointerAndKeyBody(getBodyForDesktop(keyboard))); color: Colors.black,
child: getRawPointerAndKeyBody(
getBodyForDesktop(context, keyboard)));
}) })
], ],
)); ));
@ -275,7 +277,7 @@ class _RemotePageState extends State<RemotePage>
_ffi.canvasModel.tabBarHeight = super.widget.tabBarHeight; _ffi.canvasModel.tabBarHeight = super.widget.tabBarHeight;
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
clientClose(); clientClose(_ffi.dialogManager);
return false; return false;
}, },
child: MultiProvider( child: MultiProvider(
@ -410,7 +412,7 @@ class _RemotePageState extends State<RemotePage>
color: Colors.white, color: Colors.white,
icon: Icon(Icons.clear), icon: Icon(Icons.clear),
onPressed: () { onPressed: () {
clientClose(); clientClose(_ffi.dialogManager);
}, },
) )
] + ] +
@ -420,7 +422,7 @@ class _RemotePageState extends State<RemotePage>
icon: Icon(Icons.tv), icon: Icon(Icons.tv),
onPressed: () { onPressed: () {
setState(() => _showEdit = false); setState(() => _showEdit = false);
showOptions(widget.id); showOptions(widget.id, _ffi.dialogManager);
}, },
) )
] + ] +
@ -497,7 +499,7 @@ class _RemotePageState extends State<RemotePage>
/// DoubleFiner -> right click /// DoubleFiner -> right click
/// HoldDrag -> left drag /// HoldDrag -> left drag
Widget getBodyForDesktop(bool keyboard) { Widget getBodyForDesktop(BuildContext context, bool keyboard) {
var paints = <Widget>[ var paints = <Widget>[
MouseRegion(onEnter: (evt) { MouseRegion(onEnter: (evt) {
bind.hostStopSystemKeyPropagate(stopped: false); bind.hostStopSystemKeyPropagate(stopped: false);
@ -567,7 +569,7 @@ class _RemotePageState extends State<RemotePage>
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
showSetOSPassword(widget.id, false); showSetOSPassword(widget.id, false, _ffi.dialogManager);
}, },
child: Icon(Icons.edit, color: MyTheme.accent), child: Icon(Icons.edit, color: MyTheme.accent),
) )
@ -632,7 +634,7 @@ class _RemotePageState extends State<RemotePage>
if (password != null) { if (password != null) {
bind.sessionInputOsPassword(id: widget.id, value: password); bind.sessionInputOsPassword(id: widget.id, value: password);
} else { } else {
showSetOSPassword(widget.id, true); showSetOSPassword(widget.id, true, _ffi.dialogManager);
} }
} else if (value == 'reset_canvas') { } else if (value == 'reset_canvas') {
_ffi.cursorModel.reset(); _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'; String quality = await bind.getSessionImageQuality(id: id) ?? 'balanced';
if (quality == '') quality = 'balanced'; if (quality == '') quality = 'balanced';
String viewStyle = String viewStyle =
@ -907,7 +909,7 @@ void showOptions(String id) async {
onTap: () { onTap: () {
if (i == cur) return; if (i == cur) return;
bind.sessionSwitchDisplay(id: id, value: i); bind.sessionSwitchDisplay(id: id, value: i);
SmartDialog.dismiss(); dialogManager.dismissAll();
}, },
child: Ink( child: Ink(
width: 40, width: 40,
@ -932,7 +934,7 @@ void showOptions(String id) async {
} }
final perms = ffi(id).ffiModel.permissions; final perms = ffi(id).ffiModel.permissions;
DialogManager.show((setState, close) { dialogManager.show((setState, close) {
final more = <Widget>[]; final more = <Widget>[];
if (perms['audio'] != false) { if (perms['audio'] != false) {
more.add(getToggle(id, setState, 'disable-audio', 'Mute')); more.add(getToggle(id, setState, 'disable-audio', 'Mute'));
@ -990,12 +992,13 @@ void showOptions(String id) async {
}, clickMaskDismiss: true, backDismiss: true); }, clickMaskDismiss: true, backDismiss: true);
} }
void showSetOSPassword(String id, bool login) async { void showSetOSPassword(
String id, bool login, OverlayDialogManager dialogManager) async {
final controller = TextEditingController(); final controller = TextEditingController();
var password = await bind.getSessionOption(id: id, arg: "os-password") ?? ""; var password = await bind.getSessionOption(id: id, arg: "os-password") ?? "";
var autoLogin = await bind.getSessionOption(id: id, arg: "auto-login") != ""; var autoLogin = await bind.getSessionOption(id: id, arg: "auto-login") != "";
controller.text = password; controller.text = password;
DialogManager.show((setState, close) { dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate('OS Password')), title: Text(translate('OS Password')),
content: Column(mainAxisSize: MainAxisSize.min, children: [ content: Column(mainAxisSize: MainAxisSize.min, children: [

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/desktop/pages/file_manager_tab_page.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'; import 'package:provider/provider.dart';
/// multi-tab file transfer remote screen /// multi-tab file transfer remote screen

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/desktop/pages/connection_tab_page.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'; import 'package:provider/provider.dart';
/// multi-tab desktop remote screen /// multi-tab desktop remote screen

View File

@ -258,7 +258,7 @@ class _PeerCardState extends State<_PeerCard>
final tags = List.of(gFFI.abModel.tags); final tags = List.of(gFFI.abModel.tags);
var selectedTag = gFFI.abModel.getPeerTags(id).obs; var selectedTag = gFFI.abModel.getPeerTags(id).obs;
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate("Edit Tag")), title: Text(translate("Edit Tag")),
content: Column( content: Column(
@ -314,7 +314,7 @@ class _PeerCardState extends State<_PeerCard>
} }
} }
final k = GlobalKey<FormState>(); final k = GlobalKey<FormState>();
DialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate("Rename")), title: Text(translate("Rename")),
content: Column( content: Column(

View File

@ -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_file_transfer_screen.dart';
import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart'; import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart';
import 'package:flutter_hbb/utils/multi_window_manager.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/get.dart';
import 'package:get/route_manager.dart'; import 'package:get/route_manager.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -95,14 +94,7 @@ void runRemoteScreen(Map<String, dynamic> argument) async {
), ),
navigatorObservers: [ navigatorObservers: [
// FirebaseAnalyticsObserver(analytics: analytics), // FirebaseAnalyticsObserver(analytics: analytics),
FlutterSmartDialog.observer
], ],
builder: FlutterSmartDialog.init(
builder: isAndroid
? (_, child) => AccessibilityListener(
child: child,
)
: null),
)); ));
} }
@ -116,14 +108,7 @@ void runFileTransferScreen(Map<String, dynamic> argument) async {
home: DesktopFileTransferScreen(params: argument), home: DesktopFileTransferScreen(params: argument),
navigatorObservers: [ navigatorObservers: [
// FirebaseAnalyticsObserver(analytics: analytics), // FirebaseAnalyticsObserver(analytics: analytics),
FlutterSmartDialog.observer ]));
],
builder: FlutterSmartDialog.init(
builder: isAndroid
? (_, child) => AccessibilityListener(
child: child,
)
: null)));
} }
class App extends StatelessWidget { class App extends StatelessWidget {
@ -153,14 +138,12 @@ class App extends StatelessWidget {
: HomePage(), : HomePage(),
navigatorObservers: [ navigatorObservers: [
// FirebaseAnalyticsObserver(analytics: analytics), // FirebaseAnalyticsObserver(analytics: analytics),
FlutterSmartDialog.observer
], ],
builder: FlutterSmartDialog.init( builder: isAndroid
builder: isAndroid ? (_, child) => AccessibilityListener(
? (_, child) => AccessibilityListener( child: child,
child: child, )
) : null),
: null)),
); );
} }
} }

View File

@ -380,16 +380,16 @@ class _WebMenuState extends State<WebMenu> {
}, },
onSelected: (value) { onSelected: (value) {
if (value == 'server') { if (value == 'server') {
showServerSettings(); showServerSettings(gFFI.dialogManager);
} }
if (value == 'about') { if (value == 'about') {
showAbout(); showAbout(gFFI.dialogManager);
} }
if (value == 'login') { if (value == 'login') {
if (username == null) { if (username == null) {
showLogin(); showLogin(gFFI.dialogManager);
} else { } else {
logout(); logout(gFFI.dialogManager);
} }
} }
if (value == 'scan') { if (value == 'scan') {

View File

@ -3,13 +3,11 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_breadcrumb/flutter_breadcrumb.dart'; import 'package:flutter_breadcrumb/flutter_breadcrumb.dart';
import 'package:flutter_hbb/models/file_model.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:provider/provider.dart';
import 'package:toggle_switch/toggle_switch.dart'; import 'package:toggle_switch/toggle_switch.dart';
import 'package:wakelock/wakelock.dart'; import 'package:wakelock/wakelock.dart';
import '../../common.dart'; import '../../common.dart';
import '../../models/model.dart';
import '../widgets/dialog.dart'; import '../widgets/dialog.dart';
class FileManagerPage extends StatefulWidget { class FileManagerPage extends StatefulWidget {
@ -29,7 +27,10 @@ class _FileManagerPageState extends State<FileManagerPage> {
void initState() { void initState() {
super.initState(); super.initState();
gFFI.connect(widget.id, isFileTransfer: true); gFFI.connect(widget.id, isFileTransfer: true);
showLoading(translate('Connecting...')); WidgetsBinding.instance.addPostFrameCallback((_) {
gFFI.dialogManager
.showLoading(translate('Connecting...'), cancelToClose: true);
});
gFFI.ffiModel.updateEventListener(widget.id); gFFI.ffiModel.updateEventListener(widget.id);
Wakelock.enable(); Wakelock.enable();
} }
@ -38,7 +39,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
void dispose() { void dispose() {
model.onClose(); model.onClose();
gFFI.close(); gFFI.close();
SmartDialog.dismiss(); gFFI.dialogManager.dismissAll();
Wakelock.disable(); Wakelock.disable();
super.dispose(); super.dispose();
} }
@ -60,7 +61,9 @@ class _FileManagerPageState extends State<FileManagerPage> {
backgroundColor: MyTheme.grayBg, backgroundColor: MyTheme.grayBg,
appBar: AppBar( appBar: AppBar(
leading: Row(children: [ leading: Row(children: [
IconButton(icon: Icon(Icons.close), onPressed: clientClose), IconButton(
icon: Icon(Icons.close),
onPressed: () => clientClose(gFFI.dialogManager)),
]), ]),
centerTitle: true, centerTitle: true,
title: ToggleSwitch( title: ToggleSwitch(
@ -141,8 +144,8 @@ class _FileManagerPageState extends State<FileManagerPage> {
model.toggleSelectMode(); model.toggleSelectMode();
} else if (v == "folder") { } else if (v == "folder") {
final name = TextEditingController(); final name = TextEditingController();
DialogManager.show( gFFI.dialogManager
(setState, close) => CustomAlertDialog( .show((setState, close) => CustomAlertDialog(
title: Text(translate("Create Folder")), title: Text(translate("Create Folder")),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

View File

@ -6,7 +6,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hbb/mobile/widgets/gesture_help.dart'; import 'package:flutter_hbb/mobile/widgets/gesture_help.dart';
import 'package:flutter_hbb/models/chat_model.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:provider/provider.dart';
import 'package:wakelock/wakelock.dart'; import 'package:wakelock/wakelock.dart';
@ -51,7 +50,8 @@ class _RemotePageState extends State<RemotePage> {
gFFI.connect(widget.id); gFFI.connect(widget.id);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
showLoading(translate('Connecting...')); gFFI.dialogManager
.showLoading(translate('Connecting...'), cancelToClose: true);
_interval = _interval =
Timer.periodic(Duration(milliseconds: 30), (timer) => interval()); Timer.periodic(Duration(milliseconds: 30), (timer) => interval());
}); });
@ -71,7 +71,7 @@ class _RemotePageState extends State<RemotePage> {
gFFI.close(); gFFI.close();
_interval?.cancel(); _interval?.cancel();
_timer?.cancel(); _timer?.cancel();
SmartDialog.dismiss(); gFFI.dialogManager.dismissAll();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values); overlays: SystemUiOverlay.values);
Wakelock.disable(); Wakelock.disable();
@ -226,7 +226,7 @@ class _RemotePageState extends State<RemotePage> {
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
clientClose(); clientClose(gFFI.dialogManager);
return false; return false;
}, },
child: getRawPointerAndKeyBody( child: getRawPointerAndKeyBody(
@ -401,7 +401,7 @@ class _RemotePageState extends State<RemotePage> {
color: Colors.white, color: Colors.white,
icon: Icon(Icons.clear), icon: Icon(Icons.clear),
onPressed: () { onPressed: () {
clientClose(); clientClose(gFFI.dialogManager);
}, },
) )
] + ] +
@ -411,7 +411,7 @@ class _RemotePageState extends State<RemotePage> {
icon: Icon(Icons.tv), icon: Icon(Icons.tv),
onPressed: () { onPressed: () {
setState(() => _showEdit = false); setState(() => _showEdit = false);
showOptions(widget.id); showOptions(widget.id, gFFI.dialogManager);
}, },
) )
] + ] +
@ -671,7 +671,7 @@ class _RemotePageState extends State<RemotePage> {
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
showSetOSPassword(id, false); showSetOSPassword(id, false, gFFI.dialogManager);
}, },
child: Icon(Icons.edit, color: MyTheme.accent), child: Icon(Icons.edit, color: MyTheme.accent),
) )
@ -739,12 +739,12 @@ class _RemotePageState extends State<RemotePage> {
if (password != null) { if (password != null) {
bind.sessionInputOsPassword(id: widget.id, value: password); bind.sessionInputOsPassword(id: widget.id, value: password);
} else { } else {
showSetOSPassword(id, true); showSetOSPassword(id, true, gFFI.dialogManager);
} }
} else if (value == 'reset_canvas') { } else if (value == 'reset_canvas') {
gFFI.cursorModel.reset(); gFFI.cursorModel.reset();
} else if (value == 'restart') { } else if (value == 'restart') {
showRestartRemoteDevice(pi, widget.id); showRestartRemoteDevice(pi, widget.id, gFFI.dialogManager);
} }
}(); }();
} }
@ -1008,7 +1008,7 @@ class QualityMonitor extends StatelessWidget {
: SizedBox.shrink()))); : SizedBox.shrink())));
} }
void showOptions(String id) async { void showOptions(String id, OverlayDialogManager dialogManager) async {
String quality = await bind.getSessionImageQuality(id: id) ?? 'balanced'; String quality = await bind.getSessionImageQuality(id: id) ?? 'balanced';
if (quality == '') quality = 'balanced'; if (quality == '') quality = 'balanced';
String viewStyle = String viewStyle =
@ -1026,7 +1026,7 @@ void showOptions(String id) async {
onTap: () { onTap: () {
if (i == cur) return; if (i == cur) return;
bind.sessionSwitchDisplay(id: id, value: i); bind.sessionSwitchDisplay(id: id, value: i);
SmartDialog.dismiss(); gFFI.dialogManager.dismissAll();
}, },
child: Ink( child: Ink(
width: 40, width: 40,
@ -1051,7 +1051,7 @@ void showOptions(String id) async {
} }
final perms = gFFI.ffiModel.permissions; final perms = gFFI.ffiModel.permissions;
DialogManager.show((setState, close) { dialogManager.show((setState, close) {
final more = <Widget>[]; final more = <Widget>[];
if (perms['audio'] != false) { if (perms['audio'] != false) {
more.add(getToggle(id, setState, 'disable-audio', 'Mute')); more.add(getToggle(id, setState, 'disable-audio', 'Mute'));
@ -1107,9 +1107,10 @@ void showOptions(String id) async {
}, clickMaskDismiss: true, backDismiss: true); }, clickMaskDismiss: true, backDismiss: true);
} }
void showRestartRemoteDevice(PeerInfo pi, String id) async { void showRestartRemoteDevice(
PeerInfo pi, String id, OverlayDialogManager dialogManager) async {
final res = final res =
await DialogManager.show<bool>((setState, close) => CustomAlertDialog( await dialogManager.show<bool>((setState, close) => CustomAlertDialog(
title: Row(children: [ title: Row(children: [
Icon(Icons.warning_amber_sharp, Icon(Icons.warning_amber_sharp,
color: Colors.redAccent, size: 28), color: Colors.redAccent, size: 28),
@ -1128,12 +1129,13 @@ void showRestartRemoteDevice(PeerInfo pi, String id) async {
if (res == true) bind.sessionRestartRemoteDevice(id: id); 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(); final controller = TextEditingController();
var password = await bind.getSessionOption(id: id, arg: "os-password") ?? ""; var password = await bind.getSessionOption(id: id, arg: "os-password") ?? "";
var autoLogin = await bind.getSessionOption(id: id, arg: "auto-login") != ""; var autoLogin = await bind.getSessionOption(id: id, arg: "auto-login") != "";
controller.text = password; controller.text = password;
DialogManager.show((setState, close) { dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate('OS Password')), title: Text(translate('OS Password')),
content: Column(mainAxisSize: MainAxisSize.min, children: [ content: Column(mainAxisSize: MainAxisSize.min, children: [

View File

@ -63,7 +63,7 @@ class _ScanPageState extends State<ScanPage> {
var result = reader.decode(bitmap); var result = reader.decode(bitmap);
showServerSettingFromQr(result.text); showServerSettingFromQr(result.text);
} catch (e) { } catch (e) {
showToast('No QR code found'); gFFI.dialogManager.showToast('No QR code found');
} }
} }
}), }),
@ -121,7 +121,7 @@ class _ScanPageState extends State<ScanPage> {
void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) { void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
if (!p) { if (!p) {
showToast('No permisssion'); gFFI.dialogManager.showToast('No permisssion');
} }
} }
@ -132,10 +132,10 @@ class _ScanPageState extends State<ScanPage> {
} }
void showServerSettingFromQr(String data) async { void showServerSettingFromQr(String data) async {
backToHome(); backToHomePage();
await controller?.pauseCamera(); await controller?.pauseCamera();
if (!data.startsWith('config=')) { if (!data.startsWith('config=')) {
showToast('Invalid QR code'); gFFI.dialogManager.showToast('Invalid QR code');
return; return;
} }
try { try {
@ -144,16 +144,16 @@ class _ScanPageState extends State<ScanPage> {
var key = values['key'] != null ? values['key'] as String : ''; var key = values['key'] != null ? values['key'] as String : '';
var api = values['api'] != null ? values['api'] as String : ''; var api = values['api'] != null ? values['api'] as String : '';
Timer(Duration(milliseconds: 60), () { Timer(Duration(milliseconds: 60), () {
showServerSettingsWithValue(host, '', key, api); showServerSettingsWithValue(host, '', key, api, gFFI.dialogManager);
}); });
} catch (e) { } catch (e) {
showToast('Invalid QR code'); gFFI.dialogManager.showToast('Invalid QR code');
} }
} }
} }
void showServerSettingsWithValue( void showServerSettingsWithValue(String id, String relay, String key,
String id, String relay, String key, String api) async { String api, OverlayDialogManager dialogManager) async {
Map<String, dynamic> oldOptions = jsonDecode(await bind.mainGetOptions()); Map<String, dynamic> oldOptions = jsonDecode(await bind.mainGetOptions());
String id0 = oldOptions['custom-rendezvous-server'] ?? ""; String id0 = oldOptions['custom-rendezvous-server'] ?? "";
String relay0 = oldOptions['relay-server'] ?? ""; String relay0 = oldOptions['relay-server'] ?? "";
@ -168,7 +168,7 @@ void showServerSettingsWithValue(
String? relayServerMsg; String? relayServerMsg;
String? apiServerMsg; String? apiServerMsg;
DialogManager.show((setState, close) { dialogManager.show((setState, close) {
Future<bool> validate() async { Future<bool> validate() async {
if (idController.text != id) { if (idController.text != id) {
final res = await validateAsync(idController.text); final res = await validateAsync(idController.text);

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/mobile/widgets/dialog.dart'; import 'package:flutter_hbb/mobile/widgets/dialog.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../common.dart'; import '../../common.dart';
@ -90,9 +89,9 @@ class ServerPage extends StatefulWidget implements PageShape {
if (value == "changeID") { if (value == "changeID") {
// TODO // TODO
} else if (value == "setPermanentPassword") { } else if (value == "setPermanentPassword") {
setPermanentPasswordDialog(); setPermanentPasswordDialog(gFFI.dialogManager);
} else if (value == "setTemporaryPasswordLength") { } else if (value == "setTemporaryPasswordLength") {
setTemporaryPasswordLengthDialog(); setTemporaryPasswordLengthDialog(gFFI.dialogManager);
} else if (value == kUsePermanentPassword || } else if (value == kUsePermanentPassword ||
value == kUseTemporaryPassword || value == kUseTemporaryPassword ||
value == kUseBothPasswords) { value == kUseBothPasswords) {
@ -522,7 +521,7 @@ void toAndroidChannelInit() {
switch (method) { switch (method) {
case "start_capture": case "start_capture":
{ {
SmartDialog.dismiss(); gFFI.dialogManager.dismissAll();
gFFI.serverModel.updateClientState(); gFFI.serverModel.updateClientState();
break; break;
} }

View File

@ -119,8 +119,8 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
if (v) { if (v) {
PermissionManager.request("ignore_battery_optimizations"); PermissionManager.request("ignore_battery_optimizations");
} else { } else {
final res = await DialogManager.show<bool>( final res = await gFFI.dialogManager
(setState, close) => CustomAlertDialog( .show<bool>((setState, close) => CustomAlertDialog(
title: Text(translate("Open System Setting")), title: Text(translate("Open System Setting")),
content: Text(translate( content: Text(translate(
"android_open_battery_optimizations_tip")), "android_open_battery_optimizations_tip")),
@ -153,9 +153,9 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
leading: Icon(Icons.person), leading: Icon(Icons.person),
onPressed: (context) { onPressed: (context) {
if (username == null) { if (username == null) {
showLogin(); showLogin(gFFI.dialogManager);
} else { } else {
logout(); logout(gFFI.dialogManager);
} }
}, },
), ),
@ -166,13 +166,13 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
title: Text(translate('ID/Relay Server')), title: Text(translate('ID/Relay Server')),
leading: Icon(Icons.cloud), leading: Icon(Icons.cloud),
onPressed: (context) { onPressed: (context) {
showServerSettings(); showServerSettings(gFFI.dialogManager);
}), }),
SettingsTile.navigation( SettingsTile.navigation(
title: Text(translate('Language')), title: Text(translate('Language')),
leading: Icon(Icons.translate), leading: Icon(Icons.translate),
onPressed: (context) { onPressed: (context) {
showLanguageSettings(); showLanguageSettings(gFFI.dialogManager);
}) })
]), ]),
SettingsSection( SettingsSection(
@ -204,20 +204,20 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
} }
} }
void showServerSettings() async { void showServerSettings(OverlayDialogManager dialogManager) async {
Map<String, dynamic> options = jsonDecode(await bind.mainGetOptions()); Map<String, dynamic> options = jsonDecode(await bind.mainGetOptions());
String id = options['custom-rendezvous-server'] ?? ""; String id = options['custom-rendezvous-server'] ?? "";
String relay = options['relay-server'] ?? ""; String relay = options['relay-server'] ?? "";
String api = options['api-server'] ?? ""; String api = options['api-server'] ?? "";
String key = options['key'] ?? ""; String key = options['key'] ?? "";
showServerSettingsWithValue(id, relay, key, api); showServerSettingsWithValue(id, relay, key, api, dialogManager);
} }
void showLanguageSettings() async { void showLanguageSettings(OverlayDialogManager dialogManager) async {
try { try {
final langs = json.decode(await bind.mainGetLangs()) as List<dynamic>; final langs = json.decode(await bind.mainGetLangs()) as List<dynamic>;
var lang = await bind.mainGetLocalOption(key: "lang"); var lang = await bind.mainGetLocalOption(key: "lang");
DialogManager.show((setState, close) { dialogManager.show((setState, close) {
final setLang = (v) { final setLang = (v) {
if (lang != v) { if (lang != v) {
setState(() { setState(() {
@ -246,8 +246,8 @@ void showLanguageSettings() async {
} catch (_e) {} } catch (_e) {}
} }
void showAbout() { void showAbout(OverlayDialogManager dialogManager) {
DialogManager.show((setState, close) { dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate('About') + ' RustDesk'), title: Text(translate('About') + ' RustDesk'),
content: Wrap(direction: Axis.vertical, spacing: 12, children: [ 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"); final token = await bind.mainGetOption(key: "access_token");
if (token == '') return; if (token == '') return;
final url = getUrl(); final url = getUrl();
@ -363,7 +363,7 @@ void logout() async {
}, },
body: json.encode(body)); body: json.encode(body));
} catch (e) { } catch (e) {
showToast('Failed to access $url'); dialogManager.showToast('Failed to access $url');
} }
resetToken(); resetToken();
} }
@ -396,12 +396,12 @@ Future<String> getUrl() async {
return url; return url;
} }
void showLogin() { void showLogin(OverlayDialogManager dialogManager) {
final passwordController = TextEditingController(); final passwordController = TextEditingController();
final nameController = TextEditingController(); final nameController = TextEditingController();
var loading = false; var loading = false;
var error = ''; var error = '';
DialogManager.show((setState, close) { dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate('Login')), title: Text(translate('Login')),
content: Column(mainAxisSize: MainAxisSize.min, children: [ content: Column(mainAxisSize: MainAxisSize.min, children: [

View File

@ -1,32 +1,31 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import '../../common.dart'; import '../../common.dart';
import '../../models/platform_model.dart'; import '../../models/platform_model.dart';
void clientClose() { void clientClose(OverlayDialogManager dialogManager) {
msgBox('', 'Close', 'Are you sure to close the connection?'); msgBox('', 'Close', 'Are you sure to close the connection?', dialogManager);
} }
const SEC1 = Duration(seconds: 1); const SEC1 = Duration(seconds: 1);
void showSuccess({Duration duration = SEC1}) { void showSuccess({Duration duration = SEC1}) {
SmartDialog.dismiss(); // TODO
showToast(translate("Successful"), duration: SEC1); // showToast(translate("Successful"), duration: SEC1);
} }
void showError({Duration duration = SEC1}) { void showError({Duration duration = SEC1}) {
SmartDialog.dismiss(); // TODO
showToast(translate("Error"), duration: SEC1); // showToast(translate("Error"), duration: SEC1);
} }
void setPermanentPasswordDialog() async { void setPermanentPasswordDialog(OverlayDialogManager dialogManager) async {
final pw = await bind.mainGetPermanentPassword(); final pw = await bind.mainGetPermanentPassword();
final p0 = TextEditingController(text: pw); final p0 = TextEditingController(text: pw);
final p1 = TextEditingController(text: pw); final p1 = TextEditingController(text: pw);
var validateLength = false; var validateLength = false;
var validateSame = false; var validateSame = false;
DialogManager.show((setState, close) { dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate('Set your own password')), title: Text(translate('Set your own password')),
content: Form( content: Form(
@ -86,7 +85,7 @@ void setPermanentPasswordDialog() async {
onPressed: (validateLength && validateSame) onPressed: (validateLength && validateSame)
? () async { ? () async {
close(); close();
showLoading(translate("Waiting")); dialogManager.showLoading(translate("Waiting"));
if (await gFFI.serverModel.setPermanentPassword(p0.text)) { if (await gFFI.serverModel.setPermanentPassword(p0.text)) {
showSuccess(); showSuccess();
} else { } else {
@ -101,13 +100,14 @@ void setPermanentPasswordDialog() async {
}); });
} }
void setTemporaryPasswordLengthDialog() async { void setTemporaryPasswordLengthDialog(
OverlayDialogManager dialogManager) async {
List<String> lengths = ['6', '8', '10']; List<String> lengths = ['6', '8', '10'];
String length = await bind.mainGetOption(key: "temporary-password-length"); String length = await bind.mainGetOption(key: "temporary-password-length");
var index = lengths.indexOf(length); var index = lengths.indexOf(length);
if (index < 0) index = 0; if (index < 0) index = 0;
length = lengths[index]; length = lengths[index];
DialogManager.show((setState, close) { dialogManager.show((setState, close) {
final setLength = (newValue) { final setLength = (newValue) {
final oldValue = length; final oldValue = length;
if (oldValue == newValue) return; if (oldValue == newValue) return;
@ -133,10 +133,11 @@ void setTemporaryPasswordLengthDialog() async {
}, backDismiss: true, clickMaskDismiss: true); }, backDismiss: true, clickMaskDismiss: true);
} }
void enterPasswordDialog(String id) async { void enterPasswordDialog(String id, OverlayDialogManager dialogManager) async {
final controller = TextEditingController(); final controller = TextEditingController();
var remember = await bind.getSessionRemember(id: id) ?? false; var remember = await bind.getSessionRemember(id: id) ?? false;
DialogManager.show((setState, close) { dialogManager.dismissAll();
dialogManager.show((setState, close) {
return CustomAlertDialog( return CustomAlertDialog(
title: Text(translate('Password Required')), title: Text(translate('Password Required')),
content: Column(mainAxisSize: MainAxisSize.min, children: [ content: Column(mainAxisSize: MainAxisSize.min, children: [
@ -161,7 +162,7 @@ void enterPasswordDialog(String id) async {
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
close(); close();
backToHome(); backToHomePage();
}, },
child: Text(translate('Cancel')), child: Text(translate('Cancel')),
), ),
@ -172,7 +173,8 @@ void enterPasswordDialog(String id) async {
if (text == '') return; if (text == '') return;
gFFI.login(id, text, remember); gFFI.login(id, text, remember);
close(); close();
showLoading(translate('Logging in...')); dialogManager.showLoading(translate('Logging in...'),
cancelToClose: true);
}, },
child: Text(translate('OK')), child: Text(translate('OK')),
), ),
@ -181,8 +183,8 @@ void enterPasswordDialog(String id) async {
}); });
} }
void wrongPasswordDialog(String id) { void wrongPasswordDialog(String id, OverlayDialogManager dialogManager) {
DialogManager.show((setState, close) => CustomAlertDialog( dialogManager.show((setState, close) => CustomAlertDialog(
title: Text(translate('Wrong Password')), title: Text(translate('Wrong Password')),
content: Text(translate('Do you want to enter again?')), content: Text(translate('Do you want to enter again?')),
actions: [ actions: [
@ -190,14 +192,14 @@ void wrongPasswordDialog(String id) {
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
close(); close();
backToHome(); backToHomePage();
}, },
child: Text(translate('Cancel')), child: Text(translate('Cancel')),
), ),
TextButton( TextButton(
style: flatButtonStyle, style: flatButtonStyle,
onPressed: () { onPressed: () {
enterPasswordDialog(id); enterPasswordDialog(id, dialogManager);
}, },
child: Text(translate('Retry')), child: Text(translate('Retry')),
), ),
@ -239,8 +241,8 @@ class _PasswordWidgetState extends State<PasswordWidget> {
//This will obscure text dynamically //This will obscure text dynamically
keyboardType: TextInputType.visiblePassword, keyboardType: TextInputType.visiblePassword,
decoration: InputDecoration( decoration: InputDecoration(
labelText: Translator.call('Password'), labelText: translate('Password'),
hintText: Translator.call('Enter your password'), hintText: translate('Enter your password'),
// Here is key idea // Here is key idea
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(

View File

@ -4,7 +4,6 @@ import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/mobile/pages/file_manager_page.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:get/get.dart';
import 'package:path/path.dart' as Path; import 'package:path/path.dart' as Path;
@ -126,9 +125,9 @@ class FileModel extends ChangeNotifier {
final _jobResultListener = JobResultListener<Map<String, dynamic>>(); final _jobResultListener = JobResultListener<Map<String, dynamic>>();
final WeakReference<FFI> _ffi; final WeakReference<FFI> parent;
FileModel(this._ffi); FileModel(this.parent);
toggleSelectMode() { toggleSelectMode() {
if (jobState == JobState.inProgress) { if (jobState == JobState.inProgress) {
@ -275,7 +274,7 @@ class FileModel extends ChangeNotifier {
need_override = true; need_override = true;
} }
bind.sessionSetConfirmOverrideFile( bind.sessionSetConfirmOverrideFile(
id: _ffi.target?.id ?? "", id: parent.target?.id ?? "",
actId: id, actId: id,
fileNum: int.parse(evt['file_num']), fileNum: int.parse(evt['file_num']),
needOverride: need_override, needOverride: need_override,
@ -292,22 +291,22 @@ class FileModel extends ChangeNotifier {
onReady() async { onReady() async {
_localOption.home = await bind.mainGetHomeDir(); _localOption.home = await bind.mainGetHomeDir();
_localOption.showHidden = (await bind.sessionGetPeerOption( _localOption.showHidden = (await bind.sessionGetPeerOption(
id: _ffi.target?.id ?? "", name: "local_show_hidden")) id: parent.target?.id ?? "", name: "local_show_hidden"))
.isNotEmpty; .isNotEmpty;
_remoteOption.showHidden = (await bind.sessionGetPeerOption( _remoteOption.showHidden = (await bind.sessionGetPeerOption(
id: _ffi.target?.id ?? "", name: "remote_show_hidden")) id: parent.target?.id ?? "", name: "remote_show_hidden"))
.isNotEmpty; .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)); await Future.delayed(Duration(milliseconds: 100));
final local = (await bind.sessionGetPeerOption( final local = (await bind.sessionGetPeerOption(
id: _ffi.target?.id ?? "", name: "local_dir")); id: parent.target?.id ?? "", name: "local_dir"));
final remote = (await bind.sessionGetPeerOption( 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(local.isEmpty ? _localOption.home : local, isLocal: true);
openDirectory(remote.isEmpty ? _remoteOption.home : remote, isLocal: false); openDirectory(remote.isEmpty ? _remoteOption.home : remote, isLocal: false);
await Future.delayed(Duration(seconds: 1)); await Future.delayed(Duration(seconds: 1));
@ -318,11 +317,11 @@ class FileModel extends ChangeNotifier {
openDirectory(_remoteOption.home, isLocal: false); openDirectory(_remoteOption.home, isLocal: false);
} }
// load last transfer jobs // load last transfer jobs
await bind.sessionLoadLastTransferJobs(id: '${_ffi.target?.id}'); await bind.sessionLoadLastTransferJobs(id: '${parent.target?.id}');
} }
onClose() { onClose() {
SmartDialog.dismiss(); parent.target?.dialogManager.dismissAll();
jobReset(); jobReset();
// save config // save config
@ -332,7 +331,7 @@ class FileModel extends ChangeNotifier {
msgMap["local_show_hidden"] = _localOption.showHidden ? "Y" : ""; msgMap["local_show_hidden"] = _localOption.showHidden ? "Y" : "";
msgMap["remote_dir"] = _currentRemoteDir.path; msgMap["remote_dir"] = _currentRemoteDir.path;
msgMap["remote_show_hidden"] = _remoteOption.showHidden ? "Y" : ""; msgMap["remote_show_hidden"] = _remoteOption.showHidden ? "Y" : "";
final id = _ffi.target?.id ?? ""; final id = parent.target?.id ?? "";
for (final msg in msgMap.entries) { for (final msg in msgMap.entries) {
bind.sessionPeerOption(id: id, name: msg.key, value: msg.value); bind.sessionPeerOption(id: id, name: msg.key, value: msg.value);
} }
@ -419,7 +418,7 @@ class FileModel extends ChangeNotifier {
..id = jobId ..id = jobId
..isRemote = isRemote); ..isRemote = isRemote);
bind.sessionSendFiles( bind.sessionSendFiles(
id: '${_ffi.target?.id}', id: '${parent.target?.id}',
actId: _jobId, actId: _jobId,
path: from.path, path: from.path,
to: PathUtil.join(toPath, from.name, isWindows), to: PathUtil.join(toPath, from.name, isWindows),
@ -477,14 +476,14 @@ class FileModel extends ChangeNotifier {
entries = [item]; entries = [item];
} else if (item.isDirectory) { } else if (item.isDirectory) {
title = translate("Not an empty directory"); title = translate("Not an empty directory");
showLoading(translate("Waiting")); parent.target?.dialogManager.showLoading(translate("Waiting"));
final fd = await _fileFetcher.fetchDirectoryRecursive( final fd = await _fileFetcher.fetchDirectoryRecursive(
_jobId, item.path, items.isLocal!, true); _jobId, item.path, items.isLocal!, true);
if (fd.path.isEmpty) { if (fd.path.isEmpty) {
fd.path = item.path; fd.path = item.path;
} }
fd.format(isWindows); fd.format(isWindows);
SmartDialog.dismiss(); parent.target?.dialogManager.dismissAll();
if (fd.entries.isEmpty) { if (fd.entries.isEmpty) {
final confirm = await showRemoveDialog( final confirm = await showRemoveDialog(
translate( translate(
@ -543,7 +542,7 @@ class FileModel extends ChangeNotifier {
Future<bool?> showRemoveDialog( Future<bool?> showRemoveDialog(
String title, String content, bool showCheckbox) async { String title, String content, bool showCheckbox) async {
return await DialogManager.show<bool>( return await parent.target?.dialogManager.show<bool>(
(setState, Function(bool v) close) => CustomAlertDialog( (setState, Function(bool v) close) => CustomAlertDialog(
title: Row( title: Row(
children: [ children: [
@ -594,7 +593,7 @@ class FileModel extends ChangeNotifier {
Future<bool?> showFileConfirmDialog( Future<bool?> showFileConfirmDialog(
String title, String content, bool showCheckbox) async { String title, String content, bool showCheckbox) async {
fileConfirmCheckboxRemember = false; fileConfirmCheckboxRemember = false;
return await DialogManager.show<bool?>( return await parent.target?.dialogManager.show<bool?>(
(setState, Function(bool? v) close) => CustomAlertDialog( (setState, Function(bool? v) close) => CustomAlertDialog(
title: Row( title: Row(
children: [ children: [
@ -648,7 +647,7 @@ class FileModel extends ChangeNotifier {
sendRemoveFile(String path, int fileNum, bool isLocal) { sendRemoveFile(String path, int fileNum, bool isLocal) {
bind.sessionRemoveFile( bind.sessionRemoveFile(
id: '${_ffi.target?.id}', id: '${parent.target?.id}',
actId: _jobId, actId: _jobId,
path: path, path: path,
isRemote: !isLocal, isRemote: !isLocal,
@ -657,7 +656,7 @@ class FileModel extends ChangeNotifier {
sendRemoveEmptyDir(String path, int fileNum, bool isLocal) { sendRemoveEmptyDir(String path, int fileNum, bool isLocal) {
bind.sessionRemoveAllEmptyDirs( bind.sessionRemoveAllEmptyDirs(
id: '${_ffi.target?.id}', id: '${parent.target?.id}',
actId: _jobId, actId: _jobId,
path: path, path: path,
isRemote: !isLocal); isRemote: !isLocal);
@ -667,14 +666,14 @@ class FileModel extends ChangeNotifier {
isLocal = isLocal ?? this.isLocal; isLocal = isLocal ?? this.isLocal;
_jobId++; _jobId++;
bind.sessionCreateDir( bind.sessionCreateDir(
id: '${_ffi.target?.id}', id: '${parent.target?.id}',
actId: _jobId, actId: _jobId,
path: path, path: path,
isRemote: !isLocal); isRemote: !isLocal);
} }
cancelJob(int id) async { cancelJob(int id) async {
bind.sessionCancelJob(id: '${_ffi.target?.id}', actId: id); bind.sessionCancelJob(id: '${parent.target?.id}', actId: id);
jobReset(); jobReset();
} }
@ -701,7 +700,7 @@ class FileModel extends ChangeNotifier {
} }
initFileFetcher() { initFileFetcher() {
_fileFetcher.id = _ffi.target?.id; _fileFetcher.id = parent.target?.id;
} }
void updateFolderFiles(Map<String, dynamic> evt) { void updateFolderFiles(Map<String, dynamic> evt) {
@ -742,7 +741,7 @@ class FileModel extends ChangeNotifier {
..state = JobState.paused; ..state = JobState.paused;
jobTable.add(jobProgress); jobTable.add(jobProgress);
bind.sessionAddJob( bind.sessionAddJob(
id: '${_ffi.target?.id}', id: '${parent.target?.id}',
isRemote: isRemote, isRemote: isRemote,
includeHidden: showHidden, includeHidden: showHidden,
actId: currJobId, actId: currJobId,
@ -757,7 +756,7 @@ class FileModel extends ChangeNotifier {
if (jobIndex != -1) { if (jobIndex != -1) {
final job = jobTable[jobIndex]; final job = jobTable[jobIndex];
bind.sessionResumeJob( 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; job.state = JobState.inProgress;
} else { } else {
debugPrint("jobId ${jobId} is not exists"); debugPrint("jobId ${jobId} is not exists");

View File

@ -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/file_model.dart';
import 'package:flutter_hbb/models/server_model.dart'; import 'package:flutter_hbb/models/server_model.dart';
import 'package:flutter_hbb/models/user_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:shared_preferences/shared_preferences.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
@ -60,7 +59,6 @@ class FfiModel with ChangeNotifier {
} }
FfiModel(this.parent) { FfiModel(this.parent) {
Translator.call = translate;
clear(); clear();
} }
@ -261,32 +259,35 @@ class FfiModel with ChangeNotifier {
/// Handle the message box event based on [evt] and [id]. /// Handle the message box event based on [evt] and [id].
void handleMsgBox(Map<String, dynamic> evt, String id) { void handleMsgBox(Map<String, dynamic> evt, String id) {
if (parent.target == null) return;
final dialogManager = parent.target!.dialogManager;
var type = evt['type']; var type = evt['type'];
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); wrongPasswordDialog(id, dialogManager);
} else if (type == 'input-password') { } else if (type == 'input-password') {
enterPasswordDialog(id); enterPasswordDialog(id, dialogManager);
} else if (type == 'restarting') { } else if (type == 'restarting') {
showMsgBox(id, type, title, text, false, hasCancel: false); showMsgBox(id, type, title, text, false, dialogManager, hasCancel: false);
} else { } else {
var hasRetry = evt['hasRetry'] == 'true'; 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]. /// Show a message box with [type], [title] and [text].
void showMsgBox( void showMsgBox(String id, String type, String title, String text,
String id, String type, String title, String text, bool hasRetry, bool hasRetry, OverlayDialogManager dialogManager,
{bool? hasCancel}) { {bool? hasCancel}) {
msgBox(type, title, text, hasCancel: hasCancel); msgBox(type, title, text, dialogManager, hasCancel: hasCancel);
_timer?.cancel(); _timer?.cancel();
if (hasRetry) { if (hasRetry) {
_timer = Timer(Duration(seconds: _reconnects), () { _timer = Timer(Duration(seconds: _reconnects), () {
bind.sessionReconnect(id: id); bind.sessionReconnect(id: id);
clearPermissions(); clearPermissions();
showLoading(translate('Connecting...')); dialogManager.showLoading(translate('Connecting...'),
cancelToClose: true);
}); });
_reconnects *= 2; _reconnects *= 2;
} else { } else {
@ -296,7 +297,7 @@ class FfiModel with ChangeNotifier {
/// Handle the peer info event based on [evt]. /// Handle the peer info event based on [evt].
void handlePeerInfo(Map<String, dynamic> evt, String peerId) async { void handlePeerInfo(Map<String, dynamic> evt, String peerId) async {
SmartDialog.dismiss(); parent.target?.dialogManager.dismissAll();
_pi.version = evt['version']; _pi.version = evt['version'];
_pi.username = evt['username']; _pi.username = evt['username'];
_pi.hostname = evt['hostname']; _pi.hostname = evt['hostname'];
@ -332,7 +333,9 @@ 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...')); parent.target?.dialogManager.showLoading(
translate('Connected, waiting for image...'),
cancelToClose: true);
_waitForImage = true; _waitForImage = true;
_reconnects = 1; _reconnects = 1;
} }
@ -364,7 +367,7 @@ class ImageModel with ChangeNotifier {
void onRgba(Uint8List rgba, double tabBarHeight) { void onRgba(Uint8List rgba, double tabBarHeight) {
if (_waitForImage) { if (_waitForImage) {
_waitForImage = false; _waitForImage = false;
SmartDialog.dismiss(); parent.target?.dialogManager.dismissAll();
} }
final pid = parent.target?.id; final pid = parent.target?.id;
ui.decodeImageFromPixels( ui.decodeImageFromPixels(
@ -874,16 +877,20 @@ class FFI {
var alt = false; var alt = false;
var command = false; var command = false;
var version = ""; var version = "";
late final ImageModel imageModel;
late final FfiModel ffiModel; /// dialogManager use late to ensure init after main page binding [globalKey]
late final CursorModel cursorModel; late final dialogManager = OverlayDialogManager();
late final CanvasModel canvasModel;
late final ServerModel serverModel; late final ImageModel imageModel; // session
late final ChatModel chatModel; late final FfiModel ffiModel; // session
late final FileModel fileModel; late final CursorModel cursorModel; // session
late final AbModel abModel; late final CanvasModel canvasModel; // session
late final UserModel userModel; late final ServerModel serverModel; // global
late final QualityMonitorModel qualityMonitorModel; 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() { FFI() {
this.imageModel = ImageModel(WeakReference(this)); this.imageModel = ImageModel(WeakReference(this));

View File

@ -75,7 +75,7 @@ class PlatformFFI {
} }
String translate(String name, String locale) { String translate(String name, String locale) {
if (_translate == null) return ''; if (_translate == null) return name;
var a = name.toNativeUtf8(); var a = name.toNativeUtf8();
var b = locale.toNativeUtf8(); var b = locale.toNativeUtf8();
var p = _translate!(a, b); var p = _translate!(a, b);

View File

@ -10,7 +10,7 @@ import '../common.dart';
import '../mobile/pages/server_page.dart'; import '../mobile/pages/server_page.dart';
import 'model.dart'; import 'model.dart';
const loginDialogTag = "LOGIN"; const KLoginDialogTag = "LOGIN";
const kUseTemporaryPassword = "use-temporary-password"; const kUseTemporaryPassword = "use-temporary-password";
const kUsePermanentPassword = "use-permanent-password"; const kUsePermanentPassword = "use-permanent-password";
@ -206,8 +206,8 @@ class ServerModel with ChangeNotifier {
/// Toggle the screen sharing service. /// Toggle the screen sharing service.
toggleService() async { toggleService() async {
if (_isStart) { if (_isStart) {
final res = final res = await parent.target?.dialogManager
await DialogManager.show<bool>((setState, close) => CustomAlertDialog( .show<bool>((setState, close) => CustomAlertDialog(
title: Row(children: [ title: Row(children: [
Icon(Icons.warning_amber_sharp, Icon(Icons.warning_amber_sharp,
color: Colors.redAccent, size: 28), color: Colors.redAccent, size: 28),
@ -228,8 +228,8 @@ class ServerModel with ChangeNotifier {
stopService(); stopService();
} }
} else { } else {
final res = final res = await parent.target?.dialogManager
await DialogManager.show<bool>((setState, close) => CustomAlertDialog( .show<bool>((setState, close) => CustomAlertDialog(
title: Row(children: [ title: Row(children: [
Icon(Icons.warning_amber_sharp, Icon(Icons.warning_amber_sharp,
color: Colors.redAccent, size: 28), color: Colors.redAccent, size: 28),
@ -272,7 +272,7 @@ class ServerModel with ChangeNotifier {
Future<Null> stopService() async { Future<Null> stopService() async {
_isStart = false; _isStart = false;
// TODO // TODO
parent.target?.serverModel.closeAll(); closeAll();
await parent.target?.invokeMethod("stop_service"); await parent.target?.invokeMethod("stop_service");
await bind.mainStopService(); await bind.mainStopService();
notifyListeners(); notifyListeners();
@ -370,7 +370,7 @@ class ServerModel with ChangeNotifier {
} }
void showLoginDialog(Client client) { void showLoginDialog(Client client) {
DialogManager.show( parent.target?.dialogManager.show(
(setState, close) => CustomAlertDialog( (setState, close) => CustomAlertDialog(
title: Row( title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -442,7 +442,7 @@ class ServerModel with ChangeNotifier {
void onClientAuthorized(Map<String, dynamic> evt) { void onClientAuthorized(Map<String, dynamic> evt) {
try { try {
final client = Client.fromJson(jsonDecode(evt['client'])); final client = Client.fromJson(jsonDecode(evt['client']));
DialogManager.dismissByTag(getLoginDialogTag(client.id)); parent.target?.dialogManager.dismissByTag(getLoginDialogTag(client.id));
_clients[client.id] = client; _clients[client.id] = client;
scrollToBottom(); scrollToBottom();
notifyListeners(); notifyListeners();
@ -454,7 +454,7 @@ class ServerModel with ChangeNotifier {
final id = int.parse(evt['id'] as String); final id = int.parse(evt['id'] as String);
if (_clients.containsKey(id)) { if (_clients.containsKey(id)) {
_clients.remove(id); _clients.remove(id);
DialogManager.dismissByTag(getLoginDialogTag(id)); parent.target?.dialogManager.dismissByTag(getLoginDialogTag(id));
parent.target?.invokeMethod("cancel_notification", id); parent.target?.invokeMethod("cancel_notification", id);
} }
notifyListeners(); notifyListeners();
@ -510,11 +510,11 @@ class Client {
} }
String getLoginDialogTag(int id) { String getLoginDialogTag(int id) {
return loginDialogTag + id.toString(); return KLoginDialogTag + id.toString();
} }
showInputWarnAlert(FFI ffi) { showInputWarnAlert(FFI ffi) {
DialogManager.show((setState, close) => CustomAlertDialog( ffi.dialogManager.show((setState, close) => CustomAlertDialog(
title: Text(translate("How to get Android input permission?")), title: Text(translate("How to get Android input permission?")),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,7 @@ dependencies:
zxing2: ^0.1.0 zxing2: ^0.1.0
image_picker: ^0.8.5 image_picker: ^0.8.5
image: ^3.1.3 image: ^3.1.3
flutter_smart_dialog: ^4.3.1 back_button_interceptor: ^6.0.1
flutter_rust_bridge: flutter_rust_bridge:
git: git:
url: https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge url: https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge