From e6be1cb02aacdd0138b9bfcdb7c47ef3b0417230 Mon Sep 17 00:00:00 2001 From: csf Date: Mon, 24 Oct 2022 22:30:22 +0900 Subject: [PATCH 1/5] fix android build for flutter 3.0.5 --- flutter/android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/android/build.gradle b/flutter/android/build.gradle index 92c53b7df..f7ab9782c 100644 --- a/flutter/android/build.gradle +++ b/flutter/android/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:7.0.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.14' } From 43429c41d92cc329c7c689fd45b24cf53913be78 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 25 Oct 2022 10:13:31 +0900 Subject: [PATCH 2/5] flutter 3.0.5 --- flutter/pubspec.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index 4692b3019..cfc5976b7 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -119,28 +119,28 @@ packages: name: cached_network_image url: "https://pub.dartlang.org" source: hosted - version: "3.2.2" + version: "3.2.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "1.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.1" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "1.2.0" charcode: dependency: transitive description: @@ -161,7 +161,7 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.1.0" code_builder: dependency: transitive description: @@ -243,8 +243,8 @@ packages: dependency: "direct main" description: path: "." - ref: "318ebd0a70cc5868911591c04f84bf1541f1bf4e" - resolved-ref: "318ebd0a70cc5868911591c04f84bf1541f1bf4e" + ref: "541f05f766c3f72984ff40b70dd3c7d061f2ce61" + resolved-ref: "541f05f766c3f72984ff40b70dd3c7d061f2ce61" url: "https://github.com/Kingtous/rustdesk_desktop_multi_window" source: git version: "0.1.0" @@ -504,7 +504,7 @@ packages: name: icons_launcher url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.4" image: dependency: "direct main" description: @@ -602,7 +602,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.5" + version: "0.1.4" menu_base: dependency: transitive description: @@ -616,7 +616,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.7.0" mime: dependency: transitive description: @@ -693,7 +693,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.8.1" path_drawing: dependency: transitive description: @@ -959,7 +959,7 @@ packages: name: sqflite url: "https://pub.dartlang.org" source: hosted - version: "2.1.0+1" + version: "2.0.3+1" sqflite_common: dependency: transitive description: @@ -1301,7 +1301,7 @@ packages: name: zxing2 url: "https://pub.dartlang.org" source: hosted - version: "0.1.1" + version: "0.1.0" sdks: - dart: ">=2.18.0 <3.0.0" - flutter: ">=3.3.0" + dart: ">=2.17.1 <3.0.0" + flutter: ">=3.0.0" From 46eba4758dc201f5cb12670838dc20a49aa7e222 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 25 Oct 2022 10:14:40 +0900 Subject: [PATCH 3/5] fix mobile file transfer can't send files --- flutter/lib/models/file_model.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index ed52d03ee..4beac01be 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -515,7 +515,7 @@ class FileModel extends ChangeNotifier { items.items.forEach((from) async { _jobId++; await bind.sessionSendFiles( - id: await bind.mainGetLastRemoteId(), + id: '${parent.target?.id}', actId: _jobId, path: from.path, to: PathUtil.join(toPath, from.name, isWindows), From 0c30d34cc2055a560b438a2263f9bf4d92560704 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 25 Oct 2022 10:16:11 +0900 Subject: [PATCH 4/5] add android screen record (incoming session) --- flutter/lib/mobile/pages/settings_page.dart | 57 +++++++++++++++++++++ src/server/video_service.rs | 6 +-- src/ui_cm_interface.rs | 2 +- src/ui_interface.rs | 11 ++++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index c555314d0..7a82bcdd8 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -36,6 +36,8 @@ var _enableAbr = false; var _denyLANDiscovery = false; var _onlyWhiteList = false; var _enableDirectIPAccess = false; +var _enableRecordSession = false; +var _autoRecordIncomingSession = false; var _localIP = ""; var _directAccessPort = ""; @@ -78,6 +80,21 @@ class _SettingsState extends State with WidgetsBindingObserver { _enableDirectIPAccess = enableDirectIPAccess; } + final enableRecordSession = option2bool('enable-record-session', + await bind.mainGetOption(key: 'enable-record-session')); + if (enableRecordSession != _enableRecordSession) { + update = true; + _enableRecordSession = enableRecordSession; + } + + final autoRecordIncomingSession = option2bool( + 'allow-auto-record-incoming', + await bind.mainGetOption(key: 'allow-auto-record-incoming')); + if (autoRecordIncomingSession != _autoRecordIncomingSession) { + update = true; + _autoRecordIncomingSession = autoRecordIncomingSession; + } + final localIP = await bind.mainGetOption(key: 'local-ip-addr'); if (localIP != _localIP) { update = true; @@ -178,6 +195,19 @@ class _SettingsState extends State with WidgetsBindingObserver { }); }, ), + SettingsTile.switchTile( + title: Text(translate('Enable Recording Session')), + initialValue: _enableRecordSession, + onToggle: (v) async { + await bind.mainSetOption( + key: "enable-record-session", value: v ? "" : "N"); + final newValue = + await bind.mainGetOption(key: "enable-record-session") != "N"; + setState(() { + _enableRecordSession = newValue; + }); + }, + ), SettingsTile.switchTile( title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -299,6 +329,33 @@ class _SettingsState extends State with WidgetsBindingObserver { }, ) ]), + SettingsSection( + title: Text(translate("Recording")), + tiles: [ + SettingsTile.switchTile( + title: Text(translate('Automatically record incoming sessions')), + leading: Icon(Icons.videocam), + description: FutureBuilder( + builder: (ctx, data) => Offstage( + offstage: !data.hasData, + child: Text("${translate("Directory")}: ${data.data}")), + future: bind.mainDefaultVideoSaveDirectory()), + initialValue: _autoRecordIncomingSession, + onToggle: (v) async { + await bind.mainSetOption( + key: "allow-auto-record-incoming", + value: bool2option("allow-auto-record-incoming", v)); + final newValue = option2bool( + 'allow-auto-record-incoming', + await bind.mainGetOption( + key: 'allow-auto-record-incoming')); + setState(() { + _autoRecordIncomingSession = newValue; + }); + }, + ), + ], + ), SettingsSection( title: Text(translate("Share Screen")), tiles: shareScreenTiles, diff --git a/src/server/video_service.rs b/src/server/video_service.rs index d43996559..b583a0ae3 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -449,7 +449,7 @@ fn run(sp: GenericService) -> ResultType<()> { #[cfg(windows)] log::info!("gdi: {}", c.is_gdi()); let codec_name = Encoder::current_hw_encoder_name(); - #[cfg(not(any(target_os = "android", target_os = "ios")))] + #[cfg(not(target_os = "ios"))] let recorder = if !Config::get_option("allow-auto-record-incoming").is_empty() { Recorder::new(RecorderContext { id: "local".to_owned(), @@ -463,7 +463,7 @@ fn run(sp: GenericService) -> ResultType<()> { } else { Default::default() }; - #[cfg(any(target_os = "android", target_os = "ios"))] + #[cfg(target_os = "ios")] let recorder: Arc>> = Default::default(); #[cfg(windows)] start_uac_elevation_check(); @@ -674,7 +674,7 @@ fn handle_one_frame( let mut send_conn_ids: HashSet = Default::default(); if let Ok(msg) = encoder.encode_to_message(frame, ms) { - #[cfg(not(any(target_os = "android", target_os = "ios")))] + #[cfg(not(target_os = "ios"))] recorder .lock() .unwrap() diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index bd05f3bce..96fb84b6d 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -413,7 +413,7 @@ pub async fn start_listen( _ => {} } } - cm.remove_connection(current_id); + cm.remove_connection(current_id, true); } async fn handle_fs(fs: ipc::FS, write_jobs: &mut Vec, tx: &UnboundedSender) { diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 9ef512fd7..142c9cb43 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -733,11 +733,21 @@ pub fn get_langs() -> String { #[inline] pub fn default_video_save_directory() -> String { let appname = crate::get_app_name(); + + #[cfg(any(target_os = "android", target_os = "ios"))] + if let Ok(home) = config::APP_HOME_DIR.read() { + let mut path = home.to_owned(); + path.push_str("/RustDesk/ScreenRecord"); + return path; + } + if let Some(user) = directories_next::UserDirs::new() { if let Some(video_dir) = user.video_dir() { return video_dir.join(appname).to_string_lossy().to_string(); } } + + #[cfg(not(any(target_os = "android", target_os = "ios")))] if let Some(home) = platform::get_active_user_home() { let name = if cfg!(target_os = "macos") { "Movies" @@ -746,6 +756,7 @@ pub fn default_video_save_directory() -> String { }; return home.join(name).join(appname).to_string_lossy().to_string(); } + if let Ok(exe) = std::env::current_exe() { if let Some(dir) = exe.parent() { return dir.join("videos").to_string_lossy().to_string(); From bf4ed4b727092525ddc921e3b6c985fd566b7479 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 25 Oct 2022 11:27:34 +0900 Subject: [PATCH 5/5] fix RecordingModel get size & add mobile screen record (remote) --- flutter/lib/mobile/pages/remote_page.dart | 26 ++++++++++++++++++++++- flutter/lib/models/model.dart | 11 +++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index c5775236a..0662fce2b 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -582,13 +582,35 @@ class _RemotePageState extends State { value: 'block-input')); } } - if (gFFI.ffiModel.permissions["restart"] != false && + if (perms["restart"] != false && (pi.platform == "Linux" || pi.platform == "Windows" || pi.platform == "Mac OS")) { more.add(PopupMenuItem( child: Text(translate('Restart Remote Device')), value: 'restart')); } + // Currently only support VP9 + if (gFFI.recordingModel.start || + (perms["recording"] != false && + gFFI.qualityMonitorModel.data.codecFormat == "VP9")) { + more.add(PopupMenuItem( + child: Row( + children: [ + Text(translate(gFFI.recordingModel.start + ? 'Stop session recording' + : 'Start session recording')), + Padding( + padding: EdgeInsets.only(left: 12), + child: Icon( + gFFI.recordingModel.start + ? Icons.pause_circle_filled + : Icons.videocam_outlined, + color: MyTheme.accent), + ) + ], + ), + value: 'record')); + } () async { var value = await showMenu( context: context, @@ -630,6 +652,8 @@ class _RemotePageState extends State { gFFI.cursorModel.reset(); } else if (value == 'restart') { showRestartRemoteDevice(pi, widget.id, gFFI.dialogManager); + } else if (value == 'record') { + gFFI.recordingModel.toggle(); } }(); } diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 79cd7ad54..8e5723588 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -231,7 +231,8 @@ class FfiModel with ChangeNotifier { } else if (type == 'input-password') { enterPasswordDialog(id, dialogManager); } else if (type == 'restarting') { - showMsgBox(id, type, title, text, link, false, dialogManager, hasCancel: false); + showMsgBox(id, type, title, text, link, false, dialogManager, + hasCancel: false); } else { var hasRetry = evt['hasRetry'] == 'true'; showMsgBox(id, type, title, text, link, hasRetry, dialogManager); @@ -1003,16 +1004,16 @@ class RecordingModel with ChangeNotifier { get start => _start; onSwitchDisplay() { - if (!isDesktop || !_start) return; + if (isIOS || !_start) return; var id = parent.target?.id; int? width = parent.target?.canvasModel.getDisplayWidth(); - int? height = 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); } toggle() { - if (!isDesktop) return; + if (isIOS) return; var id = parent.target?.id; if (id == null) return; _start = !_start; @@ -1025,7 +1026,7 @@ class RecordingModel with ChangeNotifier { } onClose() { - if (!isDesktop) return; + if (isIOS) return; var id = parent.target?.id; if (id == null) return; _start = false;