Skip to content

Commit

Permalink
Merge branch 'rustdesk:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangbo8418 authored Oct 21, 2024
2 parents e790a3f + e818758 commit 172be4e
Show file tree
Hide file tree
Showing 65 changed files with 447 additions and 327 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions flutter/lib/consts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const String kOptionAllowAutoDisconnect = "allow-auto-disconnect";
const String kOptionAutoDisconnectTimeout = "auto-disconnect-timeout";
const String kOptionEnableHwcodec = "enable-hwcodec";
const String kOptionAllowAutoRecordIncoming = "allow-auto-record-incoming";
const String kOptionAllowAutoRecordOutgoing = "allow-auto-record-outgoing";
const String kOptionVideoSaveDirectory = "video-save-directory";
const String kOptionAccessMode = "access-mode";
const String kOptionEnableKeyboard = "enable-keyboard";
Expand Down
93 changes: 51 additions & 42 deletions flutter/lib/desktop/pages/desktop_setting_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -575,12 +575,17 @@ class _GeneralState extends State<_General> {
bool root_dir_exists = map['root_dir_exists']!;
bool user_dir_exists = map['user_dir_exists']!;
return _Card(title: 'Recording', children: [
_OptionCheckBox(context, 'Automatically record incoming sessions',
kOptionAllowAutoRecordIncoming),
if (showRootDir)
if (!bind.isOutgoingOnly())
_OptionCheckBox(context, 'Automatically record incoming sessions',
kOptionAllowAutoRecordIncoming),
if (!bind.isIncomingOnly())
_OptionCheckBox(context, 'Automatically record outgoing sessions',
kOptionAllowAutoRecordOutgoing),
if (showRootDir && !bind.isOutgoingOnly())
Row(
children: [
Text('${translate("Incoming")}:'),
Text(
'${translate(bind.isIncomingOnly() ? "Directory" : "Incoming")}:'),
Expanded(
child: GestureDetector(
onTap: root_dir_exists
Expand All @@ -597,45 +602,49 @@ class _GeneralState extends State<_General> {
),
],
).marginOnly(left: _kContentHMargin),
Row(
children: [
Text('${translate(showRootDir ? "Outgoing" : "Directory")}:'),
Expanded(
child: GestureDetector(
onTap: user_dir_exists
? () => launchUrl(Uri.file(user_dir))
: null,
child: Text(
user_dir,
softWrap: true,
style: user_dir_exists
? const TextStyle(decoration: TextDecoration.underline)
if (!(showRootDir && bind.isIncomingOnly()))
Row(
children: [
Text(
'${translate((showRootDir && !bind.isOutgoingOnly()) ? "Outgoing" : "Directory")}:'),
Expanded(
child: GestureDetector(
onTap: user_dir_exists
? () => launchUrl(Uri.file(user_dir))
: null,
)).marginOnly(left: 10),
),
ElevatedButton(
onPressed: isOptionFixed(kOptionVideoSaveDirectory)
? null
: () async {
String? initialDirectory;
if (await Directory.fromUri(Uri.directory(user_dir))
.exists()) {
initialDirectory = user_dir;
}
String? selectedDirectory =
await FilePicker.platform.getDirectoryPath(
initialDirectory: initialDirectory);
if (selectedDirectory != null) {
await bind.mainSetOption(
key: kOptionVideoSaveDirectory,
value: selectedDirectory);
setState(() {});
}
},
child: Text(translate('Change')))
.marginOnly(left: 5),
],
).marginOnly(left: _kContentHMargin),
child: Text(
user_dir,
softWrap: true,
style: user_dir_exists
? const TextStyle(
decoration: TextDecoration.underline)
: null,
)).marginOnly(left: 10),
),
ElevatedButton(
onPressed: isOptionFixed(kOptionVideoSaveDirectory)
? null
: () async {
String? initialDirectory;
if (await Directory.fromUri(
Uri.directory(user_dir))
.exists()) {
initialDirectory = user_dir;
}
String? selectedDirectory =
await FilePicker.platform.getDirectoryPath(
initialDirectory: initialDirectory);
if (selectedDirectory != null) {
await bind.mainSetOption(
key: kOptionVideoSaveDirectory,
value: selectedDirectory);
setState(() {});
}
},
child: Text(translate('Change')))
.marginOnly(left: 5),
],
).marginOnly(left: _kContentHMargin),
]);
});
}
Expand Down
3 changes: 2 additions & 1 deletion flutter/lib/desktop/pages/remote_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ class _RemotePageState extends State<RemotePage>
_ffi.imageModel.addCallbackOnFirstImage((String peerId) {
showKBLayoutTypeChooserIfNeeded(
_ffi.ffiModel.pi.platform, _ffi.dialogManager);
_ffi.recordingModel
.updateStatus(bind.sessionGetIsRecording(sessionId: _ffi.sessionId));
});
_ffi.start(
widget.id,
Expand Down Expand Up @@ -253,7 +255,6 @@ class _RemotePageState extends State<RemotePage>
_ffi.dialogManager.hideMobileActionsOverlay();
_ffi.imageModel.disposeImage();
_ffi.cursorModel.disposeImages();
_ffi.recordingModel.onClose();
_rawKeyFocusNode.dispose();
await _ffi.close(closeSession: closeSession);
_timer?.cancel();
Expand Down
3 changes: 1 addition & 2 deletions flutter/lib/desktop/widgets/remote_toolbar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1924,8 +1924,7 @@ class _RecordMenu extends StatelessWidget {
var ffi = Provider.of<FfiModel>(context);
var recordingModel = Provider.of<RecordingModel>(context);
final visible =
(recordingModel.start || ffi.permissions['recording'] != false) &&
ffi.pi.currentDisplay != kAllDisplayValue;
(recordingModel.start || ffi.permissions['recording'] != false);
if (!visible) return Offstage();
return _IconMenuButton(
assetName: 'assets/rec.svg',
Expand Down
9 changes: 8 additions & 1 deletion flutter/lib/mobile/pages/remote_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ class _RemotePageState extends State<RemotePage> {
gFFI.chatModel
.changeCurrentKey(MessageKey(widget.id, ChatModel.clientModeID));
_blockableOverlayState.applyFfi(gFFI);
gFFI.imageModel.addCallbackOnFirstImage((String peerId) {
gFFI.recordingModel
.updateStatus(bind.sessionGetIsRecording(sessionId: gFFI.sessionId));
if (gFFI.recordingModel.start) {
showToast(translate('Automatically record outgoing sessions'));
}
});
}

@override
Expand Down Expand Up @@ -207,7 +214,7 @@ class _RemotePageState extends State<RemotePage> {
}

void _handleNonIOSSoftKeyboardInput(String newValue) {
_composingTimer?.cancel();
_composingTimer?.cancel();
if (_textController.value.isComposingRangeValid) {
_composingTimer = Timer(Duration(milliseconds: 25), () {
_handleNonIOSSoftKeyboardInput(_textController.value.text);
Expand Down
73 changes: 50 additions & 23 deletions flutter/lib/mobile/pages/settings_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
var _enableRecordSession = false;
var _enableHardwareCodec = false;
var _autoRecordIncomingSession = false;
var _autoRecordOutgoingSession = false;
var _allowAutoDisconnect = false;
var _localIP = "";
var _directAccessPort = "";
Expand All @@ -104,6 +105,8 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
bind.mainGetOptionSync(key: kOptionEnableHwcodec));
_autoRecordIncomingSession = option2bool(kOptionAllowAutoRecordIncoming,
bind.mainGetOptionSync(key: kOptionAllowAutoRecordIncoming));
_autoRecordOutgoingSession = option2bool(kOptionAllowAutoRecordOutgoing,
bind.mainGetOptionSync(key: kOptionAllowAutoRecordOutgoing));
_localIP = bind.mainGetOptionSync(key: 'local-ip-addr');
_directAccessPort = bind.mainGetOptionSync(key: kOptionDirectAccessPort);
_allowAutoDisconnect = option2bool(kOptionAllowAutoDisconnect,
Expand Down Expand Up @@ -231,6 +234,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
Widget build(BuildContext context) {
Provider.of<FfiModel>(context);
final outgoingOnly = bind.isOutgoingOnly();
final incommingOnly = bind.isIncomingOnly();
final customClientSection = CustomSettingsSection(
child: Column(
children: [
Expand Down Expand Up @@ -674,32 +678,55 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
},
),
]),
if (isAndroid && !outgoingOnly)
if (isAndroid)
SettingsSection(
title: Text(translate("Recording")),
tiles: [
SettingsTile.switchTile(
title:
Text(translate('Automatically record incoming sessions')),
leading: Icon(Icons.videocam),
description: Text(
"${translate("Directory")}: ${bind.mainVideoSaveDirectory(root: false)}"),
initialValue: _autoRecordIncomingSession,
onToggle: isOptionFixed(kOptionAllowAutoRecordIncoming)
? null
: (v) async {
await bind.mainSetOption(
key: kOptionAllowAutoRecordIncoming,
value:
bool2option(kOptionAllowAutoRecordIncoming, v));
final newValue = option2bool(
kOptionAllowAutoRecordIncoming,
await bind.mainGetOption(
key: kOptionAllowAutoRecordIncoming));
setState(() {
_autoRecordIncomingSession = newValue;
});
},
if (!outgoingOnly)
SettingsTile.switchTile(
title:
Text(translate('Automatically record incoming sessions')),
initialValue: _autoRecordIncomingSession,
onToggle: isOptionFixed(kOptionAllowAutoRecordIncoming)
? null
: (v) async {
await bind.mainSetOption(
key: kOptionAllowAutoRecordIncoming,
value: bool2option(
kOptionAllowAutoRecordIncoming, v));
final newValue = option2bool(
kOptionAllowAutoRecordIncoming,
await bind.mainGetOption(
key: kOptionAllowAutoRecordIncoming));
setState(() {
_autoRecordIncomingSession = newValue;
});
},
),
if (!incommingOnly)
SettingsTile.switchTile(
title:
Text(translate('Automatically record outgoing sessions')),
initialValue: _autoRecordOutgoingSession,
onToggle: isOptionFixed(kOptionAllowAutoRecordOutgoing)
? null
: (v) async {
await bind.mainSetOption(
key: kOptionAllowAutoRecordOutgoing,
value: bool2option(
kOptionAllowAutoRecordOutgoing, v));
final newValue = option2bool(
kOptionAllowAutoRecordOutgoing,
await bind.mainGetOption(
key: kOptionAllowAutoRecordOutgoing));
setState(() {
_autoRecordOutgoingSession = newValue;
});
},
),
SettingsTile(
title: Text(translate("Directory")),
description: Text(bind.mainVideoSaveDirectory(root: false)),
),
],
),
Expand Down
73 changes: 12 additions & 61 deletions flutter/lib/models/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,10 @@ class FfiModel with ChangeNotifier {
if (isWeb) {
parent.target?.fileModel.onSelectedFiles(evt);
}
} else if (name == "record_status") {
if (desktopType == DesktopType.remote || isMobile) {
parent.target?.recordingModel.updateStatus(evt['start'] == 'true');
}
} else {
debugPrint('Event is not handled in the fixed branch: $name');
}
Expand Down Expand Up @@ -527,7 +531,6 @@ class FfiModel with ChangeNotifier {
}
}

parent.target?.recordingModel.onSwitchDisplay();
if (!_pi.isSupportMultiUiSession || _pi.currentDisplay == display) {
handleResolutions(peerId, evt['resolutions']);
}
Expand Down Expand Up @@ -1135,8 +1138,6 @@ class FfiModel with ChangeNotifier {
// Directly switch to the new display without waiting for the response.
switchToNewDisplay(int display, SessionID sessionId, String peerId,
{bool updateCursorPos = false}) {
// VideoHandler creation is upon when video frames are received, so either caching commands(don't know next width/height) or stopping recording when switching displays.
parent.target?.recordingModel.onClose();
// no need to wait for the response
pi.currentDisplay = display;
updateCurDisplay(sessionId, updateCursorPos: updateCursorPos);
Expand Down Expand Up @@ -2342,74 +2343,24 @@ class RecordingModel with ChangeNotifier {
WeakReference<FFI> parent;
RecordingModel(this.parent);
bool _start = false;
get start => _start;

onSwitchDisplay() {
if (isIOS || !_start) return;
final sessionId = parent.target?.sessionId;
int? width = parent.target?.canvasModel.getDisplayWidth();
int? height = parent.target?.canvasModel.getDisplayHeight();
if (sessionId == null || width == null || height == null) return;
final pi = parent.target?.ffiModel.pi;
if (pi == null) return;
final currentDisplay = pi.currentDisplay;
if (currentDisplay == kAllDisplayValue) return;
bind.sessionRecordScreen(
sessionId: sessionId,
start: true,
display: currentDisplay,
width: width,
height: height);
}
bool get start => _start;

toggle() async {
if (isIOS) return;
final sessionId = parent.target?.sessionId;
if (sessionId == null) return;
final pi = parent.target?.ffiModel.pi;
if (pi == null) return;
final currentDisplay = pi.currentDisplay;
if (currentDisplay == kAllDisplayValue) return;
_start = !_start;
notifyListeners();
await _sendStatusMessage(sessionId, pi, _start);
if (_start) {
sessionRefreshVideo(sessionId, pi);
if (versionCmp(pi.version, '1.2.4') >= 0) {
// will not receive SwitchDisplay since 1.2.4
onSwitchDisplay();
}
} else {
bind.sessionRecordScreen(
sessionId: sessionId,
start: false,
display: currentDisplay,
width: 0,
height: 0);
bool value = !_start;
if (value) {
await sessionRefreshVideo(sessionId, pi);
}
await bind.sessionRecordScreen(sessionId: sessionId, start: value);
}

onClose() async {
if (isIOS) return;
final sessionId = parent.target?.sessionId;
if (sessionId == null) return;
if (!_start) return;
_start = false;
final pi = parent.target?.ffiModel.pi;
if (pi == null) return;
final currentDisplay = pi.currentDisplay;
if (currentDisplay == kAllDisplayValue) return;
await _sendStatusMessage(sessionId, pi, false);
bind.sessionRecordScreen(
sessionId: sessionId,
start: false,
display: currentDisplay,
width: 0,
height: 0);
}

_sendStatusMessage(SessionID sessionId, PeerInfo pi, bool status) async {
await bind.sessionRecordStatus(sessionId: sessionId, status: status);
updateStatus(bool status) {
_start = status;
notifyListeners();
}
}

Expand Down
Loading

0 comments on commit 172be4e

Please sign in to comment.