diff --git a/Cargo.lock b/Cargo.lock index 3a6abcaf7..e4b5d2792 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3975,7 +3975,7 @@ dependencies = [ [[package]] name = "rdev" version = "0.5.0-2" -source = "git+https://github.com/asur4s/rdev#0ad53987fa6f0e37a7bc000358f71c3802de4e7c" +source = "git+https://github.com/asur4s/rdev#bff57a29e3f14d032ab7441b2d6cf029df8adaca" dependencies = [ "cocoa", "core-foundation 0.9.3", diff --git a/build.py b/build.py index 27b5af744..97b1c02f9 100755 --- a/build.py +++ b/build.py @@ -142,12 +142,12 @@ def build_flutter_deb(version): os.chdir('flutter') os.system('dpkg-deb -R rustdesk.deb tmpdeb') os.system('flutter build linux --release') - os.system('strip build/linux/x64/release/liblibrustdesk.so') os.system('mkdir -p tmpdeb/usr/bin/') os.system('mkdir -p tmpdeb/usr/lib/rustdesk') os.system('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/') os.system('mkdir -p tmpdeb/usr/share/applications/') + os.system('mkdir -p tmpdeb/usr/share/polkit-1/actions') os.system( 'cp -r build/linux/x64/release/bundle/* tmpdeb/usr/lib/rustdesk/') @@ -163,6 +163,10 @@ def build_flutter_deb(version): 'cp ../128x128@2x.png tmpdeb/usr/share/rustdesk/files/rustdesk.png') os.system( 'cp ../rustdesk.desktop tmpdeb/usr/share/applications/rustdesk.desktop') + os.system( + 'cp ../com.rustdesk.RustDesk.policy tmpdeb/usr/share/polkit-1/actions/') + os.system("echo \"#!/bin/sh\" >> tmpdeb/usr/share/rustdesk/files/polkit && chmod a+x tmpdeb/usr/share/rustdesk/files/polkit") + os.system('mkdir -p tmpdeb/DEBIAN') generate_control_file(version) os.system('cp -a ../DEBIAN/* tmpdeb/DEBIAN/') diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 134fe4219..9024c996f 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -414,7 +414,7 @@ class _ConnectionPageState extends State { ); } else { if (model.abLoading) { - return Center( + return const Center( child: CircularProgressIndicator(), ); } else if (model.abError.isNotEmpty) { @@ -782,6 +782,7 @@ class _PeerTabbedPageState extends State<_PeerTabbedPage> bind.mainDiscover(); break; case 3: + gFFI.abModel.updateAb(); break; } } diff --git a/flutter/lib/desktop/widgets/peer_widget.dart b/flutter/lib/desktop/widgets/peer_widget.dart index 32976fb5b..f137241a9 100644 --- a/flutter/lib/desktop/widgets/peer_widget.dart +++ b/flutter/lib/desktop/widgets/peer_widget.dart @@ -43,7 +43,7 @@ class _PeerWidgetState extends State<_PeerWidget> with WindowListener { final _curPeers = {}; var _lastChangeTime = DateTime.now(); var _lastQueryPeers = {}; - var _lastQueryTime = DateTime.now().subtract(Duration(hours: 1)); + var _lastQueryTime = DateTime.now().subtract(const Duration(hours: 1)); var _queryCoun = 0; var _exit = false; @@ -143,8 +143,8 @@ class _PeerWidgetState extends State<_PeerWidget> with WindowListener { while (!_exit) { final now = DateTime.now(); if (!setEquals(_curPeers, _lastQueryPeers)) { - if (now.difference(_lastChangeTime) > Duration(seconds: 1)) { - if (_curPeers.length > 0) { + if (now.difference(_lastChangeTime) > const Duration(seconds: 1)) { + if (_curPeers.isNotEmpty) { platformFFI.ffiBind .queryOnlines(ids: _curPeers.toList(growable: false)); _lastQueryPeers = {..._curPeers}; @@ -154,8 +154,8 @@ class _PeerWidgetState extends State<_PeerWidget> with WindowListener { } } else { if (_queryCoun < _maxQueryCount) { - if (now.difference(_lastQueryTime) > Duration(seconds: 20)) { - if (_curPeers.length > 0) { + if (now.difference(_lastQueryTime) > const Duration(seconds: 20)) { + if (_curPeers.isNotEmpty) { platformFFI.ffiBind .queryOnlines(ids: _curPeers.toList(growable: false)); _lastQueryTime = DateTime.now(); @@ -164,7 +164,7 @@ class _PeerWidgetState extends State<_PeerWidget> with WindowListener { } } } - await Future.delayed(Duration(milliseconds: 300)); + await Future.delayed(const Duration(milliseconds: 300)); } }(); } @@ -266,7 +266,7 @@ class AddressBookPeerWidget extends BasePeerWidget { loadEvent: 'load_address_book_peers', offstageFunc: (Peer peer) => !_hitTag(gFFI.abModel.selectedTags, peer.tags), - peerCardWidgetFunc: (Peer peer) => DiscoveredPeerCard( + peerCardWidgetFunc: (Peer peer) => AddressBookPeerCard( peer: peer, ), initPeers: _loadPeers(), @@ -292,4 +292,11 @@ class AddressBookPeerWidget extends BasePeerWidget { } return true; } + + @override + Widget build(BuildContext context) { + final widget = super.build(context); + gFFI.abModel.updateAb(); + return widget; + } } diff --git a/flutter/lib/desktop/widgets/peercard_widget.dart b/flutter/lib/desktop/widgets/peercard_widget.dart index d9a87cd7b..fc93c59c6 100644 --- a/flutter/lib/desktop/widgets/peercard_widget.dart +++ b/flutter/lib/desktop/widgets/peercard_widget.dart @@ -113,15 +113,16 @@ class _PeerCardState extends State<_PeerCard> children: [ Row(children: [ Padding( - padding: EdgeInsets.fromLTRB(0, 4, 4, 4), + padding: const EdgeInsets.fromLTRB(0, 4, 4, 4), child: CircleAvatar( radius: 5, backgroundColor: peer.online ? Colors.green : Colors.yellow)), Text( - formatID('${peer.id}'), - style: TextStyle(fontWeight: FontWeight.w400), + formatID(peer.id), + style: + const TextStyle(fontWeight: FontWeight.w400), ), ]), Align( @@ -136,7 +137,7 @@ class _PeerCardState extends State<_PeerCard> : snapshot.data!; return Tooltip( message: name, - waitDuration: Duration(seconds: 1), + waitDuration: const Duration(seconds: 1), child: Text( name, style: greyStyle, @@ -208,10 +209,11 @@ class _PeerCardState extends State<_PeerCard> : widget.alias.value; return Tooltip( message: name, - waitDuration: Duration(seconds: 1), + waitDuration: + const Duration(seconds: 1), child: Text( name, - style: TextStyle( + style: const TextStyle( color: Colors.white70, fontSize: 12), textAlign: TextAlign.center, @@ -236,7 +238,7 @@ class _PeerCardState extends State<_PeerCard> children: [ Row(children: [ Padding( - padding: EdgeInsets.fromLTRB(0, 4, 8, 4), + padding: const EdgeInsets.fromLTRB(0, 4, 8, 4), child: CircleAvatar( radius: 5, backgroundColor: peer.online @@ -501,7 +503,7 @@ abstract class BasePeerCard extends StatelessWidget { final favs = (await bind.mainGetFav()).toList(); if (!favs.contains(id)) { favs.add(id); - bind.mainStoreFav(favs: favs); + await bind.mainStoreFav(favs: favs); } }(); }, @@ -510,7 +512,8 @@ abstract class BasePeerCard extends StatelessWidget { } @protected - MenuEntryBase _rmFavAction(String id) { + MenuEntryBase _rmFavAction( + String id, Future Function() reloadFunc) { return MenuEntryButton( childBuilder: (TextStyle? style) => Text( translate('Remove from Favorites'), @@ -520,8 +523,9 @@ abstract class BasePeerCard extends StatelessWidget { () async { final favs = (await bind.mainGetFav()).toList(); if (favs.remove(id)) { - bind.mainStoreFav(favs: favs); - Get.forceAppUpdate(); // TODO use inner model / state + await bind.mainStoreFav(favs: favs); + await reloadFunc(); + // Get.forceAppUpdate(); // TODO use inner model / state } }(); }, @@ -646,7 +650,9 @@ class FavoritePeerCard extends BasePeerCard { await bind.mainLoadFavPeers(); })); menuItems.add(_unrememberPasswordAction(peer.id)); - menuItems.add(_rmFavAction(peer.id)); + menuItems.add(_rmFavAction(peer.id, () async { + await bind.mainLoadFavPeers(); + })); return menuItems; } } @@ -817,8 +823,8 @@ class AddressBookPeerCard extends BasePeerCard { color: rxTags.contains(tagName) ? Colors.blue : null, border: Border.all(color: MyTheme.darkGray), borderRadius: BorderRadius.circular(10)), - margin: EdgeInsets.symmetric(horizontal: 4.0, vertical: 8.0), - padding: EdgeInsets.symmetric(vertical: 2.0, horizontal: 8.0), + margin: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 8.0), + padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 8.0), child: Text( tagName, style: TextStyle( @@ -831,38 +837,6 @@ class AddressBookPeerCard extends BasePeerCard { } } -Future> _forceAlwaysRelayMenuItem(String id) async { - bool force_always_relay = - (await bind.mainGetPeerOption(id: id, key: 'force-always-relay')) - .isNotEmpty; - return PopupMenuItem( - child: Row( - children: [ - Offstage( - offstage: !force_always_relay, - child: Icon(Icons.check), - ), - Text(translate('Always connect via relay')), - ], - ), - value: 'force-always-relay'); -} - -PopupMenuItem _rdpMenuItem(String id) { - return PopupMenuItem( - child: Row( - children: [ - Text('RDP'), - SizedBox(width: 20), - IconButton( - icon: Icon(Icons.edit), - onPressed: () => _rdpDialog(id), - ) - ], - ), - value: 'RDP'); -} - void _rdpDialog(String id) async { final portController = TextEditingController( text: await bind.mainGetPeerOption(id: id, key: 'rdp_port')); diff --git a/flutter/lib/models/ab_model.dart b/flutter/lib/models/ab_model.dart index 18bb73c3f..2749e972f 100644 --- a/flutter/lib/models/ab_model.dart +++ b/flutter/lib/models/ab_model.dart @@ -28,21 +28,26 @@ class AbModel with ChangeNotifier { try { final resp = await http.post(Uri.parse(api), headers: await _getHeaders()); - Map json = jsonDecode(resp.body); - if (json.containsKey('error')) { - abError = json['error']; - } else if (json.containsKey('data')) { - final data = jsonDecode(json['data']); - tags.value = data['tags']; - peers.value = data['peers']; + if (resp.body.isNotEmpty && resp.body.toLowerCase() != "null") { + Map json = jsonDecode(resp.body); + if (json.containsKey('error')) { + abError = json['error']; + } else if (json.containsKey('data')) { + final data = jsonDecode(json['data']); + tags.value = data['tags']; + peers.value = data['peers']; + } + notifyListeners(); + return resp.body; + } else { + return ""; } - return resp.body; } catch (err) { abError = err.toString(); } finally { + notifyListeners(); abLoading = false; } - notifyListeners(); return null; } @@ -60,7 +65,6 @@ class AbModel with ChangeNotifier { return _ffi?.getHttpHeaders(); } - /// void addId(String id) async { if (idContainBy(id)) { return; diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index dbdf1637b..acbd45269 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -70,7 +70,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.3.1" build_config: dependency: transitive description: @@ -91,21 +91,21 @@ packages: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.10" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.2.1" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "7.2.3" + version: "7.2.4" built_collection: dependency: transitive description: @@ -973,7 +973,7 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.2.2" + version: "1.2.3" source_span: dependency: transitive description: diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 6f73aa768..4fce42da4 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -17,14 +17,15 @@ use crate::flutter::{self, SESSIONS}; use crate::start_server; use crate::ui_interface; #[cfg(not(any(target_os = "android", target_os = "ios")))] +use crate::ui_interface::{change_id, get_sound_inputs}; use crate::ui_interface::{ - change_id, check_mouse_time, check_super_user_permission, discover, forget_password, - get_api_server, get_app_name, get_async_job_status, get_connect_status, get_fav, get_id, - get_lan_peers, get_langs, get_license, get_local_option, get_mouse_time, get_option, - get_options, get_peer, get_peer_option, get_socks, get_sound_inputs, get_uuid, get_version, - has_hwcodec, has_rendezvous_service, post_request, send_to_cm, set_local_option, set_option, - set_options, set_peer_option, set_permanent_password, set_socks, store_fav, - test_if_valid_server, update_temporary_password, using_public_server, + check_mouse_time, check_super_user_permission, discover, forget_password, get_api_server, + get_app_name, get_async_job_status, get_connect_status, get_fav, get_id, get_lan_peers, + get_langs, get_license, get_local_option, get_mouse_time, get_option, get_options, get_peer, + get_peer_option, get_socks, get_uuid, get_version, has_hwcodec, has_rendezvous_service, + post_request, send_to_cm, set_local_option, set_option, set_options, set_peer_option, + set_permanent_password, set_socks, store_fav, test_if_valid_server, update_temporary_password, + using_public_server, }; use crate::{ client::file_trait::FileManager, @@ -416,7 +417,10 @@ pub fn session_resume_job(id: String, act_id: i32, is_remote: bool) { } pub fn main_get_sound_inputs() -> Vec { - get_sound_inputs() + #[cfg(not(any(target_os = "android", target_os = "ios")))] + return get_sound_inputs(); + #[cfg(any(target_os = "android", target_os = "linux"))] + vec![String::from("")] } pub fn main_change_id(new_id: String) { diff --git a/src/ui_interface.rs b/src/ui_interface.rs index af7e8ba05..90afb8c43 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -223,6 +223,7 @@ pub fn test_if_valid_server(host: String) -> String { } #[inline] +#[cfg(not(any(target_os = "android", target_os = "ios")))] pub fn get_sound_inputs() -> Vec { let mut a = Vec::new(); #[cfg(not(target_os = "linux"))] diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 945c45385..692b592d4 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -11,7 +11,9 @@ use async_trait::async_trait; use hbb_common::config::{Config, LocalConfig, PeerConfig}; use hbb_common::rendezvous_proto::ConnType; use hbb_common::tokio::{self, sync::mpsc}; -use rdev::{Event, EventType::*, Key as RdevKey, Keyboard as RdevKeyboard, KeyboardState}; +use rdev::{Event, EventType::*, Key as RdevKey, KeyboardState}; +#[cfg(not(any(target_os = "android", target_os = "ios")))] +use rdev::Keyboard as RdevKeyboard; use hbb_common::{allow_err, message_proto::*}; use hbb_common::{fs, get_version_number, log, Stream}; @@ -27,9 +29,12 @@ pub static KEYBOARD_HOOKED: AtomicBool = AtomicBool::new(true); #[cfg(windows)] static mut IS_ALT_GR: bool = false; -#[cfg(not(any(target_os = "android", target_os = "ios")))] lazy_static::lazy_static! { static ref TO_RELEASE: Arc>> = Arc::new(Mutex::new(HashSet::::new())); +} + +#[cfg(not(any(target_os = "android", target_os = "ios")))] +lazy_static::lazy_static! { static ref KEYBOARD: Arc> = Arc::new(Mutex::new(RdevKeyboard::new().unwrap())); } @@ -268,6 +273,7 @@ impl Session { #[allow(dead_code)] fn convert_numpad_keys(&self, key: RdevKey) -> RdevKey { + #[cfg(not(any(target_os = "android", target_os = "ios")))] if get_key_state(enigo::Key::NumLock) { return key; } @@ -315,10 +321,11 @@ impl Session { key_event.set_chr(keycode); key_event.down = down_or_up; - + #[cfg(not(any(target_os = "android", target_os = "ios")))] if get_key_state(enigo::Key::CapsLock) { key_event.modifiers.push(ControlKey::CapsLock.into()); } + #[cfg(not(any(target_os = "android", target_os = "ios")))] if get_key_state(enigo::Key::NumLock) { key_event.modifiers.push(ControlKey::NumLock.into()); } @@ -326,6 +333,7 @@ impl Session { self.send_key_event(key_event, KeyboardMode::Map); } + #[cfg(not(any(target_os = "android", target_os = "ios")))] fn translate_keyboard_mode(&self, down_or_up: bool, key: RdevKey, evt: Event) { // translate mode(2): locally generated characters are send to the peer. @@ -407,10 +415,11 @@ impl Session { { key_event.modifiers.push(ControlKey::Meta.into()); } - + #[cfg(not(any(target_os = "android", target_os = "ios")))] if get_key_state(enigo::Key::CapsLock) { key_event.modifiers.push(ControlKey::CapsLock.into()); } + #[cfg(not(any(target_os = "android", target_os = "ios")))] if self.peer_platform() != "Mac OS" { if get_key_state(enigo::Key::NumLock) { key_event.modifiers.push(ControlKey::NumLock.into()); @@ -418,6 +427,7 @@ impl Session { } } + #[cfg(not(any(target_os = "android", target_os = "ios")))] fn legacy_keyboard_mode(&self, down_or_up: bool, key: RdevKey, evt: Event) { // legacy mode(0): Generate characters locally, look for keycode on other side. let peer = self.peer_platform(); @@ -648,11 +658,18 @@ impl Session { } self.map_keyboard_mode(down_or_up, key, Some(evt)); } - KeyboardMode::Legacy => self.legacy_keyboard_mode(down_or_up, key, evt), + KeyboardMode::Legacy => { + #[cfg(not(any(target_os = "android", target_os = "ios")))] + self.legacy_keyboard_mode(down_or_up, key, evt) + }, KeyboardMode::Translate => { + #[cfg(not(any(target_os = "android", target_os = "ios")))] self.translate_keyboard_mode(down_or_up, key, evt); } - _ => self.legacy_keyboard_mode(down_or_up, key, evt), + _ => { + #[cfg(not(any(target_os = "android", target_os = "ios")))] + self.legacy_keyboard_mode(down_or_up, key, evt) + }, } } @@ -742,7 +759,6 @@ impl Session { let keycode: u32 = keycode as u32; let scancode: u32 = scancode as u32; - #[cfg(not(target_os = "windows"))] let key = rdev::key_from_scancode(scancode) as RdevKey; // Windows requires special handling #[cfg(target_os = "windows")]