mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 06:43:44 +08:00
feat: enhance tray icon handling with caching and speed rate rendering
This commit is contained in:
parent
147e7d7390
commit
a1f671f380
@ -21,6 +21,10 @@ use parking_lot::RwLock;
|
|||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub use speed_rate::{SpeedRate, Traffic};
|
pub use speed_rate::{SpeedRate, Traffic};
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
use std::collections::hash_map::DefaultHasher;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, PredefinedMenuItem, Submenu},
|
menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, PredefinedMenuItem, Submenu},
|
||||||
@ -36,6 +40,9 @@ pub struct Tray {
|
|||||||
pub speed_rate: Arc<Mutex<Option<SpeedRate>>>,
|
pub speed_rate: Arc<Mutex<Option<SpeedRate>>>,
|
||||||
shutdown_tx: Arc<RwLock<Option<broadcast::Sender<()>>>>,
|
shutdown_tx: Arc<RwLock<Option<broadcast::Sender<()>>>>,
|
||||||
is_subscribed: Arc<RwLock<bool>>,
|
is_subscribed: Arc<RwLock<bool>>,
|
||||||
|
pub icon_hash: Arc<Mutex<Option<u64>>>,
|
||||||
|
pub icon_cache: Arc<Mutex<Option<Vec<u8>>>>,
|
||||||
|
pub rate_cache: Arc<Mutex<Option<Rate>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
@ -50,6 +57,9 @@ impl Tray {
|
|||||||
speed_rate: Arc::new(Mutex::new(None)),
|
speed_rate: Arc::new(Mutex::new(None)),
|
||||||
shutdown_tx: Arc::new(RwLock::new(None)),
|
shutdown_tx: Arc::new(RwLock::new(None)),
|
||||||
is_subscribed: Arc::new(RwLock::new(false)),
|
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)),
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
@ -228,34 +238,59 @@ impl Tray {
|
|||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
let enable_tray_speed = Config::verge().latest().enable_tray_speed.unwrap_or(true);
|
let enable_tray_speed = verge.enable_tray_speed.unwrap_or(true);
|
||||||
let is_colorful = tray_icon == "colorful";
|
let is_colorful = tray_icon == "colorful";
|
||||||
|
|
||||||
// 处理图标和速率
|
let icon_hash = {
|
||||||
let final_icon_bytes = if enable_tray_speed {
|
let mut hasher = DefaultHasher::new();
|
||||||
let rate = rate.or_else(|| {
|
icon_bytes.clone().hash(&mut hasher);
|
||||||
self.speed_rate
|
hasher.finish()
|
||||||
.lock()
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|speed_rate| speed_rate.get_curent_rate())
|
|
||||||
});
|
|
||||||
|
|
||||||
// 使用新的方法渲染图标和速率
|
|
||||||
SpeedRate::add_speed_text(icon_bytes, rate)?
|
|
||||||
} else {
|
|
||||||
icon_bytes
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 设置系统托盘图标
|
let mut icon_hash_guard = self.icon_hash.lock();
|
||||||
let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&final_icon_bytes)?));
|
let mut icon_bytes_guard = self.icon_cache.lock();
|
||||||
// 只对单色图标使用 template 模式
|
if *icon_hash_guard != Some(icon_hash) {
|
||||||
let _ = tray.set_icon_as_template(!is_colorful);
|
*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_as_template(!is_colorful);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let rate = if let Some(rate) = rate {
|
||||||
|
Some(rate)
|
||||||
|
} else {
|
||||||
|
let guard = self.speed_rate.lock();
|
||||||
|
if let Some(rate) = guard.as_ref().unwrap().get_curent_rate() {
|
||||||
|
Some(rate)
|
||||||
|
} else {
|
||||||
|
Some(Rate::default())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut rate_guard = self.rate_cache.lock();
|
||||||
|
if *rate_guard != rate {
|
||||||
|
*rate_guard = rate;
|
||||||
|
|
||||||
|
let bytes = icon_bytes_guard.as_ref().unwrap();
|
||||||
|
let rate = rate_guard.as_ref();
|
||||||
|
let rate_bytes = SpeedRate::add_speed_text(bytes, rate).unwrap();
|
||||||
|
let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&rate_bytes)?));
|
||||||
|
let _ = tray.set_icon_as_template(!is_colorful);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&icon_bytes)?));
|
{
|
||||||
|
let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&icon_bytes)?));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 更新托盘提示
|
/// 更新托盘提示
|
||||||
|
@ -15,7 +15,6 @@ use tungstenite::client::IntoClientRequest;
|
|||||||
pub struct SpeedRate {
|
pub struct SpeedRate {
|
||||||
rate: Arc<Mutex<(Rate, Rate)>>,
|
rate: Arc<Mutex<(Rate, Rate)>>,
|
||||||
last_update: Arc<Mutex<std::time::Instant>>,
|
last_update: Arc<Mutex<std::time::Instant>>,
|
||||||
// 移除 base_image,不再缓存原始图像
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpeedRate {
|
impl SpeedRate {
|
||||||
@ -77,20 +76,24 @@ impl SpeedRate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 分离图标加载和速率渲染
|
// 分离图标加载和速率渲染
|
||||||
pub fn add_speed_text(icon_bytes: Vec<u8>, rate: Option<Rate>) -> Result<Vec<u8>> {
|
pub fn add_speed_text<'a>(icon_bytes: &'a Vec<u8>, rate: Option<&'a Rate>) -> Result<Vec<u8>> {
|
||||||
let rate = rate.unwrap_or(Rate { up: 0, down: 0 });
|
let rate = rate.unwrap_or(&Rate { up: 0, down: 0 });
|
||||||
|
|
||||||
// 加载原始图标
|
// 加载原始图标
|
||||||
let icon_image = image::load_from_memory(&icon_bytes)?;
|
let icon_image = image::load_from_memory(icon_bytes)?;
|
||||||
let (icon_width, icon_height) = (icon_image.width(), icon_image.height());
|
let (icon_width, icon_height) = (icon_image.width(), icon_image.height());
|
||||||
|
|
||||||
// 判断是否为彩色图标
|
// 判断是否为彩色图标
|
||||||
let is_colorful =
|
let is_colorful =
|
||||||
!crate::utils::help::is_monochrome_image_from_bytes(&icon_bytes).unwrap_or(false);
|
!crate::utils::help::is_monochrome_image_from_bytes(icon_bytes).unwrap_or(false);
|
||||||
|
|
||||||
// 增加文本宽度和间距
|
// 增加文本宽度和间距
|
||||||
let text_width = 580; // 文本区域宽度
|
let total_width = if icon_width < 580 {
|
||||||
let total_width = icon_width + text_width;
|
let text_width = 580; // 文本区域宽度
|
||||||
|
icon_width + text_width
|
||||||
|
} else {
|
||||||
|
icon_width
|
||||||
|
};
|
||||||
|
|
||||||
// 创建新的透明画布
|
// 创建新的透明画布
|
||||||
let mut combined_image = RgbaImage::new(total_width, icon_height);
|
let mut combined_image = RgbaImage::new(total_width, icon_height);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user