diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 742123888..c8ff89c00 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -1,7 +1,6 @@ // main window right pane import 'dart:async'; -import 'dart:convert'; import 'dart:io'; import 'package:auto_size_text/auto_size_text.dart'; @@ -9,7 +8,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/desktop/widgets/scroll_wrapper.dart'; import 'package:flutter_hbb/models/state_model.dart'; -import 'package:flutter_hbb/models/user_model.dart'; import 'package:get/get.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:window_manager/window_manager.dart'; @@ -37,13 +35,12 @@ class _ConnectionPageState extends State /// Nested scroll controller final _scrollController = ScrollController(); - Timer? _updateTimer; + Timer? _svcStatusTimer; final RxBool _idInputFocused = false.obs; final FocusNode _idFocusNode = FocusNode(); var svcStopped = Get.find(tag: 'stop-service'); - var svcIsUsingPublicServer = true.obs; bool isWindowMinimized = false; @@ -60,8 +57,8 @@ class _ConnectionPageState extends State } }(); } - _updateTimer = periodic_immediate(Duration(seconds: 1), () async { - updateStatus(); + _svcStatusTimer = periodic_immediate(Duration(seconds: 1), () async { + stateGlobal.updateSvcStatus(); }); _idFocusNode.addListener(() { _idInputFocused.value = _idFocusNode.hasFocus; @@ -75,7 +72,8 @@ class _ConnectionPageState extends State @override void dispose() { _idController.dispose(); - _updateTimer?.cancel(); + _svcStatusTimer?.cancel(); + _svcStatusTimer = null; windowManager.removeListener(this); super.dispose(); } @@ -288,7 +286,7 @@ class _ConnectionPageState extends State child: Offstage( offstage: !(!svcStopped.value && stateGlobal.svcStatus.value == SvcStatus.ready && - svcIsUsingPublicServer.value), + stateGlobal.svcIsUsingPublicServer.value), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -327,31 +325,4 @@ class _ConnectionPageState extends State } }); } - - updateStatus() async { - final status = - jsonDecode(await bind.mainGetConnectStatus()) as Map; - final statusNum = status['status_num'] as int; - final preStatus = stateGlobal.svcStatus.value; - if (statusNum == 0) { - stateGlobal.svcStatus.value = SvcStatus.connecting; - } else if (statusNum == -1) { - stateGlobal.svcStatus.value = SvcStatus.notReady; - } else if (statusNum == 1) { - stateGlobal.svcStatus.value = SvcStatus.ready; - if (preStatus != SvcStatus.ready) { - gFFI.userModel.refreshCurrentUser(); - } - } else { - stateGlobal.svcStatus.value = SvcStatus.notReady; - } - if (stateGlobal.svcStatus.value != SvcStatus.ready) { - gFFI.userModel.isAdmin.value = false; - gFFI.groupModel.reset(); - } - if (preStatus != stateGlobal.svcStatus.value) { - UserModel.updateOtherModels(); - } - svcIsUsingPublicServer.value = await bind.mainIsUsingPublicServer(); - } } diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 14534613a..eb4901686 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -151,6 +151,7 @@ void runMobileApp() async { await initEnv(kAppTypeMain); if (isAndroid) androidChannelInit(); platformFFI.syncAndroidServiceAppDirConfigPath(); + gFFI.userModel.refreshCurrentUser(); runApp(App()); } diff --git a/flutter/lib/mobile/pages/server_page.dart b/flutter/lib/mobile/pages/server_page.dart index ae61c91a7..0b0b8cc5c 100644 --- a/flutter/lib/mobile/pages/server_page.dart +++ b/flutter/lib/mobile/pages/server_page.dart @@ -11,6 +11,7 @@ import '../../common/widgets/dialog.dart'; import '../../consts.dart'; import '../../models/platform_model.dart'; import '../../models/server_model.dart'; +import '../../models/state_model.dart'; import 'home_page.dart'; class ServerPage extends StatefulWidget implements PageShape { @@ -200,7 +201,6 @@ class ServerInfo extends StatelessWidget { @override Widget build(BuildContext context) { final isPermanent = model.verificationMethod == kUsePermanentPassword; - final serverModel = Provider.of(context); const Color colorPositive = Colors.green; const Color colorNegative = Colors.red; @@ -216,28 +216,29 @@ class ServerInfo extends StatelessWidget { showToast(translate('Copied')); } - Widget ConnectionStateNotification() { - if (serverModel.connectStatus == -1) { - return Row(children: [ - const Icon(Icons.warning_amber_sharp, - color: colorNegative, size: iconSize) - .marginOnly(right: iconMarginRight), - Expanded(child: Text(translate('not_ready_status'))) - ]); - } else if (serverModel.connectStatus == 0) { - return Row(children: [ - SizedBox(width: 20, height: 20, child: CircularProgressIndicator()) - .marginOnly(left: 4, right: iconMarginRight), - Expanded(child: Text(translate('connecting_status'))) - ]); - } else { - return Row(children: [ - const Icon(Icons.check, color: colorPositive, size: iconSize) - .marginOnly(right: iconMarginRight), - Expanded(child: Text(translate('Ready'))) - ]); - } - } + Widget ConnectionStateNotification() => Obx(() { + if (stateGlobal.svcStatus.value == SvcStatus.notReady) { + return Row(children: [ + const Icon(Icons.warning_amber_sharp, + color: colorNegative, size: iconSize) + .marginOnly(right: iconMarginRight), + Expanded(child: Text(translate('not_ready_status'))) + ]); + } else if (stateGlobal.svcStatus.value == SvcStatus.connecting) { + return Row(children: [ + SizedBox( + width: 20, height: 20, child: CircularProgressIndicator()) + .marginOnly(left: 4, right: iconMarginRight), + Expanded(child: Text(translate('connecting_status'))) + ]); + } else { + return Row(children: [ + const Icon(Icons.check, color: colorPositive, size: iconSize) + .marginOnly(right: iconMarginRight), + Expanded(child: Text(translate('Ready'))) + ]); + } + }); return PaddingCard( title: translate('Your Device'), diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index 2ca608bd6..4eddee2b6 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -15,7 +15,8 @@ import '../common/formatter/id_formatter.dart'; import '../desktop/pages/server_page.dart' as desktop; import '../desktop/widgets/tabbar_widget.dart'; import '../mobile/pages/server_page.dart'; -import 'model.dart'; +import './model.dart'; +import './state_model.dart'; const kLoginDialogTag = "LOGIN"; @@ -31,7 +32,6 @@ class ServerModel with ChangeNotifier { bool _fileOk = false; bool _showElevation = false; bool _hideCm = false; - int _connectStatus = 0; // Rendezvous Server status String _verificationMethod = ""; String _temporaryPasswordLength = ""; String _approveMode = ""; @@ -61,8 +61,6 @@ class ServerModel with ChangeNotifier { bool get hideCm => _hideCm; - int get connectStatus => _connectStatus; - String get verificationMethod { final index = [ kUseTemporaryPassword, @@ -120,15 +118,7 @@ class ServerModel with ChangeNotifier { _serverId = IDTextEditingController(text: _emptyIdShow); timerCallback() async { - var status = await bind.mainGetOnlineStatue(); - if (status > 0) { - status = 1; - } - if (status != _connectStatus) { - _connectStatus = status; - notifyListeners(); - } - + stateGlobal.updateSvcStatus(); if (desktopType == DesktopType.cm) { final res = await bind.cmCheckClientsLength(length: _clients.length); if (res != null) { diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index f7b4f8cc2..d73ddb643 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -1,10 +1,15 @@ +import 'dart:convert'; import 'dart:io'; +import 'dart:async'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../consts.dart'; +import '../common.dart'; + +import './platform_model.dart'; enum SvcStatus { notReady, connecting, ready } @@ -18,7 +23,9 @@ class StateGlobal { final RxDouble _windowBorderWidth = RxDouble(kWindowBorderWidth); final RxBool showRemoteToolBar = false.obs; final RxInt displaysCount = 0.obs; + final svcStatus = SvcStatus.notReady.obs; + final svcIsUsingPublicServer = true.obs; // Use for desktop -> remote toolbar -> resolution final Map> _lastResolutionGroupValues = {}; @@ -84,6 +91,31 @@ class StateGlobal { } } + updateSvcStatus() async { + final status = + jsonDecode(await bind.mainGetConnectStatus()) as Map; + final statusNum = status['status_num'] as int; + final preStatus = stateGlobal.svcStatus.value; + if (statusNum == 0) { + stateGlobal.svcStatus.value = SvcStatus.connecting; + } else if (statusNum == -1) { + stateGlobal.svcStatus.value = SvcStatus.notReady; + } else if (statusNum == 1) { + stateGlobal.svcStatus.value = SvcStatus.ready; + if (preStatus != SvcStatus.ready) { + gFFI.userModel.refreshCurrentUser(); + } + } else { + stateGlobal.svcStatus.value = SvcStatus.notReady; + } + if (stateGlobal.svcStatus.value != SvcStatus.ready) { + gFFI.userModel.isAdmin.value = false; + gFFI.groupModel.reset(); + } + stateGlobal.svcIsUsingPublicServer.value = + await bind.mainIsUsingPublicServer(); + } + StateGlobal._(); static final StateGlobal instance = StateGlobal._(); diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index b6445eea7..785be96ee 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -44,7 +44,7 @@ lazy_static::lazy_static! { static ref CONFIG: Arc> = Arc::new(RwLock::new(Config::load())); static ref CONFIG2: Arc> = Arc::new(RwLock::new(Config2::load())); static ref LOCAL_CONFIG: Arc> = Arc::new(RwLock::new(LocalConfig::load())); - pub static ref ONLINE: Arc>> = Default::default(); + static ref ONLINE: Arc>> = Default::default(); pub static ref PROD_RENDEZVOUS_SERVER: Arc> = Arc::new(RwLock::new(match option_env!("RENDEZVOUS_SERVER") { Some(key) if !key.is_empty() => key, _ => "", @@ -309,6 +309,11 @@ pub struct TransferSerde { pub read_jobs: Vec, } +#[inline] +pub fn get_online_statue() -> i64 { + *ONLINE.lock().unwrap().values().max().unwrap_or(&0) +} + #[cfg(not(any(target_os = "android", target_os = "ios")))] fn patch(path: PathBuf) -> PathBuf { if let Some(_tmp) = path.to_str() { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index b3c011c2b..9a3f1abab 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -14,12 +14,11 @@ use flutter_rust_bridge::{StreamSink, SyncReturn}; #[cfg(not(any(target_os = "android", target_os = "ios")))] use hbb_common::allow_err; use hbb_common::{ - config::{self, LocalConfig, PeerConfig, PeerInfoSerde, ONLINE}, + config::{self, LocalConfig, PeerConfig, PeerInfoSerde}, fs, log, message_proto::KeyboardMode, ResultType, }; -use serde_json::json; use std::{ collections::HashMap, ffi::{CStr, CString}, @@ -680,14 +679,18 @@ pub fn main_get_lan_peers() -> String { } pub fn main_get_connect_status() -> String { - let status = get_connect_status(); - // (status_num, key_confirmed, mouse_time, id) - let mut m = serde_json::Map::new(); - m.insert("status_num".to_string(), json!(status.0)); - m.insert("key_confirmed".to_string(), json!(status.1)); - m.insert("mouse_time".to_string(), json!(status.2)); - m.insert("id".to_string(), json!(status.3)); - serde_json::to_string(&m).unwrap_or("".to_string()) + #[cfg(not(any(target_os = "android", target_os = "ios")))] + { + serde_json::to_string(&get_connect_status()).unwrap_or("".to_string()) + } + #[cfg(any(target_os = "android", target_os = "ios"))] + { + let mut state = hbb_common::config::get_online_statue(); + if state > 0 { + state = 1; + } + serde_json::json!({ "status_num": state }).to_string() + } } pub fn main_check_connect_status() { @@ -995,10 +998,6 @@ pub fn main_get_fingerprint() -> String { get_fingerprint() } -pub fn main_get_online_statue() -> i64 { - ONLINE.lock().unwrap().values().max().unwrap_or(&0).clone() -} - pub fn cm_get_clients_state() -> String { crate::ui_cm_interface::get_clients_state() } @@ -1194,7 +1193,14 @@ pub fn main_check_mouse_time() { } pub fn main_get_mouse_time() -> f64 { - get_mouse_time() + #[cfg(not(any(target_os = "android", target_os = "ios")))] + { + get_mouse_time() + } + #[cfg(any(target_os = "android", target_os = "ios"))] + { + 0.0 + } } pub fn main_wol(id: String) { diff --git a/src/hbbs_http/account.rs b/src/hbbs_http/account.rs index a2ef53029..e958bf636 100644 --- a/src/hbbs_http/account.rs +++ b/src/hbbs_http/account.rs @@ -216,7 +216,7 @@ impl OidcSession { let query_timeout = OIDC_SESSION.read().unwrap().query_timeout; while OIDC_SESSION.read().unwrap().keep_querying && begin.elapsed() < query_timeout { match Self::query(&code_url.code, &id, &uuid) { - Ok(HbbHttpResponse::<_>::Data(mut auth_body)) => { + Ok(HbbHttpResponse::<_>::Data(auth_body)) => { if remember_me { LocalConfig::set_option( "access_token".to_owned(), diff --git a/src/ipc.rs b/src/ipc.rs index 83a48107c..6a426e37d 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -186,6 +186,7 @@ pub enum Data { }, SystemInfo(Option), ClickTime(i64), + #[cfg(not(any(target_os = "android", target_os = "ios")))] MouseMoveTime(i64), Authorize, Close, @@ -332,6 +333,7 @@ async fn handle(data: Data, stream: &mut Connection) { let t = crate::server::CLICK_TIME.load(Ordering::SeqCst); allow_err!(stream.send(&Data::ClickTime(t)).await); } + #[cfg(not(any(target_os = "android", target_os = "ios")))] Data::MouseMoveTime(_) => { let t = crate::server::MOUSE_MOVE_TIME.load(Ordering::SeqCst); allow_err!(stream.send(&Data::MouseMoveTime(t)).await); @@ -345,13 +347,7 @@ async fn handle(data: Data, stream: &mut Connection) { } } Data::OnlineStatus(_) => { - let x = config::ONLINE - .lock() - .unwrap() - .values() - .max() - .unwrap_or(&0) - .clone(); + let x = config::get_online_statue(); let confirmed = Config::get_key_confirmed(); allow_err!(stream.send(&Data::OnlineStatus(Some((x, confirmed)))).await); } diff --git a/src/server/connection.rs b/src/server/connection.rs index 88d7220eb..f747e47c1 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -63,6 +63,7 @@ lazy_static::lazy_static! { static ref SWITCH_SIDES_UUID: Arc::>> = Default::default(); } pub static CLICK_TIME: AtomicI64 = AtomicI64::new(0); +#[cfg(not(any(target_os = "android", target_os = "ios")))] pub static MOUSE_MOVE_TIME: AtomicI64 = AtomicI64::new(0); #[cfg(all(feature = "flutter", feature = "plugin_framework"))] @@ -163,6 +164,7 @@ pub struct Connection { // by peer disable_audio: bool, // by peer + #[cfg(windows)] enable_file_transfer: bool, // by peer audio_sender: Option, @@ -291,6 +293,7 @@ impl Connection { show_remote_cursor: false, ip: "".to_owned(), disable_audio: false, + #[cfg(windows)] enable_file_transfer: false, disable_clipboard: false, disable_keyboard: false, @@ -1112,6 +1115,7 @@ impl Connection { self.audio && !self.disable_audio } + #[cfg(windows)] fn file_transfer_enabled(&self) -> bool { self.file && self.enable_file_transfer } diff --git a/src/ui.rs b/src/ui.rs index 94ae30cf6..10eab22cb 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -362,9 +362,9 @@ impl UI { fn get_connect_status(&mut self) -> Value { let mut v = Value::array(0); let x = get_connect_status(); - v.push(x.0); - v.push(x.1); - v.push(x.3); + v.push(x.status_num); + v.push(x.key_confirmed); + v.push(x.id); v } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 7e46fd314..b61598251 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -454,10 +454,10 @@ impl IpcTaskRunner { } } Some(data) = self.rx.recv() => { - if let Data::SwitchPermission{name, enabled} = &data { + if let Data::SwitchPermission{name: _name, enabled: _enabled} = &data { #[cfg(windows)] - if name == "file" { - self.file_transfer_enabled = *enabled; + if _name == "file" { + self.file_transfer_enabled = *_enabled; } } if self.stream.send(&data).await.is_err() { diff --git a/src/ui_interface.rs b/src/ui_interface.rs index e298e1167..16d26b48f 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -1,9 +1,3 @@ -use std::{ - collections::HashMap, - process::Child, - sync::{Arc, Mutex}, -}; - #[cfg(any(target_os = "android", target_os = "ios"))] use hbb_common::password_security; use hbb_common::{ @@ -16,6 +10,12 @@ use hbb_common::{ sleep, tokio::{sync::mpsc, time}, }; +use serde_derive::Serialize; +use std::{ + collections::HashMap, + process::Child, + sync::{Arc, Mutex}, +}; use hbb_common::{ config::{CONNECT_TIMEOUT, RENDEZVOUS_PORT}, @@ -32,10 +32,28 @@ use crate::ipc; type Message = RendezvousMessage; pub type Children = Arc)>>; -type Status = (i32, bool, i64, String); // (status_num, key_confirmed, mouse_time, id) + +#[derive(Clone, Debug, Serialize)] +pub struct UiStatus { + pub status_num: i32, + #[cfg(not(feature = "flutter"))] + pub key_confirmed: bool, + #[cfg(not(any(target_os = "android", target_os = "ios")))] + pub mouse_time: i64, + #[cfg(not(feature = "flutter"))] + pub id: String, +} lazy_static::lazy_static! { - static ref UI_STATUS : Arc> = Arc::new(Mutex::new((0, false, 0, "".to_owned()))); + static ref UI_STATUS : Arc> = Arc::new(Mutex::new(UiStatus{ + status_num: 0, + #[cfg(not(feature = "flutter"))] + key_confirmed: false, + #[cfg(not(any(target_os = "android", target_os = "ios")))] + mouse_time: 0, + #[cfg(not(feature = "flutter"))] + id: "".to_owned(), + })); static ref OPTIONS : Arc>> = Arc::new(Mutex::new(Config::get_options())); static ref ASYNC_JOB_STATUS : Arc> = Default::default(); static ref TEMPORARY_PASSWD : Arc> = Arc::new(Mutex::new("".to_owned())); @@ -393,10 +411,9 @@ pub fn is_installed_lower_version() -> bool { } #[inline] +#[cfg(not(any(target_os = "android", target_os = "ios")))] pub fn get_mouse_time() -> f64 { - let ui_status = UI_STATUS.lock().unwrap(); - let res = ui_status.2 as f64; - return res; + UI_STATUS.lock().unwrap().mouse_time as f64 } #[inline] @@ -409,10 +426,9 @@ pub fn check_mouse_time() { } #[inline] -pub fn get_connect_status() -> Status { - let ui_statue = UI_STATUS.lock().unwrap(); - let res = ui_statue.clone(); - res +#[cfg(not(any(target_os = "android", target_os = "ios")))] +pub fn get_connect_status() -> UiStatus { + UI_STATUS.lock().unwrap().clone() } #[inline] @@ -857,10 +873,13 @@ pub fn get_hostname() -> String { #[cfg(not(any(target_os = "android", target_os = "ios")))] #[tokio::main(flavor = "current_thread")] async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver) { + #[cfg(not(feature = "flutter"))] let mut key_confirmed = false; let mut rx = rx; let mut mouse_time = 0; + #[cfg(not(feature = "flutter"))] let mut id = "".to_owned(); + #[cfg(target_os = "windows")] let mut enable_file_transfer = "".to_owned(); loop { @@ -874,9 +893,10 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver { mouse_time = v; - UI_STATUS.lock().unwrap().2 = v; + UI_STATUS.lock().unwrap().mouse_time = v; } Ok(Some(ipc::Data::Options(Some(v)))) => { *OPTIONS.lock().unwrap() = v; @@ -893,17 +913,31 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver { if name == "id" { - id = value; + #[cfg(not(feature = "flutter"))] + { + id = value; + } } else if name == "temporary-password" { *TEMPORARY_PASSWD.lock().unwrap() = value; } } - Ok(Some(ipc::Data::OnlineStatus(Some((mut x, c))))) => { + Ok(Some(ipc::Data::OnlineStatus(Some((mut x, _c))))) => { if x > 0 { x = 1 } - key_confirmed = c; - *UI_STATUS.lock().unwrap() = (x as _, key_confirmed, mouse_time, id.clone()); + #[cfg(not(feature = "flutter"))] + { + key_confirmed = _c; + } + *UI_STATUS.lock().unwrap() = UiStatus { + status_num: x as _, + #[cfg(not(feature = "flutter"))] + key_confirmed: _c, + #[cfg(not(any(target_os = "android", target_os = "ios")))] + mouse_time, + #[cfg(not(feature = "flutter"))] + id: id.clone(), + }; } _ => {} } @@ -927,7 +961,15 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver