mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge branch 'master' of https://github.com/rustdesk/rustdesk
This commit is contained in:
@@ -209,10 +209,19 @@ class ChatModel with ChangeNotifier {
|
||||
id: await bind.mainGetLastRemoteId(),
|
||||
);
|
||||
} else {
|
||||
final client = _ffi.target?.serverModel.clients[id];
|
||||
final client = _ffi.target?.serverModel.clients
|
||||
.firstWhere((client) => client.id == id);
|
||||
if (client == null) {
|
||||
return debugPrint("Failed to receive msg,user doesn't exist");
|
||||
}
|
||||
if (isDesktop) {
|
||||
window_on_top(null);
|
||||
var index = _ffi.target?.serverModel.clients
|
||||
.indexWhere((client) => client.id == id);
|
||||
if (index != null && index >= 0) {
|
||||
gFFI.serverModel.tabController.jumpTo(index);
|
||||
}
|
||||
}
|
||||
chatUser = ChatUser(id: client.peerId, firstName: client.name);
|
||||
}
|
||||
|
||||
|
||||
@@ -360,9 +360,9 @@ class FileModel extends ChangeNotifier {
|
||||
Future refresh({bool? isLocal}) async {
|
||||
if (isDesktop) {
|
||||
isLocal = isLocal ?? _isLocal;
|
||||
await isLocal
|
||||
? openDirectory(currentLocalDir.path, isLocal: isLocal)
|
||||
: openDirectory(currentRemoteDir.path, isLocal: isLocal);
|
||||
isLocal
|
||||
? await openDirectory(currentLocalDir.path, isLocal: isLocal)
|
||||
: await openDirectory(currentRemoteDir.path, isLocal: isLocal);
|
||||
} else {
|
||||
await openDirectory(currentDir.path);
|
||||
}
|
||||
@@ -393,7 +393,7 @@ class FileModel extends ChangeNotifier {
|
||||
}
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
debugPrint("Failed to openDirectory ${path} :$e");
|
||||
debugPrint("Failed to openDirectory $path: $e");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,49 +559,55 @@ class FileModel extends ChangeNotifier {
|
||||
Future<bool?> showRemoveDialog(
|
||||
String title, String content, bool showCheckbox) async {
|
||||
return await parent.target?.dialogManager.show<bool>(
|
||||
(setState, Function(bool v) close) => CustomAlertDialog(
|
||||
title: Row(
|
||||
children: [
|
||||
Icon(Icons.warning, color: Colors.red),
|
||||
SizedBox(width: 20),
|
||||
Text(title)
|
||||
],
|
||||
),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(content),
|
||||
SizedBox(height: 5),
|
||||
Text(translate("This is irreversible!"),
|
||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
showCheckbox
|
||||
? CheckboxListTile(
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
dense: true,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
title: Text(
|
||||
translate("Do this for all conflicts"),
|
||||
),
|
||||
value: removeCheckboxRemember,
|
||||
onChanged: (v) {
|
||||
if (v == null) return;
|
||||
setState(() => removeCheckboxRemember = v);
|
||||
},
|
||||
)
|
||||
: SizedBox.shrink()
|
||||
]),
|
||||
actions: [
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: () => close(false),
|
||||
child: Text(translate("Cancel"))),
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: () => close(true),
|
||||
child: Text(translate("OK"))),
|
||||
]),
|
||||
useAnimation: false);
|
||||
(setState, Function(bool v) close) {
|
||||
cancel() => close(false);
|
||||
submit() => close(true);
|
||||
return CustomAlertDialog(
|
||||
title: Row(
|
||||
children: [
|
||||
const Icon(Icons.warning, color: Colors.red),
|
||||
const SizedBox(width: 20),
|
||||
Text(title)
|
||||
],
|
||||
),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(content),
|
||||
const SizedBox(height: 5),
|
||||
Text(translate("This is irreversible!"),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
showCheckbox
|
||||
? CheckboxListTile(
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
dense: true,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
title: Text(
|
||||
translate("Do this for all conflicts"),
|
||||
),
|
||||
value: removeCheckboxRemember,
|
||||
onChanged: (v) {
|
||||
if (v == null) return;
|
||||
setState(() => removeCheckboxRemember = v);
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink()
|
||||
]),
|
||||
actions: [
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: cancel,
|
||||
child: Text(translate("Cancel"))),
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: submit,
|
||||
child: Text(translate("OK"))),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: cancel,
|
||||
);
|
||||
}, useAnimation: false);
|
||||
}
|
||||
|
||||
bool fileConfirmCheckboxRemember = false;
|
||||
@@ -610,55 +616,59 @@ class FileModel extends ChangeNotifier {
|
||||
String title, String content, bool showCheckbox) async {
|
||||
fileConfirmCheckboxRemember = false;
|
||||
return await parent.target?.dialogManager.show<bool?>(
|
||||
(setState, Function(bool? v) close) => CustomAlertDialog(
|
||||
title: Row(
|
||||
children: [
|
||||
Icon(Icons.warning, color: Colors.red),
|
||||
SizedBox(width: 20),
|
||||
Text(title)
|
||||
],
|
||||
),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
translate(
|
||||
"This file exists, skip or overwrite this file?"),
|
||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
SizedBox(height: 5),
|
||||
Text(content),
|
||||
showCheckbox
|
||||
? CheckboxListTile(
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
dense: true,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
title: Text(
|
||||
translate("Do this for all conflicts"),
|
||||
),
|
||||
value: fileConfirmCheckboxRemember,
|
||||
onChanged: (v) {
|
||||
if (v == null) return;
|
||||
setState(() => fileConfirmCheckboxRemember = v);
|
||||
},
|
||||
)
|
||||
: SizedBox.shrink()
|
||||
]),
|
||||
actions: [
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: () => close(false),
|
||||
child: Text(translate("Cancel"))),
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: () => close(null),
|
||||
child: Text(translate("Skip"))),
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: () => close(true),
|
||||
child: Text(translate("OK"))),
|
||||
]),
|
||||
useAnimation: false);
|
||||
(setState, Function(bool? v) close) {
|
||||
cancel() => close(false);
|
||||
submit() => close(true);
|
||||
return CustomAlertDialog(
|
||||
title: Row(
|
||||
children: [
|
||||
const Icon(Icons.warning, color: Colors.red),
|
||||
const SizedBox(width: 20),
|
||||
Text(title)
|
||||
],
|
||||
),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(translate("This file exists, skip or overwrite this file?"),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 5),
|
||||
Text(content),
|
||||
showCheckbox
|
||||
? CheckboxListTile(
|
||||
contentPadding: const EdgeInsets.all(0),
|
||||
dense: true,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
title: Text(
|
||||
translate("Do this for all conflicts"),
|
||||
),
|
||||
value: fileConfirmCheckboxRemember,
|
||||
onChanged: (v) {
|
||||
if (v == null) return;
|
||||
setState(() => fileConfirmCheckboxRemember = v);
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink()
|
||||
]),
|
||||
actions: [
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: cancel,
|
||||
child: Text(translate("Cancel"))),
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: () => close(null),
|
||||
child: Text(translate("Skip"))),
|
||||
TextButton(
|
||||
style: flatButtonStyle,
|
||||
onPressed: submit,
|
||||
child: Text(translate("OK"))),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: cancel,
|
||||
);
|
||||
}, useAnimation: false);
|
||||
}
|
||||
|
||||
sendRemoveFile(String path, int fileNum, bool isLocal) {
|
||||
|
||||
@@ -32,7 +32,7 @@ class FfiModel with ChangeNotifier {
|
||||
Display _display = Display();
|
||||
|
||||
var _inputBlocked = false;
|
||||
final _permissions = Map<String, bool>();
|
||||
final _permissions = <String, bool>{};
|
||||
bool? _secure;
|
||||
bool? _direct;
|
||||
bool _touchMode = false;
|
||||
@@ -71,12 +71,13 @@ class FfiModel with ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
void updatePermission(Map<String, dynamic> evt) {
|
||||
void updatePermission(Map<String, dynamic> evt, String id) {
|
||||
evt.forEach((k, v) {
|
||||
if (k == 'name' || k.isEmpty) return;
|
||||
_permissions[k] = v == 'true';
|
||||
});
|
||||
print('$_permissions');
|
||||
KeyboardEnabledState.find(id).value = _permissions['keyboard'] != false;
|
||||
debugPrint('$_permissions');
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -146,7 +147,7 @@ class FfiModel with ChangeNotifier {
|
||||
} else if (name == 'clipboard') {
|
||||
Clipboard.setData(ClipboardData(text: evt['content']));
|
||||
} else if (name == 'permission') {
|
||||
parent.target?.ffiModel.updatePermission(evt);
|
||||
parent.target?.ffiModel.updatePermission(evt, peerId);
|
||||
} else if (name == 'chat_client_mode') {
|
||||
parent.target?.chatModel
|
||||
.receive(ChatModel.clientModeID, evt['text'] ?? "");
|
||||
@@ -167,10 +168,8 @@ class FfiModel with ChangeNotifier {
|
||||
parent.target?.fileModel.loadLastJob(evt);
|
||||
} else if (name == 'update_folder_files') {
|
||||
parent.target?.fileModel.updateFolderFiles(evt);
|
||||
} else if (name == 'try_start_without_auth') {
|
||||
parent.target?.serverModel.loginRequest(evt);
|
||||
} else if (name == 'on_client_authorized') {
|
||||
parent.target?.serverModel.onClientAuthorized(evt);
|
||||
} else if (name == 'add_connection') {
|
||||
parent.target?.serverModel.addConnection(evt);
|
||||
} else if (name == 'on_client_remove') {
|
||||
parent.target?.serverModel.onClientRemove(evt);
|
||||
} else if (name == 'update_quality_status') {
|
||||
@@ -185,7 +184,7 @@ class FfiModel with ChangeNotifier {
|
||||
|
||||
/// Bind the event listener to receive events from the Rust core.
|
||||
void updateEventListener(String peerId) {
|
||||
final void Function(Map<String, dynamic>) cb = (evt) {
|
||||
cb(evt) {
|
||||
var name = evt['name'];
|
||||
if (name == 'msgbox') {
|
||||
handleMsgBox(evt, peerId);
|
||||
@@ -205,7 +204,7 @@ class FfiModel with ChangeNotifier {
|
||||
} else if (name == 'clipboard') {
|
||||
Clipboard.setData(ClipboardData(text: evt['content']));
|
||||
} else if (name == 'permission') {
|
||||
parent.target?.ffiModel.updatePermission(evt);
|
||||
parent.target?.ffiModel.updatePermission(evt, peerId);
|
||||
} else if (name == 'chat_client_mode') {
|
||||
parent.target?.chatModel
|
||||
.receive(ChatModel.clientModeID, evt['text'] ?? "");
|
||||
@@ -226,10 +225,8 @@ class FfiModel with ChangeNotifier {
|
||||
parent.target?.fileModel.loadLastJob(evt);
|
||||
} else if (name == 'update_folder_files') {
|
||||
parent.target?.fileModel.updateFolderFiles(evt);
|
||||
} else if (name == 'try_start_without_auth') {
|
||||
parent.target?.serverModel.loginRequest(evt);
|
||||
} else if (name == 'on_client_authorized') {
|
||||
parent.target?.serverModel.onClientAuthorized(evt);
|
||||
} else if (name == 'add_connection') {
|
||||
parent.target?.serverModel.addConnection(evt);
|
||||
} else if (name == 'on_client_remove') {
|
||||
parent.target?.serverModel.onClientRemove(evt);
|
||||
} else if (name == 'update_quality_status') {
|
||||
@@ -239,7 +236,8 @@ class FfiModel with ChangeNotifier {
|
||||
} else if (name == 'update_privacy_mode') {
|
||||
updatePrivacyMode(evt, peerId);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
platformFFI.setEventCallback(cb);
|
||||
}
|
||||
|
||||
@@ -321,15 +319,15 @@ class FfiModel with ChangeNotifier {
|
||||
if (isPeerAndroid) {
|
||||
_touchMode = true;
|
||||
if (parent.target?.ffiModel.permissions['keyboard'] != false) {
|
||||
Timer(Duration(milliseconds: 100), showMobileActionsOverlay);
|
||||
Timer(const Duration(milliseconds: 100), showMobileActionsOverlay);
|
||||
}
|
||||
} else {
|
||||
_touchMode =
|
||||
await bind.sessionGetOption(id: peerId, arg: "touch-mode") != '';
|
||||
}
|
||||
|
||||
if (evt['is_file_transfer'] == "true") {
|
||||
// TODO is file transfer
|
||||
if (parent.target != null &&
|
||||
parent.target!.connType == ConnType.fileTransfer) {
|
||||
parent.target?.fileModel.onReady();
|
||||
} else {
|
||||
_pi.displays = [];
|
||||
@@ -464,15 +462,20 @@ enum ScrollStyle {
|
||||
}
|
||||
|
||||
class CanvasModel with ChangeNotifier {
|
||||
// image offset of canvas
|
||||
double _x = 0;
|
||||
// image offset of canvas
|
||||
double _y = 0;
|
||||
// image scale
|
||||
double _scale = 1.0;
|
||||
// the tabbar over the image
|
||||
double tabBarHeight = 0.0;
|
||||
// TODO multi canvas model
|
||||
String id = "";
|
||||
// scroll offset x percent
|
||||
double _scrollX = 0.0;
|
||||
// scroll offset y percent
|
||||
double _scrollY = 0.0;
|
||||
double _x = 0;
|
||||
double _y = 0;
|
||||
double _scale = 1.0;
|
||||
double _tabBarHeight = 0.0;
|
||||
String id = ""; // TODO multi canvas model
|
||||
ScrollStyle _scrollStyle = ScrollStyle.scrollauto;
|
||||
|
||||
WeakReference<FFI> parent;
|
||||
@@ -492,9 +495,6 @@ class CanvasModel with ChangeNotifier {
|
||||
double get scrollX => _scrollX;
|
||||
double get scrollY => _scrollY;
|
||||
|
||||
set tabBarHeight(double h) => _tabBarHeight = h;
|
||||
double get tabBarHeight => _tabBarHeight;
|
||||
|
||||
void updateViewStyle() async {
|
||||
final style = await bind.sessionGetOption(id: id, arg: 'view-style');
|
||||
if (style == null) {
|
||||
@@ -548,12 +548,11 @@ class CanvasModel with ChangeNotifier {
|
||||
|
||||
Size get size {
|
||||
final size = MediaQueryData.fromWindow(ui.window).size;
|
||||
return Size(size.width, size.height - _tabBarHeight);
|
||||
return Size(size.width, size.height - tabBarHeight);
|
||||
}
|
||||
|
||||
void moveDesktopMouse(double x, double y) {
|
||||
// On mobile platforms, move the canvas with the cursor.
|
||||
//if (!isDesktop) {
|
||||
final dw = getDisplayWidth() * _scale;
|
||||
final dh = getDisplayHeight() * _scale;
|
||||
var dxOffset = 0;
|
||||
@@ -579,8 +578,13 @@ class CanvasModel with ChangeNotifier {
|
||||
if (dxOffset != 0 || dyOffset != 0) {
|
||||
notifyListeners();
|
||||
}
|
||||
//}
|
||||
parent.target?.cursorModel.moveLocal(x, y);
|
||||
|
||||
// If keyboard is not permitted, do not move cursor when mouse is moving.
|
||||
if (parent.target != null) {
|
||||
if (parent.target!.ffiModel.keyboard()) {
|
||||
parent.target!.cursorModel.moveLocal(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set scale(v) {
|
||||
@@ -597,11 +601,8 @@ class CanvasModel with ChangeNotifier {
|
||||
if (isWebDesktop) {
|
||||
updateViewStyle();
|
||||
} else {
|
||||
final size = MediaQueryData.fromWindow(ui.window).size;
|
||||
final canvasWidth = size.width;
|
||||
final canvasHeight = size.height - _tabBarHeight;
|
||||
_x = (canvasWidth - getDisplayWidth() * _scale) / 2;
|
||||
_y = (canvasHeight - getDisplayHeight() * _scale) / 2;
|
||||
_x = (size.width - getDisplayWidth() * _scale) / 2;
|
||||
_y = (size.height - getDisplayHeight() * _scale) / 2;
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
@@ -613,7 +614,7 @@ class CanvasModel with ChangeNotifier {
|
||||
|
||||
void updateScale(double v) {
|
||||
if (parent.target?.imageModel.image == null) return;
|
||||
final offset = parent.target?.cursorModel.offset ?? Offset(0, 0);
|
||||
final offset = parent.target?.cursorModel.offset ?? const Offset(0, 0);
|
||||
var r = parent.target?.cursorModel.getVisibleRect() ?? Rect.zero;
|
||||
final px0 = (offset.dx - r.left) * _scale;
|
||||
final py0 = (offset.dy - r.top) * _scale;
|
||||
@@ -640,7 +641,7 @@ class CanvasModel with ChangeNotifier {
|
||||
|
||||
class CursorModel with ChangeNotifier {
|
||||
ui.Image? _image;
|
||||
final _images = Map<int, Tuple3<ui.Image, double, double>>();
|
||||
final _images = <int, Tuple3<ui.Image, double, double>>{};
|
||||
double _x = -10000;
|
||||
double _y = -10000;
|
||||
double _hotx = 0;
|
||||
@@ -807,7 +808,7 @@ class CursorModel with ChangeNotifier {
|
||||
// my throw exception, because the listener maybe already dispose
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
print('notify cursor: $e');
|
||||
debugPrint('notify cursor: $e');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -915,6 +916,8 @@ extension ToString on MouseButtons {
|
||||
}
|
||||
}
|
||||
|
||||
enum ConnType { defaultConn, fileTransfer, portForward, rdp }
|
||||
|
||||
/// FFI class for communicating with the Rust core.
|
||||
class FFI {
|
||||
var id = "";
|
||||
@@ -923,6 +926,7 @@ class FFI {
|
||||
var alt = false;
|
||||
var command = false;
|
||||
var version = "";
|
||||
var connType = ConnType.defaultConn;
|
||||
|
||||
/// dialogManager use late to ensure init after main page binding [globalKey]
|
||||
late final dialogManager = OverlayDialogManager();
|
||||
@@ -1076,9 +1080,11 @@ class FFI {
|
||||
double tabBarHeight = 0.0}) {
|
||||
assert(!(isFileTransfer && isPortForward), "more than one connect type");
|
||||
if (isFileTransfer) {
|
||||
id = 'ft_${id}';
|
||||
connType = ConnType.fileTransfer;
|
||||
id = 'ft_$id';
|
||||
} else if (isPortForward) {
|
||||
id = 'pf_${id}';
|
||||
connType = ConnType.portForward;
|
||||
id = 'pf_$id';
|
||||
} else {
|
||||
chatModel.resetClientMode();
|
||||
canvasModel.id = id;
|
||||
@@ -1107,7 +1113,7 @@ class FFI {
|
||||
// every instance will bind a stream
|
||||
this.id = id;
|
||||
if (isFileTransfer) {
|
||||
this.fileModel.initFileFetcher();
|
||||
fileModel.initFileFetcher();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import 'package:wakelock/wakelock.dart';
|
||||
|
||||
import '../common.dart';
|
||||
import '../common/formatter/id_formatter.dart';
|
||||
import '../desktop/pages/server_page.dart' as Desktop;
|
||||
import '../desktop/widgets/tabbar_widget.dart';
|
||||
import '../mobile/pages/server_page.dart';
|
||||
@@ -29,10 +30,10 @@ class ServerModel with ChangeNotifier {
|
||||
String _temporaryPasswordLength = "";
|
||||
|
||||
late String _emptyIdShow;
|
||||
late final TextEditingController _serverId;
|
||||
late final IDTextEditingController _serverId;
|
||||
final _serverPasswd = TextEditingController(text: "");
|
||||
|
||||
final tabController = DesktopTabController();
|
||||
final tabController = DesktopTabController(tabType: DesktopTabType.cm);
|
||||
|
||||
List<Client> _clients = [];
|
||||
|
||||
@@ -88,7 +89,7 @@ class ServerModel with ChangeNotifier {
|
||||
|
||||
ServerModel(this.parent) {
|
||||
_emptyIdShow = translate("Generating ...");
|
||||
_serverId = TextEditingController(text: this._emptyIdShow);
|
||||
_serverId = IDTextEditingController(text: _emptyIdShow);
|
||||
|
||||
Timer.periodic(Duration(seconds: 1), (timer) async {
|
||||
var status = await bind.mainGetOnlineStatue();
|
||||
@@ -99,7 +100,7 @@ class ServerModel with ChangeNotifier {
|
||||
_connectStatus = status;
|
||||
notifyListeners();
|
||||
}
|
||||
final res = await bind.mainCheckClientsLength(length: _clients.length);
|
||||
final res = await bind.cmCheckClientsLength(length: _clients.length);
|
||||
if (res != null) {
|
||||
debugPrint("clients not match!");
|
||||
updateClientState(res);
|
||||
@@ -208,46 +209,48 @@ class ServerModel with ChangeNotifier {
|
||||
/// Toggle the screen sharing service.
|
||||
toggleService() async {
|
||||
if (_isStart) {
|
||||
final res = await parent.target?.dialogManager
|
||||
.show<bool>((setState, close) => CustomAlertDialog(
|
||||
title: Row(children: [
|
||||
Icon(Icons.warning_amber_sharp,
|
||||
color: Colors.redAccent, size: 28),
|
||||
SizedBox(width: 10),
|
||||
Text(translate("Warning")),
|
||||
]),
|
||||
content: Text(translate("android_stop_service_tip")),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => close(),
|
||||
child: Text(translate("Cancel"))),
|
||||
ElevatedButton(
|
||||
onPressed: () => close(true),
|
||||
child: Text(translate("OK"))),
|
||||
],
|
||||
));
|
||||
final res =
|
||||
await parent.target?.dialogManager.show<bool>((setState, close) {
|
||||
submit() => close(true);
|
||||
return CustomAlertDialog(
|
||||
title: Row(children: [
|
||||
const Icon(Icons.warning_amber_sharp,
|
||||
color: Colors.redAccent, size: 28),
|
||||
const SizedBox(width: 10),
|
||||
Text(translate("Warning")),
|
||||
]),
|
||||
content: Text(translate("android_stop_service_tip")),
|
||||
actions: [
|
||||
TextButton(onPressed: close, child: Text(translate("Cancel"))),
|
||||
ElevatedButton(onPressed: submit, child: Text(translate("OK"))),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
if (res == true) {
|
||||
stopService();
|
||||
}
|
||||
} else {
|
||||
final res = await parent.target?.dialogManager
|
||||
.show<bool>((setState, close) => CustomAlertDialog(
|
||||
title: Row(children: [
|
||||
Icon(Icons.warning_amber_sharp,
|
||||
color: Colors.redAccent, size: 28),
|
||||
SizedBox(width: 10),
|
||||
Text(translate("Warning")),
|
||||
]),
|
||||
content: Text(translate("android_service_will_start_tip")),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => close(),
|
||||
child: Text(translate("Cancel"))),
|
||||
ElevatedButton(
|
||||
onPressed: () => close(true),
|
||||
child: Text(translate("OK"))),
|
||||
],
|
||||
));
|
||||
final res =
|
||||
await parent.target?.dialogManager.show<bool>((setState, close) {
|
||||
submit() => close(true);
|
||||
return CustomAlertDialog(
|
||||
title: Row(children: [
|
||||
const Icon(Icons.warning_amber_sharp,
|
||||
color: Colors.redAccent, size: 28),
|
||||
const SizedBox(width: 10),
|
||||
Text(translate("Warning")),
|
||||
]),
|
||||
content: Text(translate("android_service_will_start_tip")),
|
||||
actions: [
|
||||
TextButton(onPressed: close, child: Text(translate("Cancel"))),
|
||||
ElevatedButton(onPressed: submit, child: Text(translate("OK"))),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
if (res == true) {
|
||||
startService();
|
||||
}
|
||||
@@ -300,7 +303,7 @@ class ServerModel with ChangeNotifier {
|
||||
}
|
||||
|
||||
_fetchID() async {
|
||||
final old = _serverId.text;
|
||||
final old = _serverId.id;
|
||||
var count = 0;
|
||||
const maxCount = 10;
|
||||
while (count < maxCount) {
|
||||
@@ -309,12 +312,12 @@ class ServerModel with ChangeNotifier {
|
||||
if (id.isEmpty) {
|
||||
continue;
|
||||
} else {
|
||||
_serverId.text = id;
|
||||
_serverId.id = id;
|
||||
}
|
||||
|
||||
debugPrint("fetch id again at $count:id:${_serverId.text}");
|
||||
debugPrint("fetch id again at $count:id:${_serverId.id}");
|
||||
count++;
|
||||
if (_serverId.text != old) {
|
||||
if (_serverId.id != old) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -344,23 +347,21 @@ class ServerModel with ChangeNotifier {
|
||||
|
||||
// force
|
||||
updateClientState([String? json]) async {
|
||||
var res = await bind.mainGetClientsState();
|
||||
var res = await bind.cmGetClientsState();
|
||||
try {
|
||||
final List clientsJson = jsonDecode(res);
|
||||
if (isDesktop && clientsJson.isEmpty && _clients.isNotEmpty) {
|
||||
// exit cm when >1 peers to no peers
|
||||
exit(0);
|
||||
}
|
||||
_clients.clear();
|
||||
tabController.state.value.tabs.clear();
|
||||
for (var clientJson in clientsJson) {
|
||||
final client = Client.fromJson(clientJson);
|
||||
_clients.add(client);
|
||||
tabController.add(TabInfo(
|
||||
key: client.id.toString(),
|
||||
label: client.name,
|
||||
closable: false,
|
||||
page: Desktop.buildConnectionCard(client)));
|
||||
tabController.add(
|
||||
TabInfo(
|
||||
key: client.id.toString(),
|
||||
label: client.name,
|
||||
closable: false,
|
||||
page: Desktop.buildConnectionCard(client)),
|
||||
authorized: client.authorized);
|
||||
}
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
@@ -368,70 +369,89 @@ class ServerModel with ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
void loginRequest(Map<String, dynamic> evt) {
|
||||
void addConnection(Map<String, dynamic> evt) {
|
||||
try {
|
||||
final client = Client.fromJson(jsonDecode(evt["client"]));
|
||||
if (_clients.any((c) => c.id == client.id)) {
|
||||
return;
|
||||
if (client.authorized) {
|
||||
parent.target?.dialogManager.dismissByTag(getLoginDialogTag(client.id));
|
||||
final index = _clients.indexWhere((c) => c.id == client.id);
|
||||
if (index < 0) {
|
||||
_clients.add(client);
|
||||
} else {
|
||||
_clients[index].authorized = true;
|
||||
}
|
||||
tabController.add(
|
||||
TabInfo(
|
||||
key: client.id.toString(),
|
||||
label: client.name,
|
||||
closable: false,
|
||||
page: Desktop.buildConnectionCard(client)),
|
||||
authorized: true);
|
||||
scrollToBottom();
|
||||
notifyListeners();
|
||||
} else {
|
||||
if (_clients.any((c) => c.id == client.id)) {
|
||||
return;
|
||||
}
|
||||
_clients.add(client);
|
||||
tabController.add(TabInfo(
|
||||
key: client.id.toString(),
|
||||
label: client.name,
|
||||
closable: false,
|
||||
page: Desktop.buildConnectionCard(client)));
|
||||
scrollToBottom();
|
||||
notifyListeners();
|
||||
if (isAndroid) showLoginDialog(client);
|
||||
}
|
||||
_clients.add(client);
|
||||
tabController.add(TabInfo(
|
||||
key: client.id.toString(),
|
||||
label: client.name,
|
||||
closable: false,
|
||||
page: Desktop.buildConnectionCard(client)));
|
||||
scrollToBottom();
|
||||
notifyListeners();
|
||||
if (isAndroid) showLoginDialog(client);
|
||||
} catch (e) {
|
||||
debugPrint("Failed to call loginRequest,error:$e");
|
||||
}
|
||||
}
|
||||
|
||||
void showLoginDialog(Client client) {
|
||||
parent.target?.dialogManager.show(
|
||||
(setState, close) => CustomAlertDialog(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(translate(client.isFileTransfer
|
||||
? "File Connection"
|
||||
: "Screen Connection")),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
close();
|
||||
},
|
||||
icon: Icon(Icons.close))
|
||||
]),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(translate("Do you accept?")),
|
||||
clientInfo(client),
|
||||
Text(
|
||||
translate("android_new_connection_tip"),
|
||||
style: TextStyle(color: Colors.black54),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(translate("Dismiss")),
|
||||
onPressed: () {
|
||||
sendLoginResponse(client, false);
|
||||
close();
|
||||
}),
|
||||
ElevatedButton(
|
||||
child: Text(translate("Accept")),
|
||||
onPressed: () {
|
||||
sendLoginResponse(client, true);
|
||||
close();
|
||||
}),
|
||||
],
|
||||
parent.target?.dialogManager.show((setState, close) {
|
||||
cancel() {
|
||||
sendLoginResponse(client, false);
|
||||
close();
|
||||
}
|
||||
|
||||
submit() {
|
||||
sendLoginResponse(client, true);
|
||||
close();
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title:
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Text(translate(
|
||||
client.isFileTransfer ? "File Connection" : "Screen Connection")),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
close();
|
||||
},
|
||||
icon: const Icon(Icons.close))
|
||||
]),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(translate("Do you accept?")),
|
||||
clientInfo(client),
|
||||
Text(
|
||||
translate("android_new_connection_tip"),
|
||||
style: const TextStyle(color: Colors.black54),
|
||||
),
|
||||
tag: getLoginDialogTag(client.id));
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: cancel, child: Text(translate("Dismiss"))),
|
||||
ElevatedButton(onPressed: submit, child: Text(translate("Accept"))),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: cancel,
|
||||
);
|
||||
}, tag: getLoginDialogTag(client.id));
|
||||
}
|
||||
|
||||
scrollToBottom() {
|
||||
@@ -471,14 +491,18 @@ class ServerModel with ChangeNotifier {
|
||||
} else {
|
||||
_clients[index].authorized = true;
|
||||
}
|
||||
tabController.add(TabInfo(
|
||||
key: client.id.toString(),
|
||||
label: client.name,
|
||||
closable: false,
|
||||
page: Desktop.buildConnectionCard(client)));
|
||||
tabController.add(
|
||||
TabInfo(
|
||||
key: client.id.toString(),
|
||||
label: client.name,
|
||||
closable: false,
|
||||
page: Desktop.buildConnectionCard(client)),
|
||||
authorized: true);
|
||||
scrollToBottom();
|
||||
notifyListeners();
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
debugPrint("onClientAuthorized:$e");
|
||||
}
|
||||
}
|
||||
|
||||
void onClientRemove(Map<String, dynamic> evt) {
|
||||
@@ -486,8 +510,10 @@ class ServerModel with ChangeNotifier {
|
||||
final id = int.parse(evt['id'] as String);
|
||||
if (_clients.any((c) => c.id == id)) {
|
||||
final index = _clients.indexWhere((client) => client.id == id);
|
||||
_clients.removeAt(index);
|
||||
tabController.remove(index);
|
||||
if (index >= 0) {
|
||||
_clients.removeAt(index);
|
||||
tabController.remove(index);
|
||||
}
|
||||
parent.target?.dialogManager.dismissByTag(getLoginDialogTag(id));
|
||||
parent.target?.invokeMethod("cancel_notification", id);
|
||||
}
|
||||
@@ -558,24 +584,29 @@ String getLoginDialogTag(int id) {
|
||||
}
|
||||
|
||||
showInputWarnAlert(FFI ffi) {
|
||||
ffi.dialogManager.show((setState, close) => CustomAlertDialog(
|
||||
title: Text(translate("How to get Android input permission?")),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(translate("android_input_permission_tip1")),
|
||||
SizedBox(height: 10),
|
||||
Text(translate("android_input_permission_tip2")),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(child: Text(translate("Cancel")), onPressed: close),
|
||||
ElevatedButton(
|
||||
child: Text(translate("Open System Setting")),
|
||||
onPressed: () {
|
||||
ffi.serverModel.initInput();
|
||||
close();
|
||||
}),
|
||||
ffi.dialogManager.show((setState, close) {
|
||||
submit() {
|
||||
ffi.serverModel.initInput();
|
||||
close();
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("How to get Android input permission?")),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(translate("android_input_permission_tip1")),
|
||||
const SizedBox(height: 10),
|
||||
Text(translate("android_input_permission_tip2")),
|
||||
],
|
||||
));
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: close, child: Text(translate("Cancel"))),
|
||||
ElevatedButton(
|
||||
onPressed: submit, child: Text(translate("Open System Setting"))),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user