diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index 3d7f0aaf5..15e3ff089 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -1,4 +1,4 @@ -use crate::config::{IProfilePreview, IVerge}; +use crate::config::{IProfilePreview, IProfiles, IVerge}; use crate::core::lightweight; use crate::core::tray::menu_def::TrayAction; use crate::process::AsyncHandler; @@ -41,7 +41,10 @@ const TRAY_CLICK_DEBOUNCE_MS: u64 = 300; pub const TRAY_ID: &str = "clash-verge-rev-tray"; #[derive(Clone, Copy)] -struct TrayMenuOptions { +struct TrayMenuOptions<'a> { + mode: Option<&'a str>, + system_proxy_enabled: bool, + tun_mode_enabled: bool, is_lightweight_mode: bool, include_proxy_groups: bool, } @@ -201,9 +204,8 @@ impl Tray { }; let verge = Config::verge().await.latest_arc(); - let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false); - let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false); - let tun_mode_available = crate::core::runstate::RUN_STATE.state().tun_capable(); + let system_proxy = verge.enable_system_proxy.unwrap_or(false); + let tun_mode = verge.enable_tun_mode.unwrap_or(false); let mode = { Config::clash() .await @@ -214,29 +216,73 @@ impl Tray { .unwrap_or("rule") .to_owned() }; - let profiles_config = Config::profiles().await; - let profiles_arc = profiles_config.latest_arc(); - let profiles_preview = profiles_arc.profiles_preview().unwrap_or_default(); let is_lightweight_mode = is_in_lightweight_mode(); - logging_error!( - Type::Tray, - tray.set_menu(Some( - create_tray_menu( - app_handle, - Some(mode.as_str()), - *system_proxy, - *tun_mode, - tun_mode_available, - profiles_preview, - TrayMenuOptions { - is_lightweight_mode, - include_proxy_groups, - }, - ) - .await?, - )) - ); + let fetch_proxy_groups = + include_proxy_groups && verge.tray_proxy_groups_display_mode.as_deref() != Some("disable"); + + // TODO: should update tray menu again when it was timeout error + let (proxy_nodes_data, runtime_proxy_groups_order) = if fetch_proxy_groups { + let proxy_nodes_data = + tokio::time::timeout(Duration::from_millis(1000), handle::Handle::mihomo().get_proxies()) + .await + .map_or(None, |res| res.ok()); + + let runtime = Config::runtime().await.latest_arc(); + let runtime_proxy_groups_order = runtime.config.as_ref().map(|config| { + config + .get("proxy-groups") + .and_then(|groups| groups.as_sequence()) + .map(|groups| { + groups + .iter() + .filter_map(|group| group.get("name")) + .filter_map(|name| name.as_str()) + .enumerate() + .map(|(index, name)| (name.into(), index)) + .collect::>() + }) + .unwrap_or_default() + }); + + (proxy_nodes_data, runtime_proxy_groups_order) + } else { + (None, None) + }; + + let verge = if fetch_proxy_groups { + Config::verge().await.latest_arc() + } else { + verge + }; + let profiles = Config::profiles().await.latest_arc(); + + let (tx, rx) = tokio::sync::oneshot::channel(); + let dispatch_handle = app_handle.clone(); + app_handle + .run_on_main_thread(move || { + let _ = tx.send((|| -> Result<()> { + let menu = build_tray_menu( + &dispatch_handle, + TrayMenuOptions { + mode: Some(mode.as_str()), + system_proxy_enabled: system_proxy, + tun_mode_enabled: tun_mode, + is_lightweight_mode, + include_proxy_groups, + }, + &verge, + &profiles, + runtime_proxy_groups_order, + proxy_nodes_data, + )?; + logging_error!(Type::Tray, tray.set_menu(Some(menu))); + Ok(()) + })()); + }) + .map_err(|e| anyhow::anyhow!("Failed to dispatch tray menu update: {e}"))?; + rx.await + .map_err(|_| anyhow::anyhow!("Tray menu update returned no result"))??; logging!(debug, Type::Tray, "托盘菜单更新成功"); Ok(()) @@ -585,53 +631,16 @@ fn create_proxy_menu_item( Ok((proxies_submenu, inline_proxy_items)) } -async fn create_tray_menu( +fn build_tray_menu( app_handle: &AppHandle, - mode: Option<&str>, - system_proxy_enabled: bool, - tun_mode_enabled: bool, - tun_mode_available: bool, - profiles_preview: Vec>, - options: TrayMenuOptions, + options: TrayMenuOptions<'_>, + verge_settings: &IVerge, + profiles_config: &IProfiles, + proxy_group_order_map: Option>, + proxy_nodes_data: Option, ) -> Result> { - let current_proxy_mode = mode.unwrap_or(""); - - let mut verge_settings = Config::verge().await.latest_arc(); - let fetch_proxy_groups = - options.include_proxy_groups && verge_settings.tray_proxy_groups_display_mode.as_deref() != Some("disable"); - - // TODO: should update tray menu again when it was timeout error - let (proxy_nodes_data, runtime_proxy_groups_order) = if fetch_proxy_groups { - let proxy_nodes_data = - tokio::time::timeout(Duration::from_millis(1000), handle::Handle::mihomo().get_proxies()) - .await - .map_or(None, |res| res.ok()); - - let runtime = Config::runtime().await.latest_arc(); - let runtime_proxy_groups_order = runtime.config.as_ref().map(|config| { - config - .get("proxy-groups") - .and_then(|groups| groups.as_sequence()) - .map(|groups| { - groups - .iter() - .filter_map(|group| group.get("name")) - .filter_map(|name| name.as_str()) - .enumerate() - .map(|(index, name)| (name.into(), index)) - .collect::>() - }) - .unwrap_or_default() - }); - - (proxy_nodes_data, runtime_proxy_groups_order) - } else { - (None, None) - }; - - if fetch_proxy_groups { - verge_settings = Config::verge().await.latest_arc(); - } + let current_proxy_mode = options.mode.unwrap_or(""); + let tun_mode_available = crate::core::runstate::RUN_STATE.state().tun_capable(); let tray_proxy_groups_display_mode = verge_settings .tray_proxy_groups_display_mode @@ -639,15 +648,14 @@ async fn create_tray_menu( .unwrap_or("default"); let include_proxy_groups = options.include_proxy_groups && tray_proxy_groups_display_mode != "disable"; - let proxy_group_order_map = runtime_proxy_groups_order; - let show_outbound_modes_inline = verge_settings.tray_inline_outbound_modes.unwrap_or(false); let version = env!("CARGO_PKG_VERSION"); let hotkeys = create_hotkeys(&verge_settings.hotkeys); - let profile_menu_items: Vec> = create_profile_menu_item(app_handle, profiles_preview)?; + let profile_menu_items: Vec> = + create_profile_menu_item(app_handle, profiles_config.profiles_preview().unwrap_or_default())?; let texts = MenuTexts::new(); let profile_menu_items_refs: Vec<&dyn IsMenuItem> = profile_menu_items @@ -738,7 +746,7 @@ async fn create_tray_menu( MenuIds::SYSTEM_PROXY, &texts.system_proxy, true, - system_proxy_enabled, + options.system_proxy_enabled, hotkeys.get("toggle_system_proxy").copied(), )?; @@ -747,7 +755,7 @@ async fn create_tray_menu( MenuIds::TUN_MODE, &texts.tun_mode, tun_mode_available, - tun_mode_enabled, + options.tun_mode_enabled, hotkeys.get("toggle_tun_mode").copied(), )?;