This commit is contained in:
Kasserrr
2025-08-29 23:45:38 +08:00
Unverified
4 changed files with 129 additions and 97 deletions

View File

@@ -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<Wry>> = group_items
.iter()
.map(|item| item as &dyn IsMenuItem<Wry>)
.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<Wry>> = group_items
.iter()
.map(|item| item as &dyn IsMenuItem<Wry>)
.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),
}
}
}
}

View File

@@ -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";

View File

@@ -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(); // 至少刷新显示
}
}

View File

@@ -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,
);
};
}
};