diff --git a/flutter/lib/common/widgets/address_book.dart b/flutter/lib/common/widgets/address_book.dart index 08df6d4e5..9a516653b 100644 --- a/flutter/lib/common/widgets/address_book.dart +++ b/flutter/lib/common/widgets/address_book.dart @@ -30,6 +30,7 @@ class _AddressBookState extends State { @override Widget build(BuildContext context) => Obx(() { + debugPrint('REMOVE ME =========================== AddressBook ${gFFI.userModel.userName.value} ${gFFI.abModel.abLoading} ${gFFI.abModel.abError} ${gFFI.abModel.fromServer} ${isDesktop}'); if (gFFI.userModel.userName.value.isEmpty) { return Center( child: ElevatedButton( diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 91d6b6032..f37bb8d9f 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -1,7 +1,5 @@ // main window right pane -import 'dart:async'; -import 'dart:convert'; import 'dart:io'; import 'package:auto_size_text/auto_size_text.dart'; @@ -9,7 +7,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 +34,10 @@ class _ConnectionPageState extends State /// Nested scroll controller final _scrollController = ScrollController(); - Timer? _updateTimer; - final RxBool _idInputFocused = false.obs; final FocusNode _idFocusNode = FocusNode(); var svcStopped = Get.find(tag: 'stop-service'); - var svcIsUsingPublicServer = true.obs; bool isWindowMinimized = false; @@ -60,9 +54,7 @@ class _ConnectionPageState extends State } }(); } - _updateTimer = periodic_immediate(Duration(seconds: 1), () async { - updateStatus(); - }); + stateGlobal.startSvcStatusTimer(); _idFocusNode.addListener(() { _idInputFocused.value = _idFocusNode.hasFocus; // select all to faciliate removing text, just following the behavior of address input of chrome @@ -75,7 +67,7 @@ class _ConnectionPageState extends State @override void dispose() { _idController.dispose(); - _updateTimer?.cancel(); + stateGlobal.cancelSvcStatusTimer(); windowManager.removeListener(this); super.dispose(); } @@ -290,7 +282,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: [ @@ -329,31 +321,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/connection_page.dart b/flutter/lib/mobile/pages/connection_page.dart index 5a581f0c7..df4a85233 100644 --- a/flutter/lib/mobile/pages/connection_page.dart +++ b/flutter/lib/mobile/pages/connection_page.dart @@ -11,6 +11,7 @@ import '../../common/widgets/login.dart'; import '../../common/widgets/peer_tab_page.dart'; import '../../consts.dart'; import '../../models/model.dart'; +import '../../models/state_model.dart'; import '../../models/platform_model.dart'; import 'home_page.dart'; import 'scan_page.dart'; @@ -54,6 +55,7 @@ class _ConnectionPageState extends State { } }(); } + stateGlobal.startSvcStatusTimer(); if (isAndroid) { Timer(const Duration(seconds: 5), () async { _updateUrl = await bind.mainGetSoftwareUpdateUrl(); @@ -180,6 +182,7 @@ class _ConnectionPageState extends State { @override void dispose() { _idController.dispose(); + stateGlobal.cancelSvcStatusTimer(); super.dispose(); } } diff --git a/flutter/lib/models/ab_model.dart b/flutter/lib/models/ab_model.dart index 8bcb3f7a6..13b153891 100644 --- a/flutter/lib/models/ab_model.dart +++ b/flutter/lib/models/ab_model.dart @@ -57,6 +57,7 @@ class AbModel { return ""; } } catch (err) { + debugPrint('REMOVE ME ====================== err $err'); err.printError(); abError.value = err.toString(); } finally { diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index f7b4f8cc2..825a73751 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -1,10 +1,16 @@ +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'; +import './user_model.dart'; enum SvcStatus { notReady, connecting, ready } @@ -18,7 +24,10 @@ 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; + Timer? _svcStatusTimer; // Use for desktop -> remote toolbar -> resolution final Map> _lastResolutionGroupValues = {}; @@ -84,6 +93,46 @@ class StateGlobal { } } + startSvcStatusTimer() { + _svcStatusTimer = periodic_immediate(Duration(seconds: 1), () async { + _updateSvcStatus(); + }); + } + + cancelSvcStatusTimer() { + _svcStatusTimer?.cancel(); + _svcStatusTimer = null; + } + + _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(); + } + debugPrint('REMOVE ME ========================== $preStatus -> ${stateGlobal.svcStatus.value}'); + if (preStatus != stateGlobal.svcStatus.value) { + UserModel.updateOtherModels(); + } + 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..73fbdc9d1 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, get_online_statue, 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 = get_online_statue(); + if state > 0 { + state = 1; + } + serde_json::json!({ "status_num": get_online_statue() }).to_string() + } } pub fn main_check_connect_status() { @@ -996,7 +999,7 @@ pub fn main_get_fingerprint() -> String { } pub fn main_get_online_statue() -> i64 { - ONLINE.lock().unwrap().values().max().unwrap_or(&0).clone() + get_online_statue() } pub fn cm_get_clients_state() -> String { @@ -1194,7 +1197,15 @@ pub fn main_check_mouse_time() { } pub fn main_get_mouse_time() -> f64 { - get_mouse_time() + let mut mouse_time = 0.0; + #[cfg(all( + not(any(target_os = "android", target_os = "ios")), + feature = "flutter" + ))] + { + mouse_time = get_mouse_time(); + } + mouse_time } pub fn main_wol(id: String) { diff --git a/src/ipc.rs b/src/ipc.rs index 83a48107c..29adb6740 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -186,6 +186,10 @@ pub enum Data { }, SystemInfo(Option), ClickTime(i64), + #[cfg(all( + not(any(target_os = "android", target_os = "ios")), + feature = "flutter" + ))] MouseMoveTime(i64), Authorize, Close, @@ -332,6 +336,10 @@ 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(all( + not(any(target_os = "android", target_os = "ios")), + feature = "flutter" + ))] Data::MouseMoveTime(_) => { let t = crate::server::MOUSE_MOVE_TIME.load(Ordering::SeqCst); allow_err!(stream.send(&Data::MouseMoveTime(t)).await); @@ -345,13 +353,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..5eb86808a 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -63,6 +63,10 @@ lazy_static::lazy_static! { static ref SWITCH_SIDES_UUID: Arc::>> = Default::default(); } pub static CLICK_TIME: AtomicI64 = AtomicI64::new(0); +#[cfg(all( + not(any(target_os = "android", target_os = "ios")), + feature = "flutter" +))] pub static MOUSE_MOVE_TIME: AtomicI64 = AtomicI64::new(0); #[cfg(all(feature = "flutter", feature = "plugin_framework"))] @@ -163,6 +167,7 @@ pub struct Connection { // by peer disable_audio: bool, // by peer + #[cfg(windows)] enable_file_transfer: bool, // by peer audio_sender: Option, @@ -291,6 +296,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 +1118,7 @@ impl Connection { self.audio && !self.disable_audio } + #[cfg(windows)] fn file_transfer_enabled(&self) -> bool { self.file && self.enable_file_transfer } @@ -1563,6 +1570,10 @@ impl Connection { if is_left_up(&me) { CLICK_TIME.store(get_time(), Ordering::SeqCst); } else { + #[cfg(all( + not(any(target_os = "android", target_os = "ios")), + feature = "flutter" + ))] MOUSE_MOVE_TIME.store(get_time(), Ordering::SeqCst); } self.input_mouse(me, self.inner.id()); 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_interface.rs b/src/ui_interface.rs index e298e1167..7ce9a0000 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,34 @@ 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(all( + not(any(target_os = "android", target_os = "ios")), + feature = "flutter" + ))] + 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(all( + not(any(target_os = "android", target_os = "ios")), + feature = "flutter" + ))] + 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,15 +417,20 @@ pub fn is_installed_lower_version() -> bool { } #[inline] +#[cfg(all( + not(any(target_os = "android", target_os = "ios")), + feature = "flutter" +))] 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] pub fn check_mouse_time() { - #[cfg(not(any(target_os = "android", target_os = "ios")))] + #[cfg(all( + not(any(target_os = "android", target_os = "ios")), + feature = "flutter" + ))] { let sender = SENDER.lock().unwrap(); allow_err!(sender.send(ipc::Data::MouseMoveTime(0))); @@ -409,10 +438,8 @@ 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 +pub fn get_connect_status() -> UiStatus { + UI_STATUS.lock().unwrap().clone() } #[inline] @@ -874,9 +901,13 @@ 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; @@ -902,8 +933,18 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver 0 { x = 1 } - key_confirmed = c; - *UI_STATUS.lock().unwrap() = (x as _, key_confirmed, mouse_time, id.clone()); + *UI_STATUS.lock().unwrap() = UiStatus { + status_num: x as _, + #[cfg(not(feature = "flutter"))] + key_confirmed: c, + #[cfg(all( + not(any(target_os = "android", target_os = "ios")), + feature = "flutter" + ))] + mouse_time, + #[cfg(not(feature = "flutter"))] + id: id.clone(), + }; } _ => {} } @@ -927,7 +968,18 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver