Merge remote-tracking branch 'upstream/master' into fix/mobile-scale-custom-pr

This commit is contained in:
Alessandro De Blasis
2025-10-29 09:48:13 +01:00
19 changed files with 497 additions and 223 deletions

View File

@@ -2121,15 +2121,20 @@ void showWindowsSessionsDialog(
return CustomAlertDialog(
title: null,
content: msgboxContent(type, title, text),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
msgboxContent(type, title, text).marginOnly(bottom: 12),
ComboBox(
keys: sids,
values: names,
initialKey: selectedUserValue,
onChanged: (value) {
selectedUserValue = value;
}),
],
),
actions: [
ComboBox(
keys: sids,
values: names,
initialKey: selectedUserValue,
onChanged: (value) {
selectedUserValue = value;
}),
dialogButton('Connect', onPressed: submit, isOutline: false),
],
);

View File

@@ -364,11 +364,12 @@ Future<List<TRadioMenu<String>>> toolbarViewStyle(
value: kRemoteViewStyleAdaptive,
groupValue: groupValue,
onChanged: onChanged),
TRadioMenu<String>(
child: Text(translate('Scale custom')),
value: kRemoteViewStyleCustom,
groupValue: groupValue,
onChanged: onChanged)
if (isDesktop || isWebDesktop)
TRadioMenu<String>(
child: Text(translate('Scale custom')),
value: kRemoteViewStyleCustom,
groupValue: groupValue,
onChanged: onChanged)
];
}

View File

@@ -61,9 +61,11 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
String? connToken,
}) {
final tabKey = '${peerId}_$terminalId';
final alias = bind.mainGetPeerOptionSync(id: peerId, key: 'alias');
final tabLabel = alias.isNotEmpty ? '$alias #$terminalId' : '$peerId #$terminalId';
return TabInfo(
key: tabKey,
label: '$peerId #$terminalId',
label: tabLabel,
selectedIcon: selectedIcon,
unselectedIcon: unselectedIcon,
onTabCloseButton: () async {

View File

@@ -153,135 +153,6 @@ class _ToolbarTheme {
typedef DismissFunc = void Function();
class RemoteMenuEntry {
static MenuEntryRadios<String> viewStyle(
String remoteId,
FFI ffi,
EdgeInsets padding, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
RxString? rxViewStyle,
}) {
return MenuEntryRadios<String>(
text: translate('Ratio'),
optionsGetter: () => [
MenuEntryRadioOption(
text: translate('Scale original'),
value: kRemoteViewStyleOriginal,
dismissOnClicked: true,
dismissCallback: dismissCallback,
),
MenuEntryRadioOption(
text: translate('Scale adaptive'),
value: kRemoteViewStyleAdaptive,
dismissOnClicked: true,
dismissCallback: dismissCallback,
),
MenuEntryRadioOption(
text: translate('Scale custom'),
value: kRemoteViewStyleCustom,
dismissOnClicked: true,
dismissCallback: dismissCallback,
),
],
curOptionGetter: () async {
// null means peer id is not found, which there's no need to care about
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(
sessionId: ffi.sessionId, value: newValue);
if (rxViewStyle != null) {
rxViewStyle.value = newValue;
}
ffi.canvasModel.updateViewStyle();
if (dismissFunc != null) {
dismissFunc();
}
},
padding: padding,
dismissOnClicked: true,
dismissCallback: dismissCallback,
);
}
static MenuEntrySwitch2<String> showRemoteCursor(
String remoteId,
SessionID sessionId,
EdgeInsets padding, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
}) {
final state = ShowRemoteCursorState.find(remoteId);
final optKey = 'show-remote-cursor';
return MenuEntrySwitch2<String>(
switchType: SwitchType.scheckbox,
text: translate('Show remote cursor'),
getter: () {
return state;
},
setter: (bool v) async {
await bind.sessionToggleOption(sessionId: sessionId, value: optKey);
state.value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: optKey);
if (dismissFunc != null) {
dismissFunc();
}
},
padding: padding,
dismissOnClicked: true,
dismissCallback: dismissCallback,
);
}
static MenuEntrySwitch<String> disableClipboard(
SessionID sessionId,
EdgeInsets? padding, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
}) {
return createSwitchMenuEntry(
sessionId,
'Disable clipboard',
'disable-clipboard',
padding,
true,
dismissCallback: dismissCallback,
);
}
static MenuEntrySwitch<String> createSwitchMenuEntry(
SessionID sessionId,
String text,
String option,
EdgeInsets? padding,
bool dismissOnClicked, {
DismissFunc? dismissFunc,
DismissCallback? dismissCallback,
}) {
return MenuEntrySwitch<String>(
switchType: SwitchType.scheckbox,
text: translate(text),
getter: () async {
return bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: option);
},
setter: (bool v) async {
await bind.sessionToggleOption(sessionId: sessionId, value: option);
if (dismissFunc != null) {
dismissFunc();
}
},
padding: padding,
dismissOnClicked: dismissOnClicked,
dismissCallback: dismissCallback,
);
}
static MenuEntryButton<String> insertLock(
SessionID sessionId,
EdgeInsets? padding, {

View File

@@ -92,6 +92,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
gFFI.dialogManager.dismissAll();
WakelockPlus.disable();
});
model.jobController.clear();
super.dispose();
}

View File

@@ -1033,30 +1033,54 @@ class JobController {
await bind.sessionCancelJob(sessionId: sessionId, actId: id);
}
void loadLastJob(Map<String, dynamic> evt) {
Future<void> loadLastJob(Map<String, dynamic> evt) async {
debugPrint("load last job: $evt");
Map<String, dynamic> jobDetail = json.decode(evt['value']);
// int id = int.parse(jobDetail['id']);
String remote = jobDetail['remote'];
String to = jobDetail['to'];
bool showHidden = jobDetail['show_hidden'];
int fileNum = jobDetail['file_num'];
bool isRemote = jobDetail['is_remote'];
final currJobId = JobController.jobID.next();
String fileName = path.basename(isRemote ? remote : to);
var jobProgress = JobProgress()
..type = JobType.transfer
..fileName = fileName
..jobName = isRemote ? remote : to
..id = currJobId
..isRemoteToLocal = isRemote
..fileNum = fileNum
..remote = remote
..to = to
..showHidden = showHidden
..state = JobState.paused;
jobTable.add(jobProgress);
bind.sessionAddJob(
bool isAutoStart = jobDetail['auto_start'] == true;
int currJobId = -1;
if (isAutoStart) {
// Ensure jobDetail['id'] exists and is an int
if (jobDetail.containsKey('id') &&
jobDetail['id'] != null &&
jobDetail['id'] is int) {
currJobId = jobDetail['id'];
}
}
if (currJobId < 0) {
// If id is missing or invalid, disable auto-start and assign a new job id
isAutoStart = false;
currJobId = JobController.jobID.next();
}
if (!isAutoStart) {
if (!(isDesktop || isWebDesktop)) {
// Don't add to job table if not auto start on mobile.
// Because mobile does not support job list view now.
return;
}
// Add to job table if not auto start on desktop.
String fileName = path.basename(isRemote ? remote : to);
final jobProgress = JobProgress()
..type = JobType.transfer
..fileName = fileName
..jobName = isRemote ? remote : to
..id = currJobId
..isRemoteToLocal = isRemote
..fileNum = fileNum
..remote = remote
..to = to
..showHidden = showHidden
..state = JobState.paused;
jobTable.add(jobProgress);
}
await bind.sessionAddJob(
sessionId: sessionId,
isRemote: isRemote,
includeHidden: showHidden,
@@ -1065,6 +1089,11 @@ class JobController {
to: isRemote ? to : remote,
fileNum: fileNum,
);
if (isAutoStart) {
await bind.sessionResumeJob(
sessionId: sessionId, actId: currJobId, isRemote: isRemote);
}
}
void resumeJob(int jobId) {
@@ -1095,6 +1124,11 @@ class JobController {
}
debugPrint("update folder files: $info");
}
void clear() {
jobTable.clear();
jobResultListener.clear();
}
}
class JobResultListener<T> {