use uuid as session id

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages
2023-06-06 07:39:44 +08:00
parent 71838ad821
commit 2ececed0c1
36 changed files with 706 additions and 546 deletions

View File

@@ -23,6 +23,7 @@ import 'package:texture_rgba_renderer/texture_rgba_renderer.dart';
import 'package:uni_links/uni_links.dart';
import 'package:uni_links_desktop/uni_links_desktop.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:uuid/uuid.dart';
import 'package:win32/win32.dart' as win32;
import 'package:window_manager/window_manager.dart';
import 'package:window_size/window_size.dart' as window_size;
@@ -68,6 +69,7 @@ typedef F = String Function(String);
typedef FMethod = String Function(String, dynamic);
typedef StreamEventHandler = Future<void> Function(Map<String, dynamic>);
typedef SessionID = UuidValue;
final iconHardDrive = MemoryImage(Uint8List.fromList(base64Decode(
'iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAmVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjHWqVAAAAMnRSTlMAv0BmzLJNXlhiUu2fxXDgu7WuSUUe29LJvpqUjX53VTstD7ilNujCqTEk5IYH+vEoFjKvAagAAAPpSURBVHja7d0JbhpBEIXhB3jYzb5vBgzYgO04df/DJXGUKMwU9ECmZ6pQfSfw028LCXW3YYwxxhhjjDHGGGOM0eZ9VV1MckdKWLM1bRQ/35GW/WxHHu1me6ShuyHvNl34VhlTKsYVeDWj1EzgUZ1S1DrAk/UDparZgxd9Sl0BHnxSBhpI3jfKQG2FpLUpE69I2ILikv1nsvygjBwPSNKYMlNHggqUoSKS80AZCnwHqQ1zCRvW+CRegwRFeFAMKKrtM8gTPJlzSfwFgT9dJom3IDN4VGaSeAryAK8m0SSeghTg1ZYiql6CjBDhO8mzlyAVhKhIwgXxrh5NojGIhyRckEdwpCdhgpSQgiWTRGMQNonGIGySp0SDvMDBX5KWxiB8Eo1BgE00SYJBykhNnkmSWJAcLpGaJNMgfJKyxiDAK4WNEwryhMtkJsk8CJtEYxA+icYgQIfCcgkEqcJNXhIRQdgkGoPwSTQG+e8khdu/7JOVREwQIKCwF41B2CQljUH4JLcH6SI+OUlEBQHa0SQag/BJNAbhkjxqDMIn0RgEeI4muSlID9eSkERgEKAVTaIxCJ9EYxA2ydVB8hCASVLRGAQYR5NoDMIn0RgEyFHYSGMQPonGII4kziCNvBgNJonEk4u3GAk8Sprk6eYaqbMDY0oKvUm5jfC/viGiSypV7+M3i2iDsAGpNEDYjlTa3W8RdR/r544g50ilnA0RxoZIE2NIXqQbhkAkGyKNDZHGhkhjQ6SxIdLYEGlsiDQ2JGTVeD0264U9zipPh7XOooffpA6pfNCXjxl4/c3pUzlChwzor53zwYYVfpI5pOV6LWFF/2jiJ5FDSs5jdY/0rwUAkUMeXWdBqnSqD0DikBqdqCHsjTvELm9In0IOri/0pwAEDtlSyNaRjAIAAoesKWTtuusxByBwCJp0oomwBXcYUuCQgE50ENajE4OvZAKHLB1/68Br5NqiyCGYOY8YRd77kTkEb64n7lZN+mOIX4QOwb5FX0ZVx3uOxwW+SB0CbBubemWP8/rlaaeRX+M3uUOuZENsiA25zIbYkPsZElBIHwL13U/PTjJ/cyOOEoVM3I+hziDQlELm7pPxw3eI8/7gPh1fpLA6xGnEeDDgO0UcIAzzM35HxLPIq5SXe9BLzOsj9eUaQqyXzxS1QFSfWM2cCANiHcAISJ0AnCKpUwTuIkkA3EeSInAXSQKcs1V18e24wlllUmQp9v9zXKeHi+akRAMOPVKhAqdPBZeUmnnEsO6QcJ0+4qmOSbBxFfGVRiTUqITrdKcCbyYO3/K4wX4+aQ+FfNjXhu3JfAVjjDHGGGOMMcYYY4xIPwCgfqT6TbhCLAAAAABJRU5ErkJggg==')));
@@ -890,8 +892,8 @@ class CustomAlertDialog extends StatelessWidget {
}
}
void msgBox(String id, String type, String title, String text, String link,
OverlayDialogManager dialogManager,
void msgBox(SessionID sessionId, String type, String title, String text,
String link, OverlayDialogManager dialogManager,
{bool? hasCancel, ReconnectHandle? reconnect}) {
dialogManager.dismissAll();
List<Widget> buttons = [];
@@ -936,7 +938,7 @@ void msgBox(String id, String type, String title, String text, String link,
buttons.insert(
0,
dialogButton('Reconnect', isOutline: true, onPressed: () {
reconnect(dialogManager, id, false);
reconnect(dialogManager, sessionId, false);
}));
}
if (link.isNotEmpty) {
@@ -950,7 +952,7 @@ void msgBox(String id, String type, String title, String text, String link,
onSubmit: hasOk ? submit : null,
onCancel: hasCancel == true ? cancel : null,
),
tag: '$id-$type-$title-$text-$link',
tag: '$sessionId-$type-$title-$text-$link',
);
}

View File

@@ -10,9 +10,9 @@ import '../../common.dart';
import '../../models/model.dart';
import '../../models/platform_model.dart';
void clientClose(String id, OverlayDialogManager dialogManager) {
msgBox(id, 'info', 'Close', 'Are you sure to close the connection?', '',
dialogManager);
void clientClose(SessionID sessionId, OverlayDialogManager dialogManager) {
msgBox(sessionId, 'info', 'Close', 'Are you sure to close the connection?',
'', dialogManager);
}
abstract class ValidationRule {
@@ -423,8 +423,8 @@ class _PasswordWidgetState extends State<PasswordWidget> {
}
}
void wrongPasswordDialog(
String id, OverlayDialogManager dialogManager, type, title, text) {
void wrongPasswordDialog(SessionID sessionId,
OverlayDialogManager dialogManager, type, title, text) {
dialogManager.dismissAll();
dialogManager.show((setState, close, context) {
cancel() {
@@ -433,7 +433,7 @@ void wrongPasswordDialog(
}
submit() {
enterPasswordDialog(id, dialogManager);
enterPasswordDialog(sessionId, dialogManager);
}
return CustomAlertDialog(
@@ -455,17 +455,19 @@ void wrongPasswordDialog(
});
}
void enterPasswordDialog(String id, OverlayDialogManager dialogManager) async {
void enterPasswordDialog(
SessionID sessionId, OverlayDialogManager dialogManager) async {
await _connectDialog(
id,
sessionId,
dialogManager,
passwordController: TextEditingController(),
);
}
void enterUserLoginDialog(String id, OverlayDialogManager dialogManager) async {
void enterUserLoginDialog(
SessionID sessionId, OverlayDialogManager dialogManager) async {
await _connectDialog(
id,
sessionId,
dialogManager,
osUsernameController: TextEditingController(),
osPasswordController: TextEditingController(),
@@ -473,9 +475,9 @@ void enterUserLoginDialog(String id, OverlayDialogManager dialogManager) async {
}
void enterUserLoginAndPasswordDialog(
String id, OverlayDialogManager dialogManager) async {
SessionID sessionId, OverlayDialogManager dialogManager) async {
await _connectDialog(
id,
sessionId,
dialogManager,
osUsernameController: TextEditingController(),
osPasswordController: TextEditingController(),
@@ -484,7 +486,7 @@ void enterUserLoginAndPasswordDialog(
}
_connectDialog(
String id,
SessionID sessionId,
OverlayDialogManager dialogManager, {
TextEditingController? osUsernameController,
TextEditingController? osPasswordController,
@@ -492,11 +494,13 @@ _connectDialog(
}) async {
var rememberPassword = false;
if (passwordController != null) {
rememberPassword = await bind.sessionGetRemember(id: id) ?? false;
rememberPassword =
await bind.sessionGetRemember(sessionId: sessionId) ?? false;
}
var rememberAccount = false;
if (osUsernameController != null) {
rememberAccount = await bind.sessionGetRemember(id: id) ?? false;
rememberAccount =
await bind.sessionGetRemember(sessionId: sessionId) ?? false;
}
dialogManager.dismissAll();
dialogManager.show((setState, close, context) {
@@ -511,13 +515,15 @@ _connectDialog(
final password = passwordController?.text.trim() ?? '';
if (passwordController != null && password.isEmpty) return;
if (rememberAccount) {
bind.sessionPeerOption(id: id, name: 'os-username', value: osUsername);
bind.sessionPeerOption(id: id, name: 'os-password', value: osPassword);
bind.sessionPeerOption(
sessionId: sessionId, name: 'os-username', value: osUsername);
bind.sessionPeerOption(
sessionId: sessionId, name: 'os-password', value: osPassword);
}
gFFI.login(
osUsername,
osPassword,
id,
sessionId,
password,
rememberPassword,
);
@@ -650,10 +656,10 @@ _connectDialog(
}
void showWaitUacDialog(
String id, OverlayDialogManager dialogManager, String type) {
SessionID sessionId, OverlayDialogManager dialogManager, String type) {
dialogManager.dismissAll();
dialogManager.show(
tag: '$id-wait-uac',
tag: '$sessionId-wait-uac',
(setState, close, context) => CustomAlertDialog(
title: null,
content: msgboxContent(type, 'Wait', 'wait_accept_uac_tip'),
@@ -661,7 +667,8 @@ void showWaitUacDialog(
}
// Another username && password dialog?
void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) {
void showRequestElevationDialog(
SessionID sessionId, OverlayDialogManager dialogManager) {
RxString groupValue = ''.obs;
RxString errUser = ''.obs;
RxString errPwd = ''.obs;
@@ -785,7 +792,8 @@ void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) {
);
dialogManager.dismissAll();
dialogManager.show(tag: '$id-request-elevation', (setState, close, context) {
dialogManager.show(tag: '$sessionId-request-elevation',
(setState, close, context) {
void submit() {
if (groupValue.value == 'logon') {
if (userController.text.isEmpty) {
@@ -797,11 +805,11 @@ void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) {
return;
}
bind.sessionElevateWithLogon(
id: id,
sessionId: sessionId,
username: userController.text,
password: pwdController.text);
} else {
bind.sessionElevateDirect(id: id);
bind.sessionElevateDirect(sessionId: sessionId);
}
}
@@ -828,20 +836,20 @@ void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) {
}
void showOnBlockDialog(
String id,
SessionID sessionId,
String type,
String title,
String text,
OverlayDialogManager dialogManager,
) {
if (dialogManager.existing('$id-wait-uac') ||
dialogManager.existing('$id-request-elevation')) {
if (dialogManager.existing('$sessionId-wait-uac') ||
dialogManager.existing('$sessionId-request-elevation')) {
return;
}
dialogManager.show(tag: '$id-$type', (setState, close, context) {
dialogManager.show(tag: '$sessionId-$type', (setState, close, context) {
void submit() {
close();
showRequestElevationDialog(id, dialogManager);
showRequestElevationDialog(sessionId, dialogManager);
}
return CustomAlertDialog(
@@ -858,12 +866,12 @@ void showOnBlockDialog(
});
}
void showElevationError(String id, String type, String title, String text,
OverlayDialogManager dialogManager) {
dialogManager.show(tag: '$id-$type', (setState, close, context) {
void showElevationError(SessionID sessionId, String type, String title,
String text, OverlayDialogManager dialogManager) {
dialogManager.show(tag: '$sessionId-$type', (setState, close, context) {
void submit() {
close();
showRequestElevationDialog(id, dialogManager);
showRequestElevationDialog(sessionId, dialogManager);
}
return CustomAlertDialog(
@@ -881,8 +889,8 @@ void showElevationError(String id, String type, String title, String text,
});
}
void showWaitAcceptDialog(String id, String type, String title, String text,
OverlayDialogManager dialogManager) {
void showWaitAcceptDialog(SessionID sessionId, String type, String title,
String text, OverlayDialogManager dialogManager) {
dialogManager.dismissAll();
dialogManager.show((setState, close, context) {
onCancel() {
@@ -900,8 +908,8 @@ void showWaitAcceptDialog(String id, String type, String title, String text,
});
}
void showRestartRemoteDevice(
PeerInfo pi, String id, OverlayDialogManager dialogManager) async {
void showRestartRemoteDevice(PeerInfo pi, String id, SessionID sessionId,
OverlayDialogManager dialogManager) async {
final res = await dialogManager
.show<bool>((setState, close, context) => CustomAlertDialog(
title: Row(children: [
@@ -928,26 +936,33 @@ void showRestartRemoteDevice(
onCancel: close,
onSubmit: () => close(true),
));
if (res == true) bind.sessionRestartRemoteDevice(id: id);
if (res == true) bind.sessionRestartRemoteDevice(sessionId: sessionId);
}
showSetOSPassword(
String id,
SessionID sessionId,
bool login,
OverlayDialogManager dialogManager,
) async {
final controller = TextEditingController();
var password = await bind.sessionGetOption(id: id, arg: 'os-password') ?? '';
var autoLogin = await bind.sessionGetOption(id: id, arg: 'auto-login') != '';
var password =
await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ??
'';
var autoLogin =
await bind.sessionGetOption(sessionId: sessionId, arg: 'auto-login') !=
'';
controller.text = password;
dialogManager.show((setState, close, context) {
submit() {
var text = controller.text.trim();
bind.sessionPeerOption(id: id, name: 'os-password', value: text);
bind.sessionPeerOption(
id: id, name: 'auto-login', value: autoLogin ? 'Y' : '');
sessionId: sessionId, name: 'os-password', value: text);
bind.sessionPeerOption(
sessionId: sessionId,
name: 'auto-login',
value: autoLogin ? 'Y' : '');
if (text != '' && login) {
bind.sessionInputOsPassword(id: id, value: text);
bind.sessionInputOsPassword(sessionId: sessionId, value: text);
}
close();
}
@@ -999,21 +1014,27 @@ showSetOSPassword(
}
showSetOSAccount(
String id,
SessionID sessionId,
OverlayDialogManager dialogManager,
) async {
final usernameController = TextEditingController();
final passwdController = TextEditingController();
var username = await bind.sessionGetOption(id: id, arg: 'os-username') ?? '';
var password = await bind.sessionGetOption(id: id, arg: 'os-password') ?? '';
var username =
await bind.sessionGetOption(sessionId: sessionId, arg: 'os-username') ??
'';
var password =
await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ??
'';
usernameController.text = username;
passwdController.text = password;
dialogManager.show((setState, close, context) {
submit() {
final username = usernameController.text.trim();
final password = usernameController.text.trim();
bind.sessionPeerOption(id: id, name: 'os-username', value: username);
bind.sessionPeerOption(id: id, name: 'os-password', value: password);
bind.sessionPeerOption(
sessionId: sessionId, name: 'os-username', value: username);
bind.sessionPeerOption(
sessionId: sessionId, name: 'os-password', value: password);
close();
}
@@ -1077,13 +1098,13 @@ showSetOSAccount(
});
}
showAuditDialog(String id, dialogManager) async {
showAuditDialog(SessionID sessionId, dialogManager) async {
final controller = TextEditingController();
dialogManager.show((setState, close) {
submit() {
var text = controller.text.trim();
if (text != '') {
bind.sessionSendNote(id: id, note: text);
bind.sessionSendNote(sessionId: sessionId, note: text);
}
close();
}
@@ -1139,10 +1160,10 @@ showAuditDialog(String id, dialogManager) async {
}
void showConfirmSwitchSidesDialog(
String id, OverlayDialogManager dialogManager) async {
SessionID sessionId, String id, OverlayDialogManager dialogManager) async {
dialogManager.show((setState, close, context) {
submit() async {
await bind.sessionSwitchSides(id: id);
await bind.sessionSwitchSides(sessionId: sessionId);
closeConnection(id: id);
}
@@ -1159,7 +1180,7 @@ void showConfirmSwitchSidesDialog(
});
}
customImageQualityDialog(String id, FFI ffi) async {
customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async {
double qualityInitValue = 50;
double fpsInitValue = 30;
bool qualitySet = false;
@@ -1167,20 +1188,22 @@ customImageQualityDialog(String id, FFI ffi) async {
setCustomValues({double? quality, double? fps}) async {
if (quality != null) {
qualitySet = true;
await bind.sessionSetCustomImageQuality(id: id, value: quality.toInt());
await bind.sessionSetCustomImageQuality(
sessionId: sessionId, value: quality.toInt());
}
if (fps != null) {
fpsSet = true;
await bind.sessionSetCustomFps(id: id, fps: fps.toInt());
await bind.sessionSetCustomFps(sessionId: sessionId, fps: fps.toInt());
}
if (!qualitySet) {
qualitySet = true;
await bind.sessionSetCustomImageQuality(
id: id, value: qualityInitValue.toInt());
sessionId: sessionId, value: qualityInitValue.toInt());
}
if (!fpsSet) {
fpsSet = true;
await bind.sessionSetCustomFps(id: id, fps: fpsInitValue.toInt());
await bind.sessionSetCustomFps(
sessionId: sessionId, fps: fpsInitValue.toInt());
}
}
@@ -1190,7 +1213,7 @@ customImageQualityDialog(String id, FFI ffi) async {
});
// quality
final quality = await bind.sessionGetCustomImageQuality(id: id);
final quality = await bind.sessionGetCustomImageQuality(sessionId: sessionId);
qualityInitValue =
quality != null && quality.isNotEmpty ? quality[0].toDouble() : 50.0;
const qualityMinValue = 10.0;
@@ -1238,7 +1261,8 @@ customImageQualityDialog(String id, FFI ffi) async {
],
));
// fps
final fpsOption = await bind.sessionGetOption(id: id, arg: 'custom-fps');
final fpsOption =
await bind.sessionGetOption(sessionId: sessionId, arg: 'custom-fps');
fpsInitValue = fpsOption == null ? 30 : double.tryParse(fpsOption) ?? 30;
if (fpsInitValue < 5 || fpsInitValue > 120) {
fpsInitValue = 30;

View File

@@ -735,7 +735,6 @@ abstract class BasePeerCard extends StatelessWidget {
}
await bind.mainRemovePeer(id: id);
}
removePreference(id);
await reloadFunc();
close();
}

View File

@@ -48,6 +48,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
final ffiModel = ffi.ffiModel;
final pi = ffiModel.pi;
final perms = ffiModel.permissions;
final sessionId = ffi.sessionId;
List<TTextMenu> v = [];
// elevation
@@ -55,7 +56,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
v.add(
TTextMenu(
child: Text(translate('Request Elevation')),
onPressed: () => showRequestElevationDialog(id, ffi.dialogManager)),
onPressed: () =>
showRequestElevationDialog(sessionId, ffi.dialogManager)),
);
}
// osAccount / osPassword
@@ -70,8 +72,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
]),
trailingIcon: Transform.scale(scale: 0.8, child: Icon(Icons.edit)),
onPressed: () => pi.is_headless
? showSetOSAccount(id, ffi.dialogManager)
: showSetOSPassword(id, false, ffi.dialogManager)),
? showSetOSAccount(sessionId, ffi.dialogManager)
: showSetOSPassword(sessionId, false, ffi.dialogManager)),
);
// paste
if (isMobile && perms['keyboard'] != false && perms['clipboard'] != false) {
@@ -80,7 +82,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
onPressed: () async {
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null && data.text != null) {
bind.sessionInputString(id: id, value: data.text ?? "");
bind.sessionInputString(
sessionId: sessionId, value: data.text ?? "");
}
}));
}
@@ -107,11 +110,13 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
);
}
// note
if (bind.sessionGetAuditServerSync(id: id, typ: "conn").isNotEmpty) {
if (bind
.sessionGetAuditServerSync(sessionId: sessionId, typ: "conn")
.isNotEmpty) {
v.add(
TTextMenu(
child: Text(translate('Note')),
onPressed: () => showAuditDialog(id, ffi.dialogManager)),
onPressed: () => showAuditDialog(sessionId, ffi.dialogManager)),
);
}
// divider
@@ -125,7 +130,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
v.add(
TTextMenu(
child: Text('${translate("Insert")} Ctrl + Alt + Del'),
onPressed: () => bind.sessionCtrlAltDel(id: id)),
onPressed: () => bind.sessionCtrlAltDel(sessionId: sessionId)),
);
}
// restart
@@ -136,7 +141,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
v.add(
TTextMenu(
child: Text(translate('Restart Remote Device')),
onPressed: () => showRestartRemoteDevice(pi, id, ffi.dialogManager)),
onPressed: () =>
showRestartRemoteDevice(pi, id, sessionId, ffi.dialogManager)),
);
}
// insertLock
@@ -144,7 +150,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
v.add(
TTextMenu(
child: Text(translate('Insert Lock')),
onPressed: () => bind.sessionLockScreen(id: id)),
onPressed: () => bind.sessionLockScreen(sessionId: sessionId)),
);
}
// blockUserInput
@@ -157,7 +163,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
onPressed: () {
RxBool blockInput = BlockInputState.find(id);
bind.sessionToggleOption(
id: id, value: '${blockInput.value ? 'un' : ''}block-input');
sessionId: sessionId,
value: '${blockInput.value ? 'un' : ''}block-input');
blockInput.value = !blockInput.value;
}));
}
@@ -169,13 +176,14 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
version_cmp(pi.version, '1.2.0') >= 0) {
v.add(TTextMenu(
child: Text(translate('Switch Sides')),
onPressed: () => showConfirmSwitchSidesDialog(id, ffi.dialogManager)));
onPressed: () =>
showConfirmSwitchSidesDialog(sessionId, id, ffi.dialogManager)));
}
// refresh
if (pi.version.isNotEmpty) {
v.add(TTextMenu(
child: Text(translate('Refresh')),
onPressed: () => bind.sessionRefresh(id: id)));
onPressed: () => bind.sessionRefresh(sessionId: sessionId)));
}
// record
var codecFormat = ffi.qualityMonitorModel.data.codecFormat;
@@ -213,11 +221,12 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
Future<List<TRadioMenu<String>>> toolbarViewStyle(
BuildContext context, String id, FFI ffi) async {
final groupValue = await bind.sessionGetViewStyle(id: id) ?? '';
final groupValue =
await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? '';
void onChanged(String? value) async {
if (value == null) return;
bind
.sessionSetViewStyle(id: id, value: value)
.sessionSetViewStyle(sessionId: ffi.sessionId, value: value)
.then((_) => ffi.canvasModel.updateViewStyle());
}
@@ -237,10 +246,11 @@ Future<List<TRadioMenu<String>>> toolbarViewStyle(
Future<List<TRadioMenu<String>>> toolbarImageQuality(
BuildContext context, String id, FFI ffi) async {
final groupValue = await bind.sessionGetImageQuality(id: id) ?? '';
final groupValue =
await bind.sessionGetImageQuality(sessionId: ffi.sessionId) ?? '';
onChanged(String? value) async {
if (value == null) return;
await bind.sessionSetImageQuality(id: id, value: value);
await bind.sessionSetImageQuality(sessionId: ffi.sessionId, value: value);
}
return [
@@ -265,7 +275,7 @@ Future<List<TRadioMenu<String>>> toolbarImageQuality(
groupValue: groupValue,
onChanged: (value) {
onChanged(value);
customImageQualityDialog(id, ffi);
customImageQualityDialog(ffi.sessionId, id, ffi);
},
),
];
@@ -273,9 +283,12 @@ Future<List<TRadioMenu<String>>> toolbarImageQuality(
Future<List<TRadioMenu<String>>> toolbarCodec(
BuildContext context, String id, FFI ffi) async {
final alternativeCodecs = await bind.sessionAlternativeCodecs(id: id);
final groupValue =
await bind.sessionGetOption(id: id, arg: 'codec-preference') ?? '';
final sessionId = ffi.sessionId;
final alternativeCodecs =
await bind.sessionAlternativeCodecs(sessionId: sessionId);
final groupValue = await bind.sessionGetOption(
sessionId: sessionId, arg: 'codec-preference') ??
'';
final List<bool> codecs = [];
try {
final Map codecsJson = jsonDecode(alternativeCodecs);
@@ -296,8 +309,8 @@ Future<List<TRadioMenu<String>>> toolbarCodec(
onChanged(String? value) async {
if (value == null) return;
await bind.sessionPeerOption(
id: id, name: 'codec-preference', value: value);
bind.sessionChangePreferCodec(id: id);
sessionId: sessionId, name: 'codec-preference', value: value);
bind.sessionChangePreferCodec(sessionId: sessionId);
}
TRadioMenu<String> radio(String label, String value, bool enabled) {
@@ -324,6 +337,7 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
final ffiModel = ffi.ffiModel;
final pi = ffiModel.pi;
final perms = ffiModel.permissions;
final sessionId = ffi.sessionId;
// show remote cursor
if (pi.platform != kPeerPlatformAndroid &&
@@ -338,14 +352,15 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
onChanged: enabled
? (value) async {
if (value == null) return;
await bind.sessionToggleOption(id: id, value: option);
state.value =
bind.sessionGetToggleOptionSync(id: id, arg: option);
await bind.sessionToggleOption(
sessionId: sessionId, value: option);
state.value = bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: option);
}
: null));
}
// zoom cursor
final viewStyle = await bind.sessionGetViewStyle(id: id) ?? '';
final viewStyle = await bind.sessionGetViewStyle(sessionId: sessionId) ?? '';
if (!isMobile &&
pi.platform != kPeerPlatformAndroid &&
viewStyle != kRemoteViewStyleOriginal) {
@@ -356,30 +371,32 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
value: peerState.value,
onChanged: (value) async {
if (value == null) return;
await bind.sessionToggleOption(id: id, value: option);
peerState.value = bind.sessionGetToggleOptionSync(id: id, arg: option);
await bind.sessionToggleOption(sessionId: sessionId, value: option);
peerState.value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
},
));
}
// show quality monitor
final option = 'show-quality-monitor';
v.add(TToggleMenu(
value: bind.sessionGetToggleOptionSync(id: id, arg: option),
value: bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option),
onChanged: (value) async {
if (value == null) return;
await bind.sessionToggleOption(id: id, value: option);
ffi.qualityMonitorModel.checkShowQualityMonitor(id);
await bind.sessionToggleOption(sessionId: sessionId, value: option);
ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId);
},
child: Text(translate('Show quality monitor'))));
// mute
if (perms['audio'] != false) {
final option = 'disable-audio';
final value = bind.sessionGetToggleOptionSync(id: id, arg: option);
final value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
v.add(TToggleMenu(
value: value,
onChanged: (value) {
if (value == null) return;
bind.sessionToggleOption(id: id, value: option);
bind.sessionToggleOption(sessionId: sessionId, value: option);
},
child: Text(translate('Mute'))));
}
@@ -388,12 +405,13 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
pi.platform == kPeerPlatformWindows &&
perms['file'] != false) {
final option = 'enable-file-transfer';
final value = bind.sessionGetToggleOptionSync(id: id, arg: option);
final value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
v.add(TToggleMenu(
value: value,
onChanged: (value) {
if (value == null) return;
bind.sessionToggleOption(id: id, value: option);
bind.sessionToggleOption(sessionId: sessionId, value: option);
},
child: Text(translate('Allow file copy and paste'))));
}
@@ -401,14 +419,15 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
if (ffiModel.keyboard && perms['clipboard'] != false) {
final enabled = !ffiModel.viewOnly;
final option = 'disable-clipboard';
var value = bind.sessionGetToggleOptionSync(id: id, arg: option);
var value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
if (ffiModel.viewOnly) value = true;
v.add(TToggleMenu(
value: value,
onChanged: enabled
? (value) {
if (value == null) return;
bind.sessionToggleOption(id: id, value: option);
bind.sessionToggleOption(sessionId: sessionId, value: option);
}
: null,
child: Text(translate('Disable clipboard'))));
@@ -416,12 +435,13 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
// lock after session end
if (ffiModel.keyboard) {
final option = 'lock-after-session-end';
final value = bind.sessionGetToggleOptionSync(id: id, arg: option);
final value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
v.add(TToggleMenu(
value: value,
onChanged: (value) {
if (value == null) return;
bind.sessionToggleOption(id: id, value: option);
bind.sessionToggleOption(sessionId: sessionId, value: option);
},
child: Text(translate('Lock after session end'))));
}
@@ -434,11 +454,11 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
onChanged: (value) {
if (value == null) return;
if (ffiModel.pi.currentDisplay != 0) {
msgBox(id, 'custom-nook-nocancel-hasclose', 'info',
msgBox(sessionId, 'custom-nook-nocancel-hasclose', 'info',
'Please switch to Display 1 first', '', ffi.dialogManager);
return;
}
bind.sessionToggleOption(id: id, value: option);
bind.sessionToggleOption(sessionId: sessionId, value: option);
},
child: Text(translate('Privacy mode'))));
}
@@ -447,12 +467,13 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
((Platform.isMacOS && pi.platform != kPeerPlatformMacOS) ||
(!Platform.isMacOS && pi.platform == kPeerPlatformMacOS))) {
final option = 'allow_swap_key';
final value = bind.sessionGetToggleOptionSync(id: id, arg: option);
final value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
v.add(TToggleMenu(
value: value,
onChanged: (value) {
if (value == null) return;
bind.sessionToggleOption(id: id, value: option);
bind.sessionToggleOption(sessionId: sessionId, value: option);
},
child: Text(translate('Swap control-command key'))));
}

View File

@@ -449,7 +449,8 @@ class _FileManagerViewState extends State<FileManagerView> {
padding: EdgeInsets.all(8.0),
child: FutureBuilder<String>(
future: bind.sessionGetPlatform(
id: _ffi.id, isRemote: !isLocal),
sessionId: _ffi.sessionId,
isRemote: !isLocal),
builder: (context, snapshot) {
if (snapshot.hasData &&
snapshot.data!.isNotEmpty) {

View File

@@ -194,7 +194,7 @@ class _PortForwardPageState extends State<PortForwardPage>
(remoteHostController.text.isEmpty ||
remoteHostController.text.trim().isNotEmpty)) {
await bind.sessionAddPortForward(
id: 'pf_${widget.id}',
sessionId: _ffi.sessionId,
localPort: localPort,
remoteHost: remoteHostController.text.trim().isEmpty
? 'localhost'
@@ -254,7 +254,7 @@ class _PortForwardPageState extends State<PortForwardPage>
icon: const Icon(Icons.close),
onPressed: () async {
await bind.sessionRemovePortForward(
id: 'pf_${widget.id}', localPort: pf.localPort);
sessionId: _ffi.sessionId, localPort: pf.localPort);
refreshTunnelConfig();
},
),
@@ -313,7 +313,7 @@ class _PortForwardPageState extends State<PortForwardPage>
width: 120,
child: ElevatedButton(
onPressed: () =>
bind.sessionNewRdp(id: "pf_${widget.id}"),
bind.sessionNewRdp(sessionId: _ffi.sessionId),
child: Text(
translate('New RDP'),
),

View File

@@ -110,12 +110,12 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
return Platform.isMacOS || kUseCompatibleUiMode
? tabWidget
: Obx(
() => SubWindowDragToResizeArea(
() => SubWindowDragToResizeArea(
child: tabWidget,
resizeEdgeSize: stateGlobal.resizeEdgeSize.value,
windowId: stateGlobal.windowId,
),
);
);
}
void onRemoveId(String id) {

View File

@@ -76,6 +76,8 @@ class _RemotePageState extends State<RemotePage>
late FFI _ffi;
SessionID get sessionId => _ffi.sessionId;
void _initStates(String id) {
initSharedStates(id);
_zoomCursor = PeerBoolOption.find(id, 'zoom-cursor');
@@ -117,19 +119,19 @@ class _RemotePageState extends State<RemotePage>
debugPrint("id: $id, texture_key: $_textureKey");
if (id != -1) {
final ptr = await textureRenderer.getTexturePtr(_textureKey);
platformFFI.registerTexture(widget.id, ptr);
platformFFI.registerTexture(sessionId, ptr);
_textureId.value = id;
}
});
}
_ffi.ffiModel.updateEventListener(widget.id);
_ffi.ffiModel.updateEventListener(sessionId, widget.id);
bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote);
_ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id);
_ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId);
// Session option should be set after models.dart/FFI.start
_showRemoteCursor.value = bind.sessionGetToggleOptionSync(
id: widget.id, arg: 'show-remote-cursor');
_zoomCursor.value =
bind.sessionGetToggleOptionSync(id: widget.id, arg: 'zoom-cursor');
sessionId: sessionId, arg: 'show-remote-cursor');
_zoomCursor.value = bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: 'zoom-cursor');
DesktopMultiWindow.addListener(this);
// if (!_isCustomCursorInited) {
// customCursorController.registerNeedUpdateCursorCallback(
@@ -203,11 +205,11 @@ class _RemotePageState extends State<RemotePage>
void dispose() {
debugPrint("REMOTE PAGE dispose ${widget.id}");
if (useTextureRender) {
platformFFI.registerTexture(widget.id, 0);
platformFFI.registerTexture(sessionId, 0);
textureRenderer.closeTexture(_textureKey);
}
// ensure we leave this session, this is a double check
bind.sessionEnterOrLeave(id: widget.id, enter: false);
bind.sessionEnterOrLeave(sessionId: sessionId, enter: false);
DesktopMultiWindow.removeListener(this);
_ffi.dialogManager.hideMobileActionsOverlay();
_ffi.recordingModel.onClose();
@@ -278,7 +280,7 @@ class _RemotePageState extends State<RemotePage>
super.build(context);
return WillPopScope(
onWillPop: () async {
clientClose(widget.id, _ffi.dialogManager);
clientClose(sessionId, _ffi.dialogManager);
return false;
},
child: MultiProvider(providers: [
@@ -305,7 +307,7 @@ class _RemotePageState extends State<RemotePage>
if (!_rawKeyFocusNode.hasFocus) {
_rawKeyFocusNode.requestFocus();
}
bind.sessionEnterOrLeave(id: widget.id, enter: true);
bind.sessionEnterOrLeave(sessionId: sessionId, enter: true);
}
}
@@ -325,7 +327,7 @@ class _RemotePageState extends State<RemotePage>
}
// See [onWindowBlur].
if (!Platform.isWindows) {
bind.sessionEnterOrLeave(id: widget.id, enter: false);
bind.sessionEnterOrLeave(sessionId: sessionId, enter: false);
}
}

View File

@@ -56,7 +56,11 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
if (peerId != null) {
ConnectionTypeState.init(peerId);
tabController.onSelected = (_, id) {
bind.setCurSessionId(id: id);
final remotePage = tabController.state.value.tabs
.firstWhere((tab) => tab.key == id)
.page as RemotePage;
final ffi = remotePage.ffi;
bind.setCurSessionId(sessionId: ffi.sessionId);
WindowController.fromWindowId(windowId())
.setTitle(getWindowNameWithId(id));
};
@@ -243,6 +247,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
final ffi = remotePage.ffi;
final pi = ffi.ffiModel.pi;
final perms = ffi.ffiModel.permissions;
final sessionId = ffi.sessionId;
menu.addAll([
MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
@@ -282,6 +287,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
menu.add(MenuEntryDivider<String>());
menu.add(RemoteMenuEntry.showRemoteCursor(
key,
sessionId,
padding,
dismissFunc: cancelFunc,
));
@@ -289,15 +295,15 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
if (perms['keyboard'] != false && !ffi.ffiModel.viewOnly) {
if (perms['clipboard'] != false) {
menu.add(RemoteMenuEntry.disableClipboard(key, padding,
menu.add(RemoteMenuEntry.disableClipboard(sessionId, padding,
dismissFunc: cancelFunc));
}
menu.add(
RemoteMenuEntry.insertLock(key, padding, dismissFunc: cancelFunc));
menu.add(RemoteMenuEntry.insertLock(sessionId, padding,
dismissFunc: cancelFunc));
if (pi.platform == kPeerPlatformLinux || pi.sasEnabled) {
menu.add(RemoteMenuEntry.insertCtrlAltDel(key, padding,
menu.add(RemoteMenuEntry.insertCtrlAltDel(sessionId, padding,
dismissFunc: cancelFunc));
}
}

View File

@@ -30,7 +30,7 @@ class _DesktopServerPageState extends State<DesktopServerPage>
final tabController = gFFI.serverModel.tabController;
@override
void initState() {
gFFI.ffiModel.updateEventListener("");
gFFI.ffiModel.updateEventListener(gFFI.sessionId, "");
windowManager.addListener(this);
tabController.onRemoved = (_, id) {
onRemoveId(id);

View File

@@ -141,14 +141,16 @@ class RemoteMenuEntry {
],
curOptionGetter: () async {
// null means peer id is not found, which there's no need to care about
final viewStyle = await bind.sessionGetViewStyle(id: remoteId) ?? '';
final viewStyle =
await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? '';
if (rxViewStyle != null) {
rxViewStyle.value = viewStyle;
}
return viewStyle;
},
optionSetter: (String oldValue, String newValue) async {
await bind.sessionSetViewStyle(id: remoteId, value: newValue);
await bind.sessionSetViewStyle(
sessionId: ffi.sessionId, value: newValue);
if (rxViewStyle != null) {
rxViewStyle.value = newValue;
}
@@ -165,6 +167,7 @@ class RemoteMenuEntry {
static MenuEntrySwitch2<String> showRemoteCursor(
String remoteId,
SessionID sessionId,
EdgeInsets padding, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
@@ -178,9 +181,9 @@ class RemoteMenuEntry {
return state;
},
setter: (bool v) async {
await bind.sessionToggleOption(id: remoteId, value: optKey);
await bind.sessionToggleOption(sessionId: sessionId, value: optKey);
state.value =
bind.sessionGetToggleOptionSync(id: remoteId, arg: optKey);
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: optKey);
if (dismissFunc != null) {
dismissFunc();
}
@@ -192,13 +195,13 @@ class RemoteMenuEntry {
}
static MenuEntrySwitch<String> disableClipboard(
String remoteId,
SessionID sessionId,
EdgeInsets? padding, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
}) {
return createSwitchMenuEntry(
remoteId,
sessionId,
'Disable clipboard',
'disable-clipboard',
padding,
@@ -208,7 +211,7 @@ class RemoteMenuEntry {
}
static MenuEntrySwitch<String> createSwitchMenuEntry(
String remoteId,
SessionID sessionId,
String text,
String option,
EdgeInsets? padding,
@@ -220,10 +223,11 @@ class RemoteMenuEntry {
switchType: SwitchType.scheckbox,
text: translate(text),
getter: () async {
return bind.sessionGetToggleOptionSync(id: remoteId, arg: option);
return bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: option);
},
setter: (bool v) async {
await bind.sessionToggleOption(id: remoteId, value: option);
await bind.sessionToggleOption(sessionId: sessionId, value: option);
if (dismissFunc != null) {
dismissFunc();
}
@@ -235,7 +239,7 @@ class RemoteMenuEntry {
}
static MenuEntryButton<String> insertLock(
String remoteId,
SessionID sessionId,
EdgeInsets? padding, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
@@ -246,7 +250,7 @@ class RemoteMenuEntry {
style: style,
),
proc: () {
bind.sessionLockScreen(id: remoteId);
bind.sessionLockScreen(sessionId: sessionId);
if (dismissFunc != null) {
dismissFunc();
}
@@ -258,7 +262,7 @@ class RemoteMenuEntry {
}
static insertCtrlAltDel(
String remoteId,
SessionID sessionId,
EdgeInsets? padding, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
@@ -269,7 +273,7 @@ class RemoteMenuEntry {
style: style,
),
proc: () {
bind.sessionCtrlAltDel(id: remoteId);
bind.sessionCtrlAltDel(sessionId: sessionId);
if (dismissFunc != null) {
dismissFunc();
}
@@ -329,7 +333,8 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
Future.delayed(Duration.zero, () async {
_fractionX.value = double.tryParse(await bind.sessionGetOption(
id: widget.id, arg: 'remote-menubar-drag-x') ??
sessionId: widget.ffi.sessionId,
arg: 'remote-menubar-drag-x') ??
'0.5') ??
0.5;
});
@@ -387,7 +392,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
elevation: _MenubarTheme.elevation,
shadowColor: MyTheme.color(context).shadow,
child: _DraggableShowHide(
id: widget.id,
sessionId: widget.ffi.sessionId,
dragging: _dragging,
fractionX: _fractionX,
show: show,
@@ -621,7 +626,7 @@ class _MonitorMenu extends StatelessWidget {
_menuDismissCallback(ffi);
RxInt display = CurrentDisplayState.find(id);
if (display.value != i) {
bind.sessionSwitchDisplay(id: id, value: i);
bind.sessionSwitchDisplay(sessionId: ffi.sessionId, value: i);
}
},
));
@@ -763,7 +768,8 @@ class ScreenAdjustor {
}
Future<bool> isWindowCanBeAdjusted() async {
final viewStyle = await bind.sessionGetViewStyle(id: id) ?? '';
final viewStyle =
await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? '';
if (viewStyle != kRemoteViewStyleOriginal) {
return false;
}
@@ -885,9 +891,11 @@ class _DisplayMenuState extends State<_DisplayMenu> {
scrollStyle() {
return futureBuilder(future: () async {
final viewStyle = await bind.sessionGetViewStyle(id: id) ?? '';
final viewStyle =
await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? '';
final visible = viewStyle == kRemoteViewStyleOriginal;
final scrollStyle = await bind.sessionGetScrollStyle(id: widget.id) ?? '';
final scrollStyle =
await bind.sessionGetScrollStyle(sessionId: ffi.sessionId) ?? '';
return {'visible': visible, 'scrollStyle': scrollStyle};
}(), hasData: (data) {
final visible = data['visible'] as bool;
@@ -895,7 +903,8 @@ class _DisplayMenuState extends State<_DisplayMenu> {
final groupValue = data['scrollStyle'] as String;
onChange(String? value) async {
if (value == null) return;
await bind.sessionSetScrollStyle(id: widget.id, value: value);
await bind.sessionSetScrollStyle(
sessionId: ffi.sessionId, value: value);
widget.ffi.canvasModel.updateScrollStyle();
}
@@ -1007,6 +1016,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
late final TextEditingController _customHeight =
TextEditingController(text: display.height.toString());
FFI get ffi => widget.ffi;
PeerInfo get pi => widget.ffi.ffiModel.pi;
FfiModel get ffiModel => widget.ffi.ffiModel;
Display get display => ffiModel.display;
@@ -1101,7 +1111,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
_changeResolution(int w, int h) async {
await bind.sessionChangeResolution(
id: widget.id,
sessionId: ffi.sessionId,
display: pi.currentDisplay,
width: w,
height: h,
@@ -1254,12 +1264,15 @@ class _KeyboardMenu extends StatelessWidget {
if (!ffiModel.keyboard) return Offstage();
String? modeOnly;
if (stateGlobal.grabKeyboard) {
if (bind.sessionIsKeyboardModeSupported(id: id, mode: _kKeyMapMode)) {
bind.sessionSetKeyboardMode(id: id, value: _kKeyMapMode);
if (bind.sessionIsKeyboardModeSupported(
sessionId: ffi.sessionId, mode: _kKeyMapMode)) {
bind.sessionSetKeyboardMode(
sessionId: ffi.sessionId, value: _kKeyMapMode);
modeOnly = _kKeyMapMode;
} else if (bind.sessionIsKeyboardModeSupported(
id: id, mode: _kKeyLegacyMode)) {
bind.sessionSetKeyboardMode(id: id, value: _kKeyLegacyMode);
sessionId: ffi.sessionId, mode: _kKeyLegacyMode)) {
bind.sessionSetKeyboardMode(
sessionId: ffi.sessionId, value: _kKeyLegacyMode);
modeOnly = _kKeyLegacyMode;
}
}
@@ -1279,7 +1292,8 @@ class _KeyboardMenu extends StatelessWidget {
mode(String? modeOnly) {
return futureBuilder(future: () async {
return await bind.sessionGetKeyboardMode(id: id) ?? _kKeyLegacyMode;
return await bind.sessionGetKeyboardMode(sessionId: ffi.sessionId) ??
_kKeyLegacyMode;
}(), hasData: (data) {
final groupValue = data as String;
List<KeyboardModeMenu> modes = [
@@ -1291,14 +1305,15 @@ class _KeyboardMenu extends StatelessWidget {
final enabled = !ffi.ffiModel.viewOnly;
onChanged(String? value) async {
if (value == null) return;
await bind.sessionSetKeyboardMode(id: id, value: value);
await bind.sessionSetKeyboardMode(
sessionId: ffi.sessionId, value: value);
}
for (KeyboardModeMenu mode in modes) {
if (modeOnly != null && mode.key != modeOnly) {
continue;
} else if (!bind.sessionIsKeyboardModeSupported(
id: id, mode: mode.key)) {
sessionId: ffi.sessionId, mode: mode.key)) {
continue;
}
@@ -1351,7 +1366,8 @@ class _KeyboardMenu extends StatelessWidget {
onChanged: enabled
? (value) async {
if (value == null) return;
await bind.sessionToggleOption(id: id, value: 'view-only');
await bind.sessionToggleOption(
sessionId: ffi.sessionId, value: 'view-only');
ffiModel.setViewOnly(id, value);
}
: null,
@@ -1412,7 +1428,8 @@ class _ChatMenuState extends State<_ChatMenu> {
return MenuButton(
child: Text(translate('Voice call')),
ffi: widget.ffi,
onPressed: () => bind.sessionRequestVoiceCall(id: widget.id),
onPressed: () =>
bind.sessionRequestVoiceCall(sessionId: widget.ffi.sessionId),
);
}
}
@@ -1447,7 +1464,8 @@ class _VoiceCallMenu extends StatelessWidget {
return _IconMenuButton(
assetName: icon,
tooltip: tooltip,
onPressed: () => bind.sessionCloseVoiceCall(id: id),
onPressed: () =>
bind.sessionCloseVoiceCall(sessionId: ffi.sessionId),
color: _MenubarTheme.redColor,
hoverColor: _MenubarTheme.hoverRedColor);
},
@@ -1492,7 +1510,7 @@ class _CloseMenu extends StatelessWidget {
return _IconMenuButton(
assetName: 'assets/close.svg',
tooltip: 'Close',
onPressed: () => clientClose(id, ffi.dialogManager),
onPressed: () => clientClose(ffi.sessionId, ffi.dialogManager),
color: _MenubarTheme.redColor,
hoverColor: _MenubarTheme.hoverRedColor,
);
@@ -1753,13 +1771,13 @@ class RdoMenuButton<T> extends StatelessWidget {
}
class _DraggableShowHide extends StatefulWidget {
final String id;
final SessionID sessionId;
final RxDouble fractionX;
final RxBool dragging;
final RxBool show;
const _DraggableShowHide({
Key? key,
required this.id,
required this.sessionId,
required this.fractionX,
required this.dragging,
required this.show,
@@ -1826,7 +1844,7 @@ class _DraggableShowHideState extends State<_DraggableShowHide> {
widget.fractionX.value = right;
}
bind.sessionPeerOption(
id: widget.id,
sessionId: widget.sessionId,
name: 'remote-menubar-drag-x',
value: widget.fractionX.value.toString(),
);
@@ -1952,7 +1970,7 @@ class _MultiMonitorMenu extends StatelessWidget {
),
onPressed: () {
if (display.value != i) {
bind.sessionSwitchDisplay(id: id, value: i);
bind.sessionSwitchDisplay(sessionId: ffi.sessionId, value: i);
}
},
);

View File

@@ -17,6 +17,7 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:get/get_rx/src/rx_workers/utils/debouncer.dart';
import 'package:scroll_pos/scroll_pos.dart';
import 'package:uuid/uuid.dart';
import 'package:window_manager/window_manager.dart';
import '../../utils/multi_window_manager.dart';

View File

@@ -73,7 +73,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
gFFI.dialogManager
.showLoading(translate('Connecting...'), onCancel: closeConnection);
});
gFFI.ffiModel.updateEventListener(widget.id);
gFFI.ffiModel.updateEventListener(gFFI.sessionId, widget.id);
Wakelock.enable();
}
@@ -104,7 +104,8 @@ class _FileManagerPageState extends State<FileManagerPage> {
leading: Row(children: [
IconButton(
icon: Icon(Icons.close),
onPressed: () => clientClose(widget.id, gFFI.dialogManager)),
onPressed: () =>
clientClose(gFFI.sessionId, gFFI.dialogManager)),
]),
centerTitle: true,
title: ToggleSwitch(

View File

@@ -54,6 +54,7 @@ class _RemotePageState extends State<RemotePage> {
var _showEdit = false; // use soft keyboard
InputModel get inputModel => gFFI.inputModel;
SessionID get sessionId => gFFI.sessionId;
@override
void initState() {
@@ -66,9 +67,9 @@ class _RemotePageState extends State<RemotePage> {
});
Wakelock.enable();
_physicalFocusNode.requestFocus();
gFFI.ffiModel.updateEventListener(widget.id);
gFFI.ffiModel.updateEventListener(sessionId, widget.id);
gFFI.inputModel.listenToMouse(true);
gFFI.qualityMonitorModel.checkShowQualityMonitor(widget.id);
gFFI.qualityMonitorModel.checkShowQualityMonitor(sessionId);
keyboardSubscription =
keyboardVisibilityController.onChange.listen(onSoftKeyboardChanged);
_blockableOverlayState.applyFfi(gFFI);
@@ -130,7 +131,7 @@ class _RemotePageState extends State<RemotePage> {
if (newValue.length > common) {
var s = newValue.substring(common);
if (s.length > 1) {
bind.sessionInputString(id: widget.id, value: s);
bind.sessionInputString(sessionId: sessionId, value: s);
} else {
inputChar(s);
}
@@ -164,11 +165,11 @@ class _RemotePageState extends State<RemotePage> {
content == '' ||
content == '【】')) {
// can not only input content[0], because when input ], [ are also auo insert, which cause ] never be input
bind.sessionInputString(id: widget.id, value: content);
bind.sessionInputString(sessionId: sessionId, value: content);
openKeyboard();
return;
}
bind.sessionInputString(id: widget.id, value: content);
bind.sessionInputString(sessionId: sessionId, value: content);
} else {
inputChar(content);
}
@@ -213,7 +214,7 @@ class _RemotePageState extends State<RemotePage> {
return WillPopScope(
onWillPop: () async {
clientClose(widget.id, gFFI.dialogManager);
clientClose(sessionId, gFFI.dialogManager);
return false;
},
child: getRawPointerAndKeyBody(Scaffold(
@@ -305,7 +306,7 @@ class _RemotePageState extends State<RemotePage> {
color: Colors.white,
icon: Icon(Icons.clear),
onPressed: () {
clientClose(widget.id, gFFI.dialogManager);
clientClose(sessionId, gFFI.dialogManager);
},
)
] +
@@ -476,7 +477,7 @@ class _RemotePageState extends State<RemotePage> {
},
onTwoFingerScaleEnd: (d) {
_scale = 1;
bind.sessionSetViewStyle(id: widget.id, value: "");
bind.sessionSetViewStyle(sessionId: sessionId, value: "");
},
onThreeFingerVerticalDragUpdate: gFFI.ffiModel.isPeerAndroid
? null
@@ -535,7 +536,7 @@ class _RemotePageState extends State<RemotePage> {
var paints = <Widget>[ImagePaint()];
if (!gFFI.canvasModel.cursorEmbedded) {
final cursor = bind.sessionGetToggleOptionSync(
id: widget.id, arg: 'show-remote-cursor');
sessionId: sessionId, arg: 'show-remote-cursor');
if (keyboard || cursor) {
paints.add(CursorPaint());
}
@@ -579,7 +580,7 @@ class _RemotePageState extends State<RemotePage> {
gFFI.ffiModel.toggleTouchMode();
final v = gFFI.ffiModel.touchMode ? 'Y' : '';
bind.sessionPeerOption(
id: widget.id, name: "touch", value: v);
sessionId: sessionId, name: "touch", value: v);
})));
}
@@ -830,7 +831,7 @@ void showOptions(
children.add(InkWell(
onTap: () {
if (i == cur) return;
bind.sessionSwitchDisplay(id: id, value: i);
bind.sessionSwitchDisplay(sessionId: gFFI.sessionId, value: i);
gFFI.dialogManager.dismissAll();
},
child: Ink(

View File

@@ -74,7 +74,11 @@ class ChatModel with ChangeNotifier {
final WeakReference<FFI> parent;
ChatModel(this.parent);
late final SessionID sessionId;
ChatModel(this.parent) {
sessionId = parent.target!.sessionId;
}
FocusNode inputNode = FocusNode();
@@ -302,7 +306,7 @@ class ChatModel with ChangeNotifier {
_messages[_currentID]?.insert(message);
if (_currentID == clientModeID) {
if (parent.target != null) {
bind.sessionSendChat(id: parent.target!.id, text: message.text);
bind.sessionSendChat(sessionId: sessionId, text: message.text);
}
} else {
bind.cmSendChat(connId: _currentID, msg: message.text);
@@ -347,8 +351,8 @@ class ChatModel with ChangeNotifier {
}
}
void closeVoiceCall(String id) {
bind.sessionCloseVoiceCall(id: id);
void closeVoiceCall() {
bind.sessionCloseVoiceCall(sessionId: sessionId);
}
}

View File

@@ -33,11 +33,11 @@ class JobID {
}
}
typedef GetSessionID = String Function();
typedef GetSessionID = SessionID Function();
class FileModel {
final WeakReference<FFI> parent;
// late final String sessionID;
// late final String sessionId;
late final FileFetcher fileFetcher;
late final JobController jobController;
@@ -45,11 +45,11 @@ class FileModel {
late final FileController remoteController;
late final GetSessionID getSessionID;
String get sessionID => getSessionID();
SessionID get sessionId => getSessionID();
late final FileDialogEventLoop evtLoop;
FileModel(this.parent) {
getSessionID = () => parent.target?.id ?? "";
getSessionID = () => parent.target!.sessionId;
fileFetcher = FileFetcher(getSessionID);
jobController = JobController(getSessionID);
localController = FileController(
@@ -133,7 +133,7 @@ class FileModel {
evtLoop.setSkip(!need_override);
}
await bind.sessionSetConfirmOverrideFile(
id: sessionID,
sessionId: sessionId,
actId: id,
fileNum: int.parse(evt['file_num']),
needOverride: need_override,
@@ -236,7 +236,7 @@ class DirectoryData {
class FileController {
final bool isLocal;
final GetSessionID getSessionID;
String get sessionID => getSessionID();
SessionID get sessionId => getSessionID();
final FileFetcher fileFetcher;
@@ -287,7 +287,7 @@ class FileController {
options.value.home = await bind.mainGetHomeDir();
}
options.value.showHidden = (await bind.sessionGetPeerOption(
id: sessionID,
sessionId: sessionId,
name: isLocal ? "local_show_hidden" : "remote_show_hidden"))
.isNotEmpty;
options.value.isWindows = isLocal
@@ -297,7 +297,7 @@ class FileController {
await Future.delayed(Duration(milliseconds: 100));
final dir = (await bind.sessionGetPeerOption(
id: sessionID, name: isLocal ? "local_dir" : "remote_dir"));
sessionId: sessionId, name: isLocal ? "local_dir" : "remote_dir"));
openDirectory(dir.isEmpty ? options.value.home : dir);
await Future.delayed(Duration(seconds: 1));
@@ -315,7 +315,7 @@ class FileController {
options.value.showHidden ? "Y" : "";
for (final msg in msgMap.entries) {
await bind.sessionPeerOption(
id: sessionID, name: msg.key, value: msg.value);
sessionId: sessionId, name: msg.key, value: msg.value);
}
directory.value.clear();
options.value.clear();
@@ -447,7 +447,7 @@ class FileController {
for (var from in items.items) {
final jobID = jobController.add(from, isRemoteToLocal);
bind.sessionSendFiles(
id: sessionID,
sessionId: sessionId,
actId: jobID,
path: from.path,
to: PathUtil.join(toPath, from.name, isWindows),
@@ -547,7 +547,8 @@ class FileController {
Future<bool?> showRemoveDialog(
String title, String content, bool showCheckbox) async {
return await dialogManager?.show<bool>((setState, Function(bool v) close, context) {
return await dialogManager?.show<bool>(
(setState, Function(bool v) close, context) {
cancel() => close(false);
submit() => close(true);
return CustomAlertDialog(
@@ -611,7 +612,7 @@ class FileController {
void sendRemoveFile(String path, int fileNum) {
bind.sessionRemoveFile(
id: sessionID,
sessionId: sessionId,
actId: JobController.jobID.next(),
path: path,
isRemote: !isLocal,
@@ -621,7 +622,7 @@ class FileController {
void sendRemoveEmptyDir(String path, int fileNum) {
history.removeWhere((element) => element.contains(path));
bind.sessionRemoveAllEmptyDirs(
id: sessionID,
sessionId: sessionId,
actId: JobController.jobID.next(),
path: path,
isRemote: !isLocal);
@@ -629,7 +630,7 @@ class FileController {
Future<void> createDir(String path) async {
bind.sessionCreateDir(
id: sessionID,
sessionId: sessionId,
actId: JobController.jobID.next(),
path: path,
isRemote: !isLocal);
@@ -641,7 +642,7 @@ class JobController {
final jobTable = List<JobProgress>.empty(growable: true).obs;
final jobResultListener = JobResultListener<Map<String, dynamic>>();
final GetSessionID getSessionID;
String get sessionID => getSessionID();
SessionID get sessionId => getSessionID();
JobController(this.getSessionID);
@@ -719,7 +720,7 @@ class JobController {
}
Future<void> cancelJob(int id) async {
await bind.sessionCancelJob(id: sessionID, actId: id);
await bind.sessionCancelJob(sessionId: sessionId, actId: id);
}
void loadLastJob(Map<String, dynamic> evt) {
@@ -745,7 +746,7 @@ class JobController {
..state = JobState.paused;
jobTable.add(jobProgress);
bind.sessionAddJob(
id: sessionID,
sessionId: sessionId,
isRemote: isRemote,
includeHidden: showHidden,
actId: currJobId,
@@ -760,7 +761,7 @@ class JobController {
if (jobIndex != -1) {
final job = jobTable[jobIndex];
bind.sessionResumeJob(
id: sessionID, actId: job.id, isRemote: job.isRemoteToLocal);
sessionId: sessionId, actId: job.id, isRemote: job.isRemoteToLocal);
job.state = JobState.inProgress;
jobTable.refresh();
} else {
@@ -831,7 +832,7 @@ class FileFetcher {
Map<int, Completer<FileDirectory>> readRecursiveTasks = {};
final GetSessionID getSessionID;
String get sessionID => getSessionID();
SessionID get sessionId => getSessionID();
FileFetcher(this.getSessionID);
@@ -896,12 +897,12 @@ class FileFetcher {
try {
if (isLocal) {
final res = await bind.sessionReadLocalDirSync(
id: sessionID, path: path, showHidden: showHidden);
sessionId: sessionId, path: path, showHidden: showHidden);
final fd = FileDirectory.fromJson(jsonDecode(res));
return fd;
} else {
await bind.sessionReadRemoteDir(
id: sessionID, path: path, includeHidden: showHidden);
sessionId: sessionId, path: path, includeHidden: showHidden);
return registerReadTask(isLocal, path);
}
} catch (e) {
@@ -914,7 +915,7 @@ class FileFetcher {
// TODO test Recursive is show hidden default?
try {
await bind.sessionReadDirRecursive(
id: sessionID,
sessionId: sessionId,
actId: actID,
path: path,
isRemote: !isLocal,

View File

@@ -59,9 +59,13 @@ class InputModel {
get id => parent.target?.id ?? "";
late final SessionID sessionId;
bool get keyboardPerm => parent.target!.ffiModel.keyboard;
InputModel(this.parent);
InputModel(this.parent) {
sessionId = parent.target!.sessionId;
}
KeyEventResult handleRawKeyEvent(FocusNode data, RawKeyEvent e) {
if (isDesktop && !stateGlobal.grabKeyboard) {
@@ -70,7 +74,7 @@ class InputModel {
// * Currently mobile does not enable map mode
if (isDesktop) {
bind.sessionGetKeyboardMode(id: id).then((result) {
bind.sessionGetKeyboardMode(sessionId: sessionId).then((result) {
keyboardMode = result.toString();
});
}
@@ -169,7 +173,7 @@ class InputModel {
lockModes |= (1 << scrolllock);
}
bind.sessionHandleFlutterKeyEvent(
id: id,
sessionId: sessionId,
name: name,
platformCode: platformCode,
positionCode: positionCode,
@@ -204,7 +208,7 @@ class InputModel {
void inputKey(String name, {bool? down, bool? press}) {
if (!keyboardPerm) return;
bind.sessionInputKey(
id: id,
sessionId: sessionId,
name: name,
down: down ?? false,
press: press ?? true,
@@ -264,7 +268,7 @@ class InputModel {
/// Send scroll event with scroll distance [y].
void scroll(int y) {
bind.sessionSendMouse(
id: id,
sessionId: sessionId,
msg: json
.encode(modify({'id': id, 'type': 'wheel', 'y': y.toString()})));
}
@@ -287,7 +291,7 @@ class InputModel {
void sendMouse(String type, MouseButtons button) {
if (!keyboardPerm) return;
bind.sessionSendMouse(
id: id,
sessionId: sessionId,
msg: json.encode(modify({'type': type, 'buttons': button.value})));
}
@@ -297,7 +301,7 @@ class InputModel {
resetModifiers();
}
_flingTimer?.cancel();
bind.sessionEnterOrLeave(id: id, enter: enter);
bind.sessionEnterOrLeave(sessionId: sessionId, enter: enter);
}
/// Send mouse movement event with distance in [x] and [y].
@@ -306,7 +310,8 @@ class InputModel {
var x2 = x.toInt();
var y2 = y.toInt();
bind.sessionSendMouse(
id: id, msg: json.encode(modify({'x': '$x2', 'y': '$y2'})));
sessionId: sessionId,
msg: json.encode(modify({'x': '$x2', 'y': '$y2'})));
}
void onPointHoverImage(PointerHoverEvent e) {
@@ -333,7 +338,8 @@ class InputModel {
var y = delta.dy.toInt();
if (x != 0 || y != 0) {
bind.sessionSendMouse(
id: id, msg: '{"type": "trackpad", "x": "$x", "y": "$y"}');
sessionId: sessionId,
msg: '{"type": "trackpad", "x": "$x", "y": "$y"}');
}
}
@@ -364,7 +370,8 @@ class InputModel {
}
bind.sessionSendMouse(
id: id, msg: '{"type": "trackpad", "x": "$dx", "y": "$dy"}');
sessionId: sessionId,
msg: '{"type": "trackpad", "x": "$dx", "y": "$dy"}');
_scheduleFling(x, y, delay);
});
}
@@ -439,7 +446,8 @@ class InputModel {
dy = 1;
}
bind.sessionSendMouse(
id: id, msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}');
sessionId: sessionId,
msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}');
}
}
@@ -632,7 +640,7 @@ class InputModel {
break;
}
evt['buttons'] = buttons;
bind.sessionSendMouse(id: id, msg: json.encode(evt));
bind.sessionSendMouse(sessionId: sessionId, msg: json.encode(evt));
}
/// Web only

View File

@@ -27,6 +27,7 @@ import 'package:image/image.dart' as img2;
import 'package:flutter_custom_cursor/cursor_manager.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:uuid/uuid.dart';
import 'package:window_manager/window_manager.dart';
import '../common.dart';
@@ -36,7 +37,7 @@ import 'input_model.dart';
import 'platform_model.dart';
typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id);
typedef ReconnectHandle = Function(OverlayDialogManager, String, bool);
typedef ReconnectHandle = Function(OverlayDialogManager, SessionID, bool);
final _waitForImage = <String, bool>{};
class FfiModel with ChangeNotifier {
@@ -52,6 +53,7 @@ class FfiModel with ChangeNotifier {
var _reconnects = 1;
bool _viewOnly = false;
WeakReference<FFI> parent;
late final SessionID sessionId;
Map<String, bool> get permissions => _permissions;
@@ -77,6 +79,7 @@ class FfiModel with ChangeNotifier {
FfiModel(this.parent) {
clear();
sessionId = parent.target!.sessionId;
}
toggleTouchMode() {
@@ -139,20 +142,21 @@ class FfiModel with ChangeNotifier {
_permissions.clear();
}
StreamEventHandler startEventListener(String peerId) {
// todo: why called by two position
StreamEventHandler startEventListener(SessionID sessionId, String peerId) {
return (evt) async {
var name = evt['name'];
if (name == 'msgbox') {
handleMsgBox(evt, peerId);
handleMsgBox(evt, sessionId, peerId);
} else if (name == 'peer_info') {
handlePeerInfo(evt, peerId);
} else if (name == 'sync_peer_info') {
handleSyncPeerInfo(evt, peerId);
handleSyncPeerInfo(evt, sessionId);
} else if (name == 'connection_ready') {
setConnectionType(
peerId, evt['secure'] == 'true', evt['direct'] == 'true');
} else if (name == 'switch_display') {
handleSwitchDisplay(evt, peerId);
handleSwitchDisplay(evt, sessionId, peerId);
} else if (name == 'cursor_data') {
await parent.target?.cursorModel.updateCursorData(evt);
} else if (name == 'cursor_id') {
@@ -193,7 +197,7 @@ class FfiModel with ChangeNotifier {
} else if (name == 'update_block_input_state') {
updateBlockInputState(evt, peerId);
} else if (name == 'update_privacy_mode') {
updatePrivacyMode(evt, peerId);
updatePrivacyMode(evt, sessionId, peerId);
} else if (name == 'new_connection') {
var uni_links = evt['uni_links'].toString();
if (uni_links.startsWith(kUniLinksPrefix)) {
@@ -205,10 +209,10 @@ class FfiModel with ChangeNotifier {
final show = evt['show'].toString() == 'true';
parent.target?.serverModel.setShowElevation(show);
} else if (name == 'cancel_msgbox') {
cancelMsgBox(evt, peerId);
cancelMsgBox(evt, sessionId);
} else if (name == 'switch_back') {
final peer_id = evt['peer_id'].toString();
await bind.sessionSwitchSides(id: peer_id);
await bind.sessionSwitchSides(sessionId: sessionId);
closeConnection(id: peer_id);
} else if (name == 'portable_service_running') {
parent.target?.elevationModel.onPortableServiceRunning(evt);
@@ -234,12 +238,12 @@ class FfiModel with ChangeNotifier {
} else if (name == 'plugin_manager') {
pluginManager.handleEvent(evt);
} else if (name == 'plugin_event') {
handlePluginEvent(
evt, peerId, (Map<String, dynamic> e) => handleMsgBox(e, peerId));
handlePluginEvent(evt,
(Map<String, dynamic> e) => handleMsgBox(e, sessionId, peerId));
} else if (name == 'plugin_reload') {
handleReloading(evt, peerId);
handleReloading(evt);
} else if (name == 'plugin_option') {
handleOption(evt, peerId);
handleOption(evt);
} else {
debugPrint('Unknown event name: $name');
}
@@ -271,8 +275,8 @@ class FfiModel with ChangeNotifier {
}
/// Bind the event listener to receive events from the Rust core.
updateEventListener(String peerId) {
platformFFI.setEventCallback(startEventListener(peerId));
updateEventListener(SessionID sessionId, String peerId) {
platformFFI.setEventCallback(startEventListener(sessionId, peerId));
}
handleAliasChanged(Map<String, dynamic> evt) {
@@ -282,18 +286,19 @@ class FfiModel with ChangeNotifier {
}
}
_updateCurDisplay(String peerId, Display newDisplay) {
_updateCurDisplay(SessionID sessionId, Display newDisplay) {
if (newDisplay != _display) {
if (newDisplay.x != _display.x || newDisplay.y != _display.y) {
parent.target?.cursorModel
.updateDisplayOrigin(newDisplay.x, newDisplay.y);
}
_display = newDisplay;
_updateSessionWidthHeight(peerId);
_updateSessionWidthHeight(sessionId);
}
}
handleSwitchDisplay(Map<String, dynamic> evt, String peerId) {
handleSwitchDisplay(
Map<String, dynamic> evt, SessionID sessionId, String peerId) {
_pi.currentDisplay = int.parse(evt['display']);
var newDisplay = Display();
newDisplay.x = double.tryParse(evt['x']) ?? newDisplay.x;
@@ -306,7 +311,7 @@ class FfiModel with ChangeNotifier {
newDisplay.originalHeight =
int.tryParse(evt['original_height']) ?? kInvalidResolutionValue;
_updateCurDisplay(peerId, newDisplay);
_updateCurDisplay(sessionId, newDisplay);
try {
CurrentDisplayState.find(peerId).value = _pi.currentDisplay;
@@ -318,15 +323,15 @@ class FfiModel with ChangeNotifier {
notifyListeners();
}
cancelMsgBox(Map<String, dynamic> evt, String id) {
cancelMsgBox(Map<String, dynamic> evt, SessionID sessionId) {
if (parent.target == null) return;
final dialogManager = parent.target!.dialogManager;
final tag = '$id-${evt['tag']}';
final tag = '$sessionId-${evt['tag']}';
dialogManager.dismissByTag(tag);
}
/// Handle the message box event based on [evt] and [id].
handleMsgBox(Map<String, dynamic> evt, String id) {
handleMsgBox(Map<String, dynamic> evt, SessionID sessionId, String peerId) {
if (parent.target == null) return;
final dialogManager = parent.target!.dialogManager;
final type = evt['type'];
@@ -334,43 +339,43 @@ class FfiModel with ChangeNotifier {
final text = evt['text'];
final link = evt['link'];
if (type == 're-input-password') {
wrongPasswordDialog(id, dialogManager, type, title, text);
wrongPasswordDialog(sessionId, dialogManager, type, title, text);
} else if (type == 'input-password') {
enterPasswordDialog(id, dialogManager);
enterPasswordDialog(sessionId, dialogManager);
} else if (type == 'session-login' || type == 'session-re-login') {
enterUserLoginDialog(id, dialogManager);
enterUserLoginDialog(sessionId, dialogManager);
} else if (type == 'session-login-password' ||
type == 'session-login-password') {
enterUserLoginAndPasswordDialog(id, dialogManager);
enterUserLoginAndPasswordDialog(sessionId, dialogManager);
} else if (type == 'restarting') {
showMsgBox(id, type, title, text, link, false, dialogManager,
showMsgBox(sessionId, type, title, text, link, false, dialogManager,
hasCancel: false);
} else if (type == 'wait-remote-accept-nook') {
showWaitAcceptDialog(id, type, title, text, dialogManager);
showWaitAcceptDialog(sessionId, type, title, text, dialogManager);
} else if (type == 'on-uac' || type == 'on-foreground-elevated') {
showOnBlockDialog(id, type, title, text, dialogManager);
showOnBlockDialog(sessionId, type, title, text, dialogManager);
} else if (type == 'wait-uac') {
showWaitUacDialog(id, dialogManager, type);
showWaitUacDialog(sessionId, dialogManager, type);
} else if (type == 'elevation-error') {
showElevationError(id, type, title, text, dialogManager);
showElevationError(sessionId, type, title, text, dialogManager);
} else if (type == 'relay-hint') {
showRelayHintDialog(id, type, title, text, dialogManager);
showRelayHintDialog(sessionId, type, title, text, dialogManager);
} else {
var hasRetry = evt['hasRetry'] == 'true';
showMsgBox(id, type, title, text, link, hasRetry, dialogManager);
showMsgBox(sessionId, type, title, text, link, hasRetry, dialogManager);
}
}
/// Show a message box with [type], [title] and [text].
showMsgBox(String id, String type, String title, String text, String link,
bool hasRetry, OverlayDialogManager dialogManager,
showMsgBox(SessionID sessionId, String type, String title, String text,
String link, bool hasRetry, OverlayDialogManager dialogManager,
{bool? hasCancel}) {
msgBox(id, type, title, text, link, dialogManager,
msgBox(sessionId, type, title, text, link, dialogManager,
hasCancel: hasCancel, reconnect: reconnect);
_timer?.cancel();
if (hasRetry) {
_timer = Timer(Duration(seconds: _reconnects), () {
reconnect(dialogManager, id, false);
reconnect(dialogManager, sessionId, false);
});
_reconnects *= 2;
} else {
@@ -378,17 +383,17 @@ class FfiModel with ChangeNotifier {
}
}
void reconnect(
OverlayDialogManager dialogManager, String id, bool forceRelay) {
bind.sessionReconnect(id: id, forceRelay: forceRelay);
void reconnect(OverlayDialogManager dialogManager, SessionID sessionId,
bool forceRelay) {
bind.sessionReconnect(sessionId: sessionId, forceRelay: forceRelay);
clearPermissions();
dialogManager.showLoading(translate('Connecting...'),
onCancel: closeConnection);
}
void showRelayHintDialog(String id, String type, String title, String text,
OverlayDialogManager dialogManager) {
dialogManager.show(tag: '$id-$type', (setState, close, context) {
void showRelayHintDialog(SessionID sessionId, String type, String title,
String text, OverlayDialogManager dialogManager) {
dialogManager.show(tag: '$sessionId-$type', (setState, close, context) {
onClose() {
closeConnection();
close();
@@ -403,15 +408,17 @@ class FfiModel with ChangeNotifier {
actions: [
dialogButton('Close', onPressed: onClose, isOutline: true),
dialogButton('Retry',
onPressed: () => reconnect(dialogManager, id, false)),
onPressed: () => reconnect(dialogManager, sessionId, false)),
dialogButton('Connect via relay',
onPressed: () => reconnect(dialogManager, id, true),
onPressed: () => reconnect(dialogManager, sessionId, true),
buttonStyle: style),
dialogButton('Always connect via relay', onPressed: () {
const option = 'force-always-relay';
bind.sessionPeerOption(
id: id, name: option, value: bool2option(option, true));
reconnect(dialogManager, id, true);
sessionId: sessionId,
name: option,
value: bool2option(option, true));
reconnect(dialogManager, sessionId, true);
}, buttonStyle: style),
],
onCancel: onClose,
@@ -419,13 +426,14 @@ class FfiModel with ChangeNotifier {
});
}
_updateSessionWidthHeight(String id) {
_updateSessionWidthHeight(SessionID sessionId) {
parent.target?.canvasModel.updateViewStyle();
if (display.width <= 0 || display.height <= 0) {
debugPrintStack(
label: 'invalid display size (${display.width},${display.height})');
} else {
bind.sessionSetSize(id: id, width: display.width, height: display.height);
bind.sessionSetSize(
sessionId: sessionId, width: display.width, height: display.height);
}
}
@@ -461,8 +469,9 @@ class FfiModel with ChangeNotifier {
.showMobileActionsOverlay(ffi: parent.target!));
}
} else {
_touchMode =
await bind.sessionGetOption(id: peerId, arg: 'touch-mode') != '';
_touchMode = await bind.sessionGetOption(
sessionId: sessionId, arg: 'touch-mode') !=
'';
}
if (connType == ConnType.fileTransfer) {
@@ -476,7 +485,7 @@ class FfiModel with ChangeNotifier {
stateGlobal.displaysCount.value = _pi.displays.length;
if (_pi.currentDisplay < _pi.displays.length) {
_display = _pi.displays[_pi.currentDisplay];
_updateSessionWidthHeight(peerId);
_updateSessionWidthHeight(sessionId);
}
if (displays.isNotEmpty) {
parent.target?.dialogManager.showLoading(
@@ -491,8 +500,10 @@ class FfiModel with ChangeNotifier {
parent.target?.elevationModel.onPeerInfo(_pi);
}
if (connType == ConnType.defaultConn) {
setViewOnly(peerId,
bind.sessionGetToggleOptionSync(id: peerId, arg: 'view-only'));
setViewOnly(
peerId,
bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: 'view-only'));
}
if (connType == ConnType.defaultConn) {
final platform_additions = evt['platform_additions'];
@@ -547,7 +558,7 @@ class FfiModel with ChangeNotifier {
}
/// Handle the peer info synchronization event based on [evt].
handleSyncPeerInfo(Map<String, dynamic> evt, String peerId) async {
handleSyncPeerInfo(Map<String, dynamic> evt, SessionID sessionId) async {
if (evt['displays'] != null) {
List<dynamic> displays = json.decode(evt['displays']);
List<Display> newDisplays = [];
@@ -557,7 +568,7 @@ class FfiModel with ChangeNotifier {
_pi.displays = newDisplays;
stateGlobal.displaysCount.value = _pi.displays.length;
if (_pi.currentDisplay >= 0 && _pi.currentDisplay < _pi.displays.length) {
_updateCurDisplay(peerId, _pi.displays[_pi.currentDisplay]);
_updateCurDisplay(sessionId, _pi.displays[_pi.currentDisplay]);
}
}
notifyListeners();
@@ -573,11 +584,12 @@ class FfiModel with ChangeNotifier {
}
}
updatePrivacyMode(Map<String, dynamic> evt, String peerId) {
updatePrivacyMode(
Map<String, dynamic> evt, SessionID sessionId, String peerId) {
notifyListeners();
try {
PrivacyModeState.find(peerId).value =
bind.sessionGetToggleOptionSync(id: peerId, arg: 'privacy-mode');
PrivacyModeState.find(peerId).value = bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: 'privacy-mode');
} catch (e) {
//
}
@@ -592,8 +604,8 @@ class FfiModel with ChangeNotifier {
if (value) {
ShowRemoteCursorState.find(id).value = value;
} else {
ShowRemoteCursorState.find(id).value =
bind.sessionGetToggleOptionSync(id: id, arg: 'show-remote-cursor');
ShowRemoteCursorState.find(id).value = bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: 'show-remote-cursor');
}
} catch (e) {
//
@@ -612,11 +624,15 @@ class ImageModel with ChangeNotifier {
String id = '';
late final SessionID sessionId;
WeakReference<FFI> parent;
final List<Function(String)> callbacksOnFirstImage = [];
ImageModel(this.parent);
ImageModel(this.parent) {
sessionId = parent.target!.sessionId;
}
addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb);
@@ -645,7 +661,7 @@ class ImageModel with ChangeNotifier {
isWeb ? ui.PixelFormat.rgba8888 : ui.PixelFormat.bgra8888,
onPixelsCopied: () {
// Unlock the rgba memory from rust codes.
platformFFI.nextRgba(id);
platformFFI.nextRgba(sessionId);
}).then((image) {
if (parent.target?.id != pid) return;
try {
@@ -674,7 +690,7 @@ class ImageModel with ChangeNotifier {
await initializeCursorAndCanvas(parent.target!);
}
if (parent.target?.ffiModel.isPeerAndroid ?? false) {
bind.sessionSetViewStyle(id: id, value: 'adaptive');
bind.sessionSetViewStyle(sessionId: sessionId, value: 'adaptive');
parent.target?.canvasModel.updateViewStyle();
}
}
@@ -793,6 +809,7 @@ class CanvasModel with ChangeNotifier {
// double windowBorderWidth = 0.0;
// remote id
String id = '';
late final SessionID sessionId;
// scroll offset x percent
double _scrollX = 0.0;
// scroll offset y percent
@@ -804,7 +821,9 @@ class CanvasModel with ChangeNotifier {
WeakReference<FFI> parent;
CanvasModel(this.parent);
CanvasModel(this.parent) {
sessionId = parent.target!.sessionId;
}
double get x => _x;
double get y => _y;
@@ -847,7 +866,7 @@ class CanvasModel with ChangeNotifier {
return Size(w < 0 ? 0 : w, h < 0 ? 0 : h);
}
final style = await bind.sessionGetViewStyle(id: id);
final style = await bind.sessionGetViewStyle(sessionId: sessionId);
if (style == null) {
return;
}
@@ -883,7 +902,7 @@ class CanvasModel with ChangeNotifier {
}
updateScrollStyle() async {
final style = await bind.sessionGetScrollStyle(id: id);
final style = await bind.sessionGetScrollStyle(sessionId: sessionId);
if (style == kRemoteScrollStyleBar) {
_scrollStyle = ScrollStyle.scrollbar;
_resetScroll();
@@ -1358,8 +1377,8 @@ class CursorModel with ChangeNotifier {
Future<bool> _updateCache(
Uint8List rgba, ui.Image image, int id, int w, int h) async {
Uint8List? data;
img2.Image imgOrigin =
img2.Image.fromBytes(width: w, height:h, bytes: rgba.buffer, order: img2.ChannelOrder.rgba);
img2.Image imgOrigin = img2.Image.fromBytes(
width: w, height: h, bytes: rgba.buffer, order: img2.ChannelOrder.rgba);
if (Platform.isWindows) {
data = imgOrigin.getBytes(order: img2.ChannelOrder.bgra);
} else {
@@ -1474,9 +1493,9 @@ class QualityMonitorModel with ChangeNotifier {
bool get show => _show;
QualityMonitorData get data => _data;
checkShowQualityMonitor(String id) async {
checkShowQualityMonitor(SessionID sessionId) async {
final show = await bind.sessionGetToggleOption(
id: id, arg: 'show-quality-monitor') ==
sessionId: sessionId, arg: 'show-quality-monitor') ==
true;
if (_show != show) {
_show = show;
@@ -1510,32 +1529,35 @@ class RecordingModel with ChangeNotifier {
onSwitchDisplay() {
if (isIOS || !_start) return;
var id = parent.target?.id;
final sessionId = parent.target?.sessionId;
int? width = parent.target?.canvasModel.getDisplayWidth();
int? height = parent.target?.canvasModel.getDisplayHeight();
if (id == null || width == null || height == null) return;
bind.sessionRecordScreen(id: id, start: true, width: width, height: height);
if (sessionId == null || width == null || height == null) return;
bind.sessionRecordScreen(
sessionId: sessionId, start: true, width: width, height: height);
}
toggle() {
if (isIOS) return;
var id = parent.target?.id;
if (id == null) return;
final sessionId = parent.target?.sessionId;
if (sessionId == null) return;
_start = !_start;
notifyListeners();
if (_start) {
bind.sessionRefresh(id: id);
bind.sessionRefresh(sessionId: sessionId);
} else {
bind.sessionRecordScreen(id: id, start: false, width: 0, height: 0);
bind.sessionRecordScreen(
sessionId: sessionId, start: false, width: 0, height: 0);
}
}
onClose() {
if (isIOS) return;
var id = parent.target?.id;
if (id == null) return;
final sessionId = parent.target?.sessionId;
if (sessionId == null) return;
_start = false;
bind.sessionRecordScreen(id: id, start: false, width: 0, height: 0);
bind.sessionRecordScreen(
sessionId: sessionId, start: false, width: 0, height: 0);
}
}
@@ -1558,6 +1580,7 @@ enum ConnType { defaultConn, fileTransfer, portForward, rdp }
/// Flutter state manager and data communication with the Rust core.
class FFI {
final sessionId = Uuid().v4obj();
var id = '';
var version = '';
var connType = ConnType.defaultConn;
@@ -1610,10 +1633,8 @@ class FFI {
assert(!(isFileTransfer && isPortForward), 'more than one connect type');
if (isFileTransfer) {
connType = ConnType.fileTransfer;
id = 'ft_$id';
} else if (isPortForward) {
connType = ConnType.portForward;
id = 'pf_$id';
} else {
chatModel.resetClientMode();
connType = ConnType.defaultConn;
@@ -1623,6 +1644,7 @@ class FFI {
}
// ignore: unused_local_variable
final addRes = bind.sessionAddSync(
sessionId: sessionId,
id: id,
isFileTransfer: isFileTransfer,
isPortForward: isPortForward,
@@ -1631,8 +1653,8 @@ class FFI {
forceRelay: forceRelay ?? false,
password: password ?? "",
);
final stream = bind.sessionStart(id: id);
final cb = ffiModel.startEventListener(id);
final stream = bind.sessionStart(sessionId: sessionId, id: id);
final cb = ffiModel.startEventListener(sessionId, id);
() async {
final useTextureRender = bind.mainUseTextureRender();
// Preserved for the rgba data.
@@ -1664,11 +1686,11 @@ class FFI {
}
} else {
// Fetch the image buffer from rust codes.
final sz = platformFFI.getRgbaSize(id);
final sz = platformFFI.getRgbaSize(sessionId);
if (sz == null || sz == 0) {
return;
}
final rgba = platformFFI.getRgba(id, sz);
final rgba = platformFFI.getRgba(sessionId, sz);
if (rgba != null) {
imageModel.onRgba(rgba);
}
@@ -1682,10 +1704,10 @@ class FFI {
}
/// Login with [password], choose if the client should [remember] it.
void login(String osUsername, String osPassword, String id, String password,
bool remember) {
void login(String osUsername, String osPassword, SessionID sessionId,
String password, bool remember) {
bind.sessionLogin(
id: id,
sessionId: sessionId,
osUsername: osUsername,
osPassword: osPassword,
password: password,
@@ -1696,15 +1718,21 @@ class FFI {
Future<void> close() async {
chatModel.close();
if (imageModel.image != null && !isWebDesktop) {
await setCanvasConfig(id, cursorModel.x, cursorModel.y, canvasModel.x,
canvasModel.y, canvasModel.scale, ffiModel.pi.currentDisplay);
await setCanvasConfig(
sessionId,
cursorModel.x,
cursorModel.y,
canvasModel.x,
canvasModel.y,
canvasModel.scale,
ffiModel.pi.currentDisplay);
}
imageModel.update(null);
cursorModel.clear();
ffiModel.clear();
canvasModel.clear();
inputModel.resetModifiers();
await bind.sessionClose(id: id);
await bind.sessionClose(sessionId: sessionId);
debugPrint('model $id closed');
id = '';
}
@@ -1795,8 +1823,14 @@ class PeerInfo {
const canvasKey = 'canvas';
Future<void> setCanvasConfig(String id, double xCursor, double yCursor,
double xCanvas, double yCanvas, double scale, int currentDisplay) async {
Future<void> setCanvasConfig(
SessionID sessionId,
double xCursor,
double yCursor,
double xCanvas,
double yCanvas,
double scale,
int currentDisplay) async {
final p = <String, dynamic>{};
p['xCursor'] = xCursor;
p['yCursor'] = yCursor;
@@ -1804,12 +1838,14 @@ Future<void> setCanvasConfig(String id, double xCursor, double yCursor,
p['yCanvas'] = yCanvas;
p['scale'] = scale;
p['currentDisplay'] = currentDisplay;
await bind.sessionSetFlutterConfig(id: id, k: canvasKey, v: jsonEncode(p));
await bind.sessionSetFlutterConfig(
sessionId: sessionId, k: canvasKey, v: jsonEncode(p));
}
Future<Map<String, dynamic>?> getCanvasConfig(String id) async {
Future<Map<String, dynamic>?> getCanvasConfig(SessionID sessionId) async {
if (!isWebDesktop) return null;
var p = await bind.sessionGetFlutterConfig(id: id, k: canvasKey);
var p =
await bind.sessionGetFlutterConfig(sessionId: sessionId, k: canvasKey);
if (p == null || p.isEmpty) return null;
try {
Map<String, dynamic> m = json.decode(p);
@@ -1819,12 +1855,8 @@ Future<Map<String, dynamic>?> getCanvasConfig(String id) async {
}
}
void removePreference(String id) async {
await bind.sessionSetFlutterConfig(id: id, k: canvasKey, v: '');
}
Future<void> initializeCursorAndCanvas(FFI ffi) async {
var p = await getCanvasConfig(ffi.id);
var p = await getCanvasConfig(ffi.sessionId);
int currentDisplay = 0;
if (p != null) {
currentDisplay = p['currentDisplay'];

View File

@@ -104,9 +104,10 @@ class PlatformFFI {
return res;
}
Uint8List? getRgba(String id, int bufSize) {
Uint8List? getRgba(SessionID sessionId, int bufSize) {
if (_session_get_rgba == null) return null;
var a = id.toNativeUtf8();
final sessionIdStr = sessionId.toString();
var a = sessionIdStr.toNativeUtf8();
try {
final buffer = _session_get_rgba!(a);
if (buffer == nullptr) {
@@ -119,24 +120,27 @@ class PlatformFFI {
}
}
int? getRgbaSize(String id) {
int? getRgbaSize(SessionID sessionId) {
if (_session_get_rgba_size == null) return null;
var a = id.toNativeUtf8();
final sessionIdStr = sessionId.toString();
var a = sessionIdStr.toNativeUtf8();
final bufferSize = _session_get_rgba_size!(a);
malloc.free(a);
return bufferSize;
}
void nextRgba(String id) {
void nextRgba(SessionID sessionId) {
if (_session_next_rgba == null) return;
final a = id.toNativeUtf8();
final sessionIdStr = sessionId.toString();
final a = sessionIdStr.toNativeUtf8();
_session_next_rgba!(a);
malloc.free(a);
}
void registerTexture(String id, int ptr) {
void registerTexture(SessionID sessionId, int ptr) {
if (_session_register_texture == null) return;
final a = id.toNativeUtf8();
final sessionIdStr = sessionId.toString();
final a = sessionIdStr.toNativeUtf8();
_session_register_texture!(a, ptr);
malloc.free(a);
}

View File

@@ -343,7 +343,7 @@ class ServerModel with ChangeNotifier {
Future<void> startService() async {
_isStart = true;
notifyListeners();
parent.target?.ffiModel.updateEventListener("");
parent.target?.ffiModel.updateEventListener(parent.target!.sessionId, "");
await parent.target?.invokeMethod("init_service");
// ugly is here, because for desktop, below is useless
await bind.mainStartService();

View File

@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
void handlePluginEvent(
Map<String, dynamic> evt,
String peer,
Function(Map<String, dynamic> e) handleMsgBox,
) {
Map<String, dynamic>? content;

View File

@@ -275,7 +275,7 @@ class PluginItem extends StatelessWidget {
}
}
void handleReloading(Map<String, dynamic> evt, String peer) {
void handleReloading(Map<String, dynamic> evt) {
if (evt['id'] == null || evt['location'] == null) {
return;
}
@@ -295,7 +295,7 @@ void handleReloading(Map<String, dynamic> evt, String peer) {
}
}
void handleOption(Map<String, dynamic> evt, String peer) {
void handleOption(Map<String, dynamic> evt) {
updateOption(
evt['location'], evt['id'], evt['peer'] ?? '', evt['key'], evt['value']);
}

View File

@@ -1331,7 +1331,7 @@ packages:
source: hosted
version: "3.0.3"
uuid:
dependency: transitive
dependency: "direct main"
description:
name: uuid
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"

View File

@@ -95,6 +95,7 @@ dependencies:
texture_rgba_renderer: ^0.0.16
percent_indicator: ^4.2.2
dropdown_button2: ^2.0.0
uuid: ^3.0.7
dev_dependencies:
icons_launcher: ^2.0.4