diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index f4de6042..834feeb6 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -657,89 +657,81 @@ async fn create_tray_menu( if let Some(proxies) = proxy_nodes_data.get("proxies").and_then(|v| v.as_object()) { for (group_name, group_data) in proxies.iter() { - let group_type_wrap = group_data.get("type").and_then(|v| v.as_str()); - let all_proxies_wrap = group_data.get("all").and_then(|v| v.as_array()); - - if group_type_wrap.is_none() || all_proxies_wrap.is_none() { - continue; - } + if let (Some(group_type),Some(all_proxies)) = (group_data.get("type").and_then(|v| v.as_str()),group_data.get("all").and_then(|v| v.as_array())) { + // 在全局模式下只显示GLOBAL组,在规则模式下显示所有Selector类型的代理组 + let should_show_group = if mode == "global" { + group_name == "GLOBAL" + } else { + group_type == "Selector" && group_name != "GLOBAL" + }; + + if !should_show_group { + continue; + } - let group_type = group_type_wrap.unwrap(); - let all_proxies = all_proxies_wrap.unwrap(); - - // 在全局模式下只显示GLOBAL组,在规则模式下显示所有Selector类型的代理组 - let should_show_group = if mode == "global" { - group_name == "GLOBAL" - } else { - group_type == "Selector" && group_name != "GLOBAL" - }; - - if !should_show_group { - continue; - } - - let now_proxy = group_data.get("now").and_then(|v| v.as_str()).unwrap_or(""); - - // 为每个代理组创建子菜单项 - let mut group_items = Vec::new(); - for proxy_name in all_proxies.iter() { - if let Some(proxy_str) = proxy_name.as_str() { - let is_selected = proxy_str == now_proxy; - let item_id = format!("proxy_{}_{}", group_name, proxy_str); - - match CheckMenuItem::with_id( - app_handle, - item_id, - proxy_str, // 只显示节点名,不显示组名前缀 - true, - is_selected, - None::<&str>, - ) { - Ok(item) => group_items.push(item), - Err(e) => log::warn!(target: "app", "创建代理菜单项失败: {}", e), + let now_proxy = group_data.get("now").and_then(|v| v.as_str()).unwrap_or(""); + + // 为每个代理组创建子菜单项 + let mut group_items = Vec::new(); + for proxy_name in all_proxies.iter() { + if let Some(proxy_str) = proxy_name.as_str() { + let is_selected = proxy_str == now_proxy; + let item_id = format!("proxy_{}_{}", group_name, proxy_str); + + match CheckMenuItem::with_id( + app_handle, + item_id, + proxy_str, // 只显示节点名,不显示组名前缀 + true, + is_selected, + None::<&str>, + ) { + Ok(item) => group_items.push(item), + Err(e) => log::warn!(target: "app", "创建代理菜单项失败: {}", e), + } } } - } - - // 创建代理组子菜单 - if !group_items.is_empty() { - let group_items_refs: Vec<&dyn IsMenuItem> = group_items - .iter() - .map(|item| item as &dyn IsMenuItem) - .collect(); - // 判断当前代理组是否为真正在使用中的组 - let is_group_active = if mode == "global" { - // 全局模式下,只有GLOBAL组才能显示勾选 - group_name == "GLOBAL" && !now_proxy.is_empty() - } else if mode == "direct" { - // 直连模式下,不显示任何勾选 - false - } else { - // 规则模式下:只对用户在当前配置中手动选择过的代理组显示勾选 - // 这些组表示用户真正关心和使用的代理组 - let is_user_selected = current_profile_selected.iter().any(|selected| { - selected.name.as_deref() == Some(group_name) - }); - is_user_selected && !now_proxy.is_empty() - }; - - // 如果组处于活动状态,在组名前添加勾选标记 - let group_display_name = if is_group_active { - format!("✓ {}", group_name) - } else { - group_name.to_string() - }; - - match Submenu::with_id_and_items( - app_handle, - format!("proxy_group_{}", group_name), - group_display_name, // 使用带勾选标记的组名 - true, - &group_items_refs, - ) { - Ok(submenu) => submenus.push(submenu), - Err(e) => log::warn!(target: "app", "创建代理组子菜单失败: {}", e), + // 创建代理组子菜单 + if !group_items.is_empty() { + let group_items_refs: Vec<&dyn IsMenuItem> = group_items + .iter() + .map(|item| item as &dyn IsMenuItem) + .collect(); + + // 判断当前代理组是否为真正在使用中的组 + let is_group_active = if mode == "global" { + // 全局模式下,只有GLOBAL组才能显示勾选 + group_name == "GLOBAL" && !now_proxy.is_empty() + } else if mode == "direct" { + // 直连模式下,不显示任何勾选 + false + } else { + // 规则模式下:只对用户在当前配置中手动选择过的代理组显示勾选 + // 这些组表示用户真正关心和使用的代理组 + let is_user_selected = current_profile_selected.iter().any(|selected| { + selected.name.as_deref() == Some(group_name) + }); + is_user_selected && !now_proxy.is_empty() + }; + + // 如果组处于活动状态,在组名前添加勾选标记 + let group_display_name = if is_group_active { + format!("✓ {}", group_name) + } else { + group_name.to_string() + }; + + match Submenu::with_id_and_items( + app_handle, + format!("proxy_group_{}", group_name), + group_display_name, // 使用带勾选标记的组名 + true, + &group_items_refs, + ) { + Ok(submenu) => submenus.push(submenu), + Err(e) => log::warn!(target: "app", "创建代理组子菜单失败: {}", e), + } } } } diff --git a/src/components/home/current-proxy-card.tsx b/src/components/home/current-proxy-card.tsx index e47a20ab..b0cdf767 100644 --- a/src/components/home/current-proxy-card.tsx +++ b/src/components/home/current-proxy-card.tsx @@ -29,7 +29,11 @@ import { } from "@mui/icons-material"; import { useNavigate } from "react-router-dom"; import { EnhancedCard } from "@/components/home/enhanced-card"; -import { updateProxy, deleteConnection, syncTrayProxySelection } from "@/services/cmds"; +import { + updateProxy, + deleteConnection, + syncTrayProxySelection, +} from "@/services/cmds"; import delayManager from "@/services/delay"; import { useVerge } from "@/hooks/use-verge"; import { useAppData } from "@/providers/app-data-provider"; diff --git a/src/components/proxy/proxy-groups.tsx b/src/components/proxy/proxy-groups.tsx index ca93677b..015eb2c9 100644 --- a/src/components/proxy/proxy-groups.tsx +++ b/src/components/proxy/proxy-groups.tsx @@ -344,7 +344,7 @@ export const ProxyGroups = (props: Props) => { const { name, now } = group; console.log(`[ProxyGroups] GUI代理切换: ${name} -> ${proxy.name}`); - + try { // 1. 保存到selected中 (先保存本地状态) if (current) { @@ -364,7 +364,9 @@ export const ProxyGroups = (props: Props) => { // 2. 使用统一的同步命令更新代理并同步状态 await updateProxyAndSync(name, proxy.name); - console.log(`[ProxyGroups] 代理和状态同步完成: ${name} -> ${proxy.name}`); + console.log( + `[ProxyGroups] 代理和状态同步完成: ${name} -> ${proxy.name}`, + ); // 3. 刷新前端显示 onProxies(); @@ -379,18 +381,25 @@ export const ProxyGroups = (props: Props) => { }); }); } - } catch (error) { - console.error(`[ProxyGroups] 代理切换失败: ${name} -> ${proxy.name}`, error); + console.error( + `[ProxyGroups] 代理切换失败: ${name} -> ${proxy.name}`, + error, + ); // 如果统一命令失败,回退到原来的方式 try { await updateProxy(name, proxy.name); await forceRefreshProxies(); await syncTrayProxySelection(); onProxies(); - console.log(`[ProxyGroups] 代理切换回退成功: ${name} -> ${proxy.name}`); + console.log( + `[ProxyGroups] 代理切换回退成功: ${name} -> ${proxy.name}`, + ); } catch (fallbackError) { - console.error(`[ProxyGroups] 代理切换回退也失败: ${name} -> ${proxy.name}`, fallbackError); + console.error( + `[ProxyGroups] 代理切换回退也失败: ${name} -> ${proxy.name}`, + fallbackError, + ); onProxies(); // 至少刷新显示 } } diff --git a/src/providers/app-data-provider.tsx b/src/providers/app-data-provider.tsx index f2f89d1f..9e72ecd3 100644 --- a/src/providers/app-data-provider.tsx +++ b/src/providers/app-data-provider.tsx @@ -240,7 +240,7 @@ export const AppDataProvider = ({ // 监听强制代理刷新事件(托盘代理切换立即刷新) const handleForceRefreshProxies = () => { console.log("[AppDataProvider] 强制代理刷新事件"); - + // 立即刷新,无延迟,无防抖 forceRefreshProxies() .then(() => { @@ -263,9 +263,18 @@ export const AppDataProvider = ({ // 使用 Tauri 事件监听器替代 window 事件监听器 const setupTauriListeners = async () => { try { - const unlistenClash = await listen("verge://refresh-clash-config", handleRefreshClash); - const unlistenProxy = await listen("verge://refresh-proxy-config", handleRefreshProxy); - const unlistenForceRefresh = await listen("verge://force-refresh-proxies", handleForceRefreshProxies); + const unlistenClash = await listen( + "verge://refresh-clash-config", + handleRefreshClash, + ); + const unlistenProxy = await listen( + "verge://refresh-proxy-config", + handleRefreshProxy, + ); + const unlistenForceRefresh = await listen( + "verge://force-refresh-proxies", + handleForceRefreshProxies, + ); return () => { unlistenClash(); @@ -274,16 +283,34 @@ export const AppDataProvider = ({ }; } catch (error) { console.warn("[AppDataProvider] 设置 Tauri 事件监听器失败:", error); - + // 降级到 window 事件监听器 - window.addEventListener("verge://refresh-clash-config", handleRefreshClash); - window.addEventListener("verge://refresh-proxy-config", handleRefreshProxy); - window.addEventListener("verge://force-refresh-proxies", handleForceRefreshProxies); + window.addEventListener( + "verge://refresh-clash-config", + handleRefreshClash, + ); + window.addEventListener( + "verge://refresh-proxy-config", + handleRefreshProxy, + ); + window.addEventListener( + "verge://force-refresh-proxies", + handleForceRefreshProxies, + ); return () => { - window.removeEventListener("verge://refresh-clash-config", handleRefreshClash); - window.removeEventListener("verge://refresh-proxy-config", handleRefreshProxy); - window.removeEventListener("verge://force-refresh-proxies", handleForceRefreshProxies); + window.removeEventListener( + "verge://refresh-clash-config", + handleRefreshClash, + ); + window.removeEventListener( + "verge://refresh-proxy-config", + handleRefreshProxy, + ); + window.removeEventListener( + "verge://force-refresh-proxies", + handleForceRefreshProxies, + ); }; } };