From 88764d763c7cc6ae1b96a51354c1ba705dbe28a0 Mon Sep 17 00:00:00 2001 From: Tunglies Date: Sun, 8 Feb 2026 21:05:07 +0800 Subject: [PATCH] refactor(tray): simplify tray event handling and improve menu event processing (#6278) * refactor(tray): simplify tray event handling and improve menu event processing * refactor(tray): enhance error handling in tray menu and icon updates * refactor(tray): enhance tray icon event handling and add debounce for click events * fix: remove duplicated set tooltip * refactor(tray): simplify tray icon event handling by removing redundant parameters --- src-tauri/src/core/tray/mod.rs | 197 ++++++++++++++++++--------------- 1 file changed, 107 insertions(+), 90 deletions(-) diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index b6f18dd57..1e7b29405 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -10,7 +10,8 @@ use crate::{ utils::dirs::find_target_icons, }; use clash_verge_limiter::{Limiter, SystemClock, SystemLimiter}; -use tauri::tray::TrayIconBuilder; +use clash_verge_logging::logging_error; +use tauri::tray::{MouseButton, MouseButtonState, TrayIcon, TrayIconBuilder, TrayIconEvent}; use tauri_plugin_clash_verge_sysinfo::is_current_app_handle_admin; use tauri_plugin_mihomo::models::Proxies; use tokio::fs; @@ -23,7 +24,6 @@ use std::time::Duration; use tauri::{ AppHandle, Wry, menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, PredefinedMenuItem, Submenu}, - tray::{MouseButton, MouseButtonState, TrayIconEvent}, }; mod menu_def; use menu_def::{MenuIds, MenuTexts}; @@ -202,6 +202,11 @@ impl Tray { } async fn update_menu_internal(&self, app_handle: &AppHandle) -> Result<()> { + let Some(tray) = app_handle.tray_by_id("main") else { + logging!(warn, Type::Tray, "Failed to update tray menu: tray not found"); + return Ok(()); + }; + 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); @@ -222,28 +227,24 @@ impl Tray { let profiles_preview = profiles_arc.profiles_preview().unwrap_or_default(); let is_lightweight_mode = is_in_lightweight_mode(); - match app_handle.tray_by_id("main") { - Some(tray) => { - let _ = tray.set_menu(Some( - create_tray_menu( - app_handle, - Some(mode.as_str()), - *system_proxy, - *tun_mode, - tun_mode_available, - profiles_preview, - is_lightweight_mode, - ) - .await?, - )); - logging!(debug, Type::Tray, "托盘菜单更新成功"); - Ok(()) - } - None => { - logging!(warn, Type::Tray, "Failed to update tray menu: tray not found"); - Ok(()) - } - } + 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, + is_lightweight_mode, + ) + .await?, + )) + ); + + logging!(debug, Type::Tray, "托盘菜单更新成功"); + Ok(()) } /// 更新托盘图标 @@ -256,12 +257,9 @@ impl Tray { let app_handle = handle::Handle::app_handle(); - let tray = match app_handle.tray_by_id("main") { - Some(tray) => tray, - None => { - logging!(warn, Type::Tray, "Failed to update tray icon: tray not found"); - return Ok(()); - } + let Some(tray) = app_handle.tray_by_id("main") else { + logging!(warn, Type::Tray, "Failed to update tray icon: tray not found"); + return Ok(()); }; let (_is_custom_icon, icon_bytes) = TrayState::get_tray_icon(verge).await; @@ -269,8 +267,11 @@ impl Tray { let colorful = verge.tray_icon.clone().unwrap_or_else(|| "monochrome".into()); let is_colorful = colorful == "colorful"; - let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&icon_bytes)?)); - let _ = tray.set_icon_as_template(!is_colorful); + logging_error!( + Type::Tray, + tray.set_icon(Some(tauri::image::Image::from_bytes(&icon_bytes)?)) + ); + logging_error!(Type::Tray, tray.set_icon_as_template(!is_colorful)); Ok(()) } @@ -283,17 +284,17 @@ impl Tray { let app_handle = handle::Handle::app_handle(); - let tray = match app_handle.tray_by_id("main") { - Some(tray) => tray, - None => { - logging!(warn, Type::Tray, "Failed to update tray icon: tray not found"); - return Ok(()); - } + let Some(tray) = app_handle.tray_by_id("main") else { + logging!(warn, Type::Tray, "Failed to update tray icon: tray not found"); + return Ok(()); }; let (_is_custom_icon, icon_bytes) = TrayState::get_tray_icon(verge).await; - let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&icon_bytes)?)); + logging_error!( + Type::Tray, + tray.set_icon(Some(tauri::image::Image::from_bytes(&icon_bytes)?)) + ); Ok(()) } @@ -353,11 +354,12 @@ impl Tray { current_profile_name ); - if let Some(tray) = app_handle.tray_by_id("main") { - let _ = tray.set_tooltip(Some(&tooltip)); - } else { + let Some(tray) = app_handle.tray_by_id("main") else { logging!(warn, Type::Tray, "Failed to update tray tooltip: tray not found"); - } + return Ok(()); + }; + + logging_error!(Type::Tray, tray.set_tooltip(Some(&tooltip))); Ok(()) } @@ -409,49 +411,7 @@ impl Tray { } let tray = builder.build(app_handle)?; - let tray_event = verge.tray_event.clone().unwrap_or_else(|| "main_window".into()); - let tray_action = TrayAction::from(tray_event.as_str()); - - tray.on_tray_icon_event(move |_app_handle, event| { - if matches!(tray_action, TrayAction::Unknown) { - return; - } - if let TrayIconEvent::Click { - button: MouseButton::Left, - button_state: MouseButtonState::Down, - .. - } = event - { - // 添加防抖检查,防止快速连击 - #[allow(clippy::use_self)] - if !Tray::global().should_handle_tray_click() { - return; - } - logging!(debug, Type::Tray, "tray event: {tray_action:?}"); - match tray_action { - TrayAction::SystemProxy => { - AsyncHandler::spawn(|| async move { - let _ = feat::toggle_system_proxy().await; - }); - } - TrayAction::TunMode => { - AsyncHandler::spawn(|| async move { - let _ = feat::toggle_tun_mode(None).await; - }); - } - TrayAction::MainWindow => { - AsyncHandler::spawn(|| async move { - if !lightweight::exit_lightweight_mode().await { - WindowManager::show_main_window().await; - }; - }); - } - _ => { - logging!(warn, Type::Tray, "invalid tray event: {}", tray_event); - } - }; - } - }); + tray.on_tray_icon_event(on_tray_icon_event); tray.on_menu_event(on_menu_event); Ok(()) } @@ -923,14 +883,68 @@ async fn create_tray_menu( Ok(menu) } +fn on_tray_icon_event(_tray_icon: &TrayIcon, tray_event: TrayIconEvent) { + if matches!( + tray_event, + TrayIconEvent::Move { .. } | TrayIconEvent::Leave { .. } | TrayIconEvent::Enter { .. } + ) { + return; + } + + if let TrayIconEvent::Click { + button: MouseButton::Left, + button_state: MouseButtonState::Down, + .. + } = tray_event + { + // 添加防抖检查,防止快速连击 + #[allow(clippy::use_self)] + if !Tray::global().should_handle_tray_click() { + return; + } + + AsyncHandler::spawn(|| async move { + let verge = Config::verge().await.data_arc(); + let verge_tray_event = verge.tray_event.clone().unwrap_or_else(|| "main_window".into()); + let verge_tray_action = TrayAction::from(verge_tray_event.as_str()); + logging!(debug, Type::Tray, "tray event: {verge_tray_action:?}"); + match verge_tray_action { + TrayAction::SystemProxy => { + let _ = feat::toggle_system_proxy().await; + } + TrayAction::TunMode => { + let _ = feat::toggle_tun_mode(None).await; + } + TrayAction::MainWindow => { + if !lightweight::exit_lightweight_mode().await { + WindowManager::show_main_window().await; + }; + } + _ => { + logging!(warn, Type::Tray, "invalid tray event: {}", verge_tray_event); + } + }; + }); + } +} + fn on_menu_event(_: &AppHandle, event: MenuEvent) { + if !Tray::global().should_handle_tray_click() { + return; + } + if event.id.as_ref().is_empty() { + return; + } AsyncHandler::spawn(|| async move { match event.id.as_ref() { mode @ (MenuIds::RULE_MODE | MenuIds::GLOBAL_MODE | MenuIds::DIRECT_MODE) => { // Removing the the "tray_" prefix and "_mode" suffix - let mode = &mode[5..mode.len() - 5]; - logging!(info, Type::ProxyMode, "Switch Proxy Mode To: {}", mode); - feat::change_clash_mode(mode.into()).await; + if let Some(stripped) = mode.strip_prefix("tray_") + && let Some(final_mode) = stripped.strip_suffix("_mode") + { + logging!(info, Type::ProxyMode, "Switch Proxy Mode To: {}", final_mode); + feat::change_clash_mode(final_mode.into()).await; + } } MenuIds::DASHBOARD => { logging!(info, Type::Tray, "托盘菜单点击: 打开窗口"); @@ -978,7 +992,10 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) { feat::quit().await; } id if id.starts_with("profiles_") => { - let profile_index = &id["profiles_".len()..]; + let profile_index = match id.strip_prefix("profiles_") { + Some(index_str) => index_str, + None => return, + }; feat::toggle_proxy_profile(profile_index.into()).await; } id if id.starts_with("proxy_") => {