diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index 9fe70b12..d9b6ce2c 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -22,6 +22,7 @@ pub fn copy_clash_env() -> CmdResult { #[tauri::command] pub fn get_profiles() -> CmdResult { + let _ = tray::Tray::global().update_menu(); Ok(Config::profiles().data().clone()) } @@ -62,7 +63,6 @@ pub async fn delete_profile(index: String) -> CmdResult { wrap_err!(CoreManager::global().update_config().await)?; handle::Handle::refresh_clash(); } - Ok(()) } @@ -70,7 +70,6 @@ pub async fn delete_profile(index: String) -> CmdResult { #[tauri::command] pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult { wrap_err!({ Config::profiles().draft().patch_config(profiles) })?; - match CoreManager::global().update_config().await { Ok(_) => { handle::Handle::refresh_clash(); @@ -87,6 +86,14 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult { } } +/// 根据profile name修改profiles +#[tauri::command] +pub async fn patch_profiles_config_by_profile_name(profile_name: String) -> CmdResult { + let profile_id = Config::profiles().data().get_profile_uid(&profile_name); + let profiles = IProfiles{current: profile_id, items: None}; + patch_profiles_config(profiles).await +} + /// 修改某个profile item的 #[tauri::command] pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult { diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs index a535457b..97a13ef7 100644 --- a/src-tauri/src/config/profiles.rs +++ b/src-tauri/src/config/profiles.rs @@ -71,7 +71,6 @@ impl IProfiles { if let Some(current) = patch.current { let items = self.items.as_ref().unwrap(); let some_uid = Some(current); - if items.iter().any(|e| e.uid == some_uid) { self.current = some_uid; } @@ -465,4 +464,50 @@ impl IProfiles { _ => None, } } + + /// 获取current指向的profile名称 + pub fn current_profile_name(&self) -> Option { + match (self.current.as_ref(), self.items.as_ref()) { + (Some(current), Some(items)) => { + if let Some(item) = items.iter().find(|e| e.uid.as_ref() == Some(current)) { + return item.name.clone(); + } + None + } + _ => None, + } + } + + /// 判断profile是否是current指向的 + pub fn is_current_profile(&self, profile_name: &str) -> bool { + match self.current_profile_name() { + Some(current_profile_name) => current_profile_name == profile_name, + None => false, + } + } + + /// 根据profile名称获取uid + pub fn get_profile_uid(&self, profile_name: &str) -> Option { + match self.items.as_ref() { + Some(items) => { + for item in items.iter() { + if item.name.as_ref() == Some(&profile_name.to_string()) { + return item.uid.clone(); + } + } + None + } + None => None, + } + } + + + /// 获取所有的profiles称 + pub fn all_profile_names(&self) -> Option> { + log::info!(target: "app", "{:?}", self.get_items()); + match self.items.as_ref() { + Some(items) => Some(items.iter().filter_map(|e| e.name.clone()).collect()), + None => None, + } + } } diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index 78e13278..7910bf3e 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -21,7 +21,7 @@ use parking_lot::RwLock; pub use speed_rate::{SpeedRate, Traffic}; #[cfg(target_os = "macos")] use std::sync::Arc; -use tauri::menu::CheckMenuItem; +use tauri::menu::{CheckMenuItem, IsMenuItem}; use tauri::AppHandle; use tauri::{ menu::{MenuEvent, MenuItem, PredefinedMenuItem, Submenu}, @@ -124,6 +124,10 @@ impl Tray { .unwrap_or("rule") .to_owned() }; + let profile_names = Config::profiles() + .data() + .all_profile_names() + .unwrap_or(Vec::new()); let tray = app_handle.tray_by_id("main").unwrap(); let _ = tray.set_menu(Some(create_tray_menu( @@ -131,6 +135,7 @@ impl Tray { Some(mode.as_str()), *system_proxy, *tun_mode, + profile_names, )?)); Ok(()) } @@ -363,6 +368,7 @@ fn create_tray_menu( mode: Option<&str>, system_proxy_enabled: bool, tun_mode_enabled: bool, + profile_names: Vec, ) -> Result> { let mode = mode.unwrap_or(""); let version = VERSION.get().unwrap(); @@ -422,6 +428,33 @@ fn create_tray_menu( ) .unwrap(); + let profile_menu_items: Vec> = profile_names + .iter() + .map(|item| { + let is_current_profile = Config::profiles().data().is_current_profile(item); + CheckMenuItem::with_id( + app_handle, + &format!("profiles_{}", item), + t(&item), + true, + is_current_profile, + None::<&str>, + ) + .unwrap() + }).collect(); + let profile_menu_items: Vec<&dyn IsMenuItem> = profile_menu_items + .iter() + .map(|item| item as &dyn IsMenuItem) + .collect(); + + let profiles = &Submenu::with_id_and_items( + app_handle, + "profiles", + t("Profiles"), + true, + &profile_menu_items, + ).unwrap(); + let system_proxy = &CheckMenuItem::with_id( app_handle, "system_proxy", @@ -530,6 +563,8 @@ fn create_tray_menu( global_mode, direct_mode, separator, + profiles, + separator, system_proxy, tun_mode, copy_env, @@ -562,6 +597,10 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) { "quit" => { println!("quit"); feat::quit(Some(0)); + }, + id if id.starts_with("profiles_") => { + let profile_name = &id["profiles_".len()..]; + feat::toggle_proxy_profile(profile_name.into()); } _ => {} } diff --git a/src-tauri/src/feat.rs b/src-tauri/src/feat.rs index 821f3c37..0e14a9a9 100644 --- a/src-tauri/src/feat.rs +++ b/src-tauri/src/feat.rs @@ -4,6 +4,7 @@ //! - timer 定时器 //! - cmds 页面调用 //! +use crate::cmds; use crate::config::*; use crate::core::*; use crate::log_err; @@ -103,6 +104,19 @@ pub fn toggle_system_proxy() { }); } +// 切换代理文件 +pub fn toggle_proxy_profile(profile_name: String) { + tauri::async_runtime::spawn(async move { + match cmds::patch_profiles_config_by_profile_name(profile_name).await { + Ok(_) => { + let _ = tray::Tray::global().update_menu(); + handle::Handle::refresh_verge(); + }, + Err(err) => log::error!(target: "app", "{err}"), + } + }); +} + // 切换tun模式 pub fn toggle_tun_mode() { let enable = Config::verge().data().enable_tun_mode;