From 70bd5ec03c13af27a1733de48601fae10ff34240 Mon Sep 17 00:00:00 2001 From: Tunglies Date: Thu, 27 Mar 2025 12:04:52 +0800 Subject: [PATCH] refactor: simplify tray icon handling and update return types for icon functions fix: custom tray icon with speedrate display large gap --- UPDATELOG.md | 3 +- src-tauri/src/core/tray/mod.rs | 96 ++++++++++++++------------- src-tauri/src/core/tray/speed_rate.rs | 22 +++--- 3 files changed, 63 insertions(+), 58 deletions(-) diff --git a/UPDATELOG.md b/UPDATELOG.md index 9f603905..168e45c7 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -6,7 +6,8 @@ ### 2.2.3-alpha 相对于 2.2.2 #### 修复了: - 首页“当前代理”因为重复刷新导致的CPU占用过高的问题 - - 托盘图标无法自定义 + - 自定义托盘图标未能应用更改 + - MacOS 自定义托盘图标显示速率时图标和文本间隙过大 #### 新增了: - ClashVergeRev 从现在开始不再强依赖系统服务和管理权限 diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index 7286876c..7251e732 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -20,12 +20,8 @@ use parking_lot::Mutex; use parking_lot::RwLock; #[cfg(target_os = "macos")] pub use speed_rate::{SpeedRate, Traffic}; -#[cfg(target_os = "macos")] -use std::collections::hash_map::DefaultHasher; use std::fs; #[cfg(target_os = "macos")] -use std::hash::{Hash, Hasher}; -#[cfg(target_os = "macos")] use std::sync::Arc; use tauri::{ menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, PredefinedMenuItem, Submenu}, @@ -45,10 +41,7 @@ pub struct Tray { pub speed_rate: Arc>>, shutdown_tx: Arc>>>, is_subscribed: Arc>, - pub icon_hash: Arc>>, - pub icon_cache: Arc>>>, pub rate_cache: Arc>>, - // pub tray_state: Arc>, } #[cfg(not(target_os = "macos"))] @@ -57,77 +50,104 @@ pub struct Tray { } impl TrayState { - pub fn get_common_tray_icon() -> Vec { + pub fn get_common_tray_icon() -> (bool, Vec) { let verge = Config::verge().latest().clone(); let is_common_tray_icon = verge.common_tray_icon.clone().unwrap_or(false); if is_common_tray_icon { if let Some(common_icon_path) = find_target_icons("common").unwrap() { let icon_data = fs::read(common_icon_path).unwrap(); - return icon_data; + return (true, icon_data); } } #[cfg(target_os = "macos")] { let tray_icon_colorful = verge.tray_icon.clone().unwrap_or("monochrome".to_string()); if tray_icon_colorful == "monochrome" { - include_bytes!("../../../icons/tray-icon.ico").to_vec() + ( + false, + include_bytes!("../../../icons/tray-icon-mono.ico").to_vec(), + ) } else { - include_bytes!("../../../icons/tray-icon-mono.ico").to_vec() + ( + false, + include_bytes!("../../../icons/tray-icon.ico").to_vec(), + ) } } #[cfg(not(target_os = "macos"))] { - include_bytes!("../../../icons/tray-icon.ico").to_vec() + ( + false, + include_bytes!("../../../icons/tray-icon.ico").to_vec(), + ) } } - pub fn get_sysproxy_tray_icon() -> Vec { + pub fn get_sysproxy_tray_icon() -> (bool, Vec) { let verge = Config::verge().latest().clone(); let is_sysproxy_tray_icon = verge.sysproxy_tray_icon.clone().unwrap_or(false); if is_sysproxy_tray_icon { if let Some(sysproxy_icon_path) = find_target_icons("sysproxy").unwrap() { let icon_data = fs::read(sysproxy_icon_path).unwrap(); - return icon_data; + return (true, icon_data); } } #[cfg(target_os = "macos")] { let tray_icon_colorful = verge.tray_icon.clone().unwrap_or("monochrome".to_string()); if tray_icon_colorful == "monochrome" { - include_bytes!("../../../icons/tray-icon-sys.ico").to_vec() + ( + false, + include_bytes!("../../../icons/tray-icon-sys-mono.ico").to_vec(), + ) } else { - include_bytes!("../../../icons/tray-icon-sys-mono.ico").to_vec() + ( + false, + include_bytes!("../../../icons/tray-icon-sys.ico").to_vec(), + ) } } #[cfg(not(target_os = "macos"))] { - include_bytes!("../../../icons/tray-icon-sys.ico").to_vec() + ( + false, + include_bytes!("../../../icons/tray-icon-sys.ico").to_vec(), + ) } } - pub fn get_tun_tray_icon() -> Vec { + pub fn get_tun_tray_icon() -> (bool, Vec) { let verge = Config::verge().latest().clone(); let is_tun_tray_icon = verge.tun_tray_icon.clone().unwrap_or(false); if is_tun_tray_icon { if let Some(tun_icon_path) = find_target_icons("tun").unwrap() { let icon_data = fs::read(tun_icon_path).unwrap(); - return icon_data; + return (true, icon_data); } } #[cfg(target_os = "macos")] { let tray_icon_colorful = verge.tray_icon.clone().unwrap_or("monochrome".to_string()); if tray_icon_colorful == "monochrome" { - include_bytes!("../../../icons/tray-icon-tun.ico").to_vec() + ( + false, + include_bytes!("../../../icons/tray-icon-tun-mono.ico").to_vec(), + ) } else { - include_bytes!("../../../icons/tray-icon-tun-mono.ico").to_vec() + ( + false, + include_bytes!("../../../icons/tray-icon-tun.ico").to_vec(), + ) } } #[cfg(not(target_os = "macos"))] { - include_bytes!("../../../icons/tray-icon-tun.ico").to_vec() + ( + false, + include_bytes!("../../../icons/tray-icon-tun.ico").to_vec(), + ) } } } @@ -141,8 +161,6 @@ impl Tray { speed_rate: Arc::new(Mutex::new(None)), shutdown_tx: Arc::new(RwLock::new(None)), is_subscribed: Arc::new(RwLock::new(false)), - icon_hash: Arc::new(Mutex::new(None)), - icon_cache: Arc::new(Mutex::new(None)), rate_cache: Arc::new(Mutex::new(None)), }); @@ -251,13 +269,12 @@ impl Tray { let app_handle = handle::Handle::global().app_handle().unwrap(); let tray = app_handle.tray_by_id("main").unwrap(); - let icon_bytes = match (*system_mode, *tun_mode) { + let (is_custom_icon, icon_bytes) = match (*system_mode, *tun_mode) { (true, true) => TrayState::get_tun_tray_icon(), (true, false) => TrayState::get_sysproxy_tray_icon(), (false, true) => TrayState::get_tun_tray_icon(), (false, false) => TrayState::get_common_tray_icon(), }; - #[cfg(target_os = "macos")] { let enable_tray_speed = verge.enable_tray_speed.unwrap_or(true); @@ -265,23 +282,8 @@ impl Tray { let colorful = verge.tray_icon.clone().unwrap_or("monochrome".to_string()); let is_colorful = colorful == "colorful"; - let icon_hash = { - let mut hasher = DefaultHasher::new(); - icon_bytes.clone().hash(&mut hasher); - hasher.finish() - }; - - let mut icon_hash_guard = self.icon_hash.lock(); - let mut icon_bytes_guard = self.icon_cache.lock(); - if *icon_hash_guard != Some(icon_hash) { - *icon_hash_guard = Some(icon_hash); - *icon_bytes_guard = Some(icon_bytes.clone()); - } - if !enable_tray_speed { - let _ = tray.set_icon(Some(tauri::image::Image::from_bytes( - &(*icon_bytes_guard).clone().unwrap(), - )?)); + let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&icon_bytes)?)); let _ = tray.set_icon_as_template(!is_colorful); return Ok(()); } @@ -302,16 +304,20 @@ impl Tray { *rate_guard = rate; let bytes = if enable_tray_icon { - Some(icon_bytes_guard.as_ref().unwrap()) + Some(icon_bytes) } else { None }; let rate = rate_guard.as_ref(); - let rate_bytes = SpeedRate::add_speed_text(bytes, rate).unwrap(); + let rate_bytes = SpeedRate::add_speed_text(is_custom_icon, bytes, rate).unwrap(); let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&rate_bytes)?)); - let _ = tray.set_icon_as_template(!is_colorful); + if !is_custom_icon { + let _ = tray.set_icon_as_template(!is_colorful); + } else { + let _ = tray.set_icon_as_template(false); + } } Ok(()) } diff --git a/src-tauri/src/core/tray/speed_rate.rs b/src-tauri/src/core/tray/speed_rate.rs index 089d8157..8af0acca 100644 --- a/src-tauri/src/core/tray/speed_rate.rs +++ b/src-tauri/src/core/tray/speed_rate.rs @@ -77,14 +77,15 @@ impl SpeedRate { // 分离图标加载和速率渲染 pub fn add_speed_text<'a>( - icon_bytes: Option<&'a Vec>, + is_custom_icon: bool, + icon_bytes: Option>, rate: Option<&'a Rate>, ) -> Result> { let rate = rate.unwrap_or(&Rate { up: 0, down: 0 }); let (mut icon_width, mut icon_height) = (0, 256); - let icon_image = if let Some(bytes) = icon_bytes { - let icon_image = image::load_from_memory(bytes)?; + let icon_image = if let Some(bytes) = icon_bytes.clone() { + let icon_image = image::load_from_memory(&bytes)?; icon_width = icon_image.width(); icon_height = icon_image.height(); icon_image @@ -94,19 +95,16 @@ impl SpeedRate { }; // 判断是否为彩色图标 - let is_colorful = if let Some(bytes) = icon_bytes { - !crate::utils::help::is_monochrome_image_from_bytes(bytes).unwrap_or(false) + let is_colorful = if let Some(bytes) = icon_bytes.clone() { + !crate::utils::help::is_monochrome_image_from_bytes(&bytes).unwrap_or(false) } else { false }; - // 增加文本宽度和间距 - let total_width = if icon_bytes.is_some() { - if icon_width < 580 { - icon_width + 580 - } else { - icon_width - } + let total_width = if is_custom_icon { + 450 + } else if icon_bytes.is_some() { + icon_width + 580 } else { 580 };