feat(tray): add optional inline outbound modes in tray menu #5881

Closes #5881
This commit is contained in:
Slinetrac 2025-12-21 10:33:19 +08:00
parent a0b12b8797
commit 23e551e384
No known key found for this signature in database
20 changed files with 76 additions and 19 deletions

View File

@ -230,6 +230,8 @@ pub struct IVerge {
// pub enable_tray_icon: Option<bool>, // pub enable_tray_icon: Option<bool>,
/// show proxy groups directly on tray root menu /// show proxy groups directly on tray root menu
pub tray_inline_proxy_groups: Option<bool>, pub tray_inline_proxy_groups: Option<bool>,
/// show outbound modes directly on tray root menu
pub tray_inline_outbound_modes: Option<bool>,
/// 自动进入轻量模式 /// 自动进入轻量模式
pub enable_auto_light_weight_mode: Option<bool>, pub enable_auto_light_weight_mode: Option<bool>,
@ -440,6 +442,7 @@ impl IVerge {
enable_tray_speed: Some(false), enable_tray_speed: Some(false),
// enable_tray_icon: Some(true), // enable_tray_icon: Some(true),
tray_inline_proxy_groups: Some(true), tray_inline_proxy_groups: Some(true),
tray_inline_outbound_modes: Some(false),
enable_global_hotkey: Some(true), enable_global_hotkey: Some(true),
enable_auto_light_weight_mode: Some(false), enable_auto_light_weight_mode: Some(false),
auto_light_weight_minutes: Some(10), auto_light_weight_minutes: Some(10),
@ -541,6 +544,7 @@ impl IVerge {
patch!(enable_tray_speed); patch!(enable_tray_speed);
// patch!(enable_tray_icon); // patch!(enable_tray_icon);
patch!(tray_inline_proxy_groups); patch!(tray_inline_proxy_groups);
patch!(tray_inline_outbound_modes);
patch!(enable_auto_light_weight_mode); patch!(enable_auto_light_weight_mode);
patch!(auto_light_weight_minutes); patch!(auto_light_weight_minutes);
patch!(enable_dns_settings); patch!(enable_dns_settings);

View File

@ -771,6 +771,7 @@ async fn create_tray_menu(
let verge_settings = Config::verge().await.latest_arc(); let verge_settings = Config::verge().await.latest_arc();
let show_proxy_groups_inline = verge_settings.tray_inline_proxy_groups.unwrap_or(true); let show_proxy_groups_inline = verge_settings.tray_inline_proxy_groups.unwrap_or(true);
let show_outbound_modes_inline = verge_settings.tray_inline_outbound_modes.unwrap_or(false);
let version = env!("CARGO_PKG_VERSION"); let version = env!("CARGO_PKG_VERSION");
@ -794,13 +795,6 @@ async fn create_tray_menu(
hotkeys.get("open_or_close_dashboard").map(|s| s.as_str()), hotkeys.get("open_or_close_dashboard").map(|s| s.as_str()),
)?; )?;
let current_mode_text = match current_proxy_mode {
"global" => rust_i18n::t!("tray.global"),
"direct" => rust_i18n::t!("tray.direct"),
_ => rust_i18n::t!("tray.rule"),
};
let outbound_modes_label = format!("{} ({})", texts.outbound_modes, current_mode_text);
let rule_mode = &CheckMenuItem::with_id( let rule_mode = &CheckMenuItem::with_id(
app_handle, app_handle,
MenuIds::RULE_MODE, MenuIds::RULE_MODE,
@ -828,17 +822,27 @@ async fn create_tray_menu(
hotkeys.get("clash_mode_direct").map(|s| s.as_str()), hotkeys.get("clash_mode_direct").map(|s| s.as_str()),
)?; )?;
let outbound_modes = &Submenu::with_id_and_items( let outbound_modes = if show_outbound_modes_inline {
app_handle, None
MenuIds::OUTBOUND_MODES, } else {
outbound_modes_label.as_str(), let current_mode_text = match current_proxy_mode {
true, "global" => rust_i18n::t!("tray.global"),
&[ "direct" => rust_i18n::t!("tray.direct"),
rule_mode as &dyn IsMenuItem<Wry>, _ => rust_i18n::t!("tray.rule"),
global_mode as &dyn IsMenuItem<Wry>, };
direct_mode as &dyn IsMenuItem<Wry>, let outbound_modes_label = format!("{} ({})", texts.outbound_modes, current_mode_text);
], Some(Submenu::with_id_and_items(
)?; app_handle,
MenuIds::OUTBOUND_MODES,
outbound_modes_label.as_str(),
true,
&[
rule_mode as &dyn IsMenuItem<Wry>,
global_mode as &dyn IsMenuItem<Wry>,
direct_mode as &dyn IsMenuItem<Wry>,
],
)?)
};
let profiles = &Submenu::with_id_and_items( let profiles = &Submenu::with_id_and_items(
app_handle, app_handle,
@ -946,7 +950,19 @@ async fn create_tray_menu(
let separator = &PredefinedMenuItem::separator(app_handle)?; let separator = &PredefinedMenuItem::separator(app_handle)?;
// 动态构建菜单项 // 动态构建菜单项
let mut menu_items: Vec<&dyn IsMenuItem<Wry>> = vec![open_window, outbound_modes, separator, profiles]; let mut menu_items: Vec<&dyn IsMenuItem<Wry>> = vec![open_window, separator];
if show_outbound_modes_inline {
menu_items.extend_from_slice(&[
rule_mode as &dyn IsMenuItem<Wry>,
global_mode as &dyn IsMenuItem<Wry>,
direct_mode as &dyn IsMenuItem<Wry>,
]);
} else if let Some(ref outbound_modes) = outbound_modes {
menu_items.push(outbound_modes);
}
menu_items.extend_from_slice(&[separator, profiles]);
// 如果有代理节点,添加代理节点菜单 // 如果有代理节点,添加代理节点菜单
if show_proxy_groups_inline { if show_proxy_groups_inline {

View File

@ -103,6 +103,7 @@ fn determine_update_flags(patch: &IVerge) -> i32 {
let enable_auto_light_weight = patch.enable_auto_light_weight_mode; let enable_auto_light_weight = patch.enable_auto_light_weight_mode;
let enable_external_controller = patch.enable_external_controller; let enable_external_controller = patch.enable_external_controller;
let tray_inline_proxy_groups = patch.tray_inline_proxy_groups; let tray_inline_proxy_groups = patch.tray_inline_proxy_groups;
let tray_inline_outbound_modes = patch.tray_inline_outbound_modes;
let enable_proxy_guard = patch.enable_proxy_guard; let enable_proxy_guard = patch.enable_proxy_guard;
let proxy_guard_duration = patch.proxy_guard_duration; let proxy_guard_duration = patch.proxy_guard_duration;
@ -184,6 +185,9 @@ fn determine_update_flags(patch: &IVerge) -> i32 {
if tray_inline_proxy_groups.is_some() { if tray_inline_proxy_groups.is_some() {
update_flags |= UpdateFlags::SystrayMenu as i32; update_flags |= UpdateFlags::SystrayMenu as i32;
} }
if tray_inline_outbound_modes.is_some() {
update_flags |= UpdateFlags::SystrayMenu as i32;
}
update_flags update_flags
} }

View File

@ -436,6 +436,23 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
<Switch edge="end" /> <Switch edge="end" />
</GuardState> </GuardState>
</Item> </Item>
<Item>
<ListItemText
primary={t(
"settings.components.verge.layout.fields.showOutboundModesInline",
)}
/>
<GuardState
value={verge?.tray_inline_outbound_modes ?? false}
valueProps="checked"
onCatch={onError}
onFormat={onSwitchFormat}
onChange={(e) => onChangeData({ tray_inline_outbound_modes: e })}
onGuard={(e) => patchVerge({ tray_inline_outbound_modes: e })}
>
<Switch edge="end" />
</GuardState>
</Item>
<Item> <Item>
<ListItemText <ListItemText

View File

@ -212,6 +212,7 @@
"collapseNavBar": "طي شريط التنقل", "collapseNavBar": "طي شريط التنقل",
"trayIcon": "أيقونة شريط المهام", "trayIcon": "أيقونة شريط المهام",
"showProxyGroupsInline": "Show Proxy Groups Inline", "showProxyGroupsInline": "Show Proxy Groups Inline",
"showOutboundModesInline": "Show Outbound Modes Inline",
"commonTrayIcon": "أيقونة شريط مهام عامة", "commonTrayIcon": "أيقونة شريط مهام عامة",
"systemProxyTrayIcon": "أيقونة شريط المهام لوكيل النظام", "systemProxyTrayIcon": "أيقونة شريط المهام لوكيل النظام",
"tunTrayIcon": "أيقونة شريط المهام لـ TUN", "tunTrayIcon": "أيقونة شريط المهام لـ TUN",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "Navigationsleiste einklappen", "collapseNavBar": "Navigationsleiste einklappen",
"trayIcon": "Tray-Symbol", "trayIcon": "Tray-Symbol",
"showProxyGroupsInline": "Show Proxy Groups Inline", "showProxyGroupsInline": "Show Proxy Groups Inline",
"showOutboundModesInline": "Show Outbound Modes Inline",
"commonTrayIcon": "Standard-Tray-Symbol", "commonTrayIcon": "Standard-Tray-Symbol",
"systemProxyTrayIcon": "Systemproxy-Tray-Symbol", "systemProxyTrayIcon": "Systemproxy-Tray-Symbol",
"tunTrayIcon": "TUN-Modus-Tray-Symbol", "tunTrayIcon": "TUN-Modus-Tray-Symbol",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "Collapse Navigation Bar", "collapseNavBar": "Collapse Navigation Bar",
"trayIcon": "Tray Icon", "trayIcon": "Tray Icon",
"showProxyGroupsInline": "Show Proxy Groups Inline", "showProxyGroupsInline": "Show Proxy Groups Inline",
"showOutboundModesInline": "Show Outbound Modes Inline",
"commonTrayIcon": "Common Tray Icon", "commonTrayIcon": "Common Tray Icon",
"systemProxyTrayIcon": "System Proxy Tray Icon", "systemProxyTrayIcon": "System Proxy Tray Icon",
"tunTrayIcon": "Tun Tray Icon", "tunTrayIcon": "Tun Tray Icon",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "Colapsar barra de navegación", "collapseNavBar": "Colapsar barra de navegación",
"trayIcon": "Icono de la bandeja", "trayIcon": "Icono de la bandeja",
"showProxyGroupsInline": "Show Proxy Groups Inline", "showProxyGroupsInline": "Show Proxy Groups Inline",
"showOutboundModesInline": "Show Outbound Modes Inline",
"commonTrayIcon": "Icono de bandeja común", "commonTrayIcon": "Icono de bandeja común",
"systemProxyTrayIcon": "Icono de bandeja del proxy del sistema", "systemProxyTrayIcon": "Icono de bandeja del proxy del sistema",
"tunTrayIcon": "Icono de bandeja del modo TUN", "tunTrayIcon": "Icono de bandeja del modo TUN",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "جمع کردن نوار ناوبری", "collapseNavBar": "جمع کردن نوار ناوبری",
"trayIcon": "آیکون سینی سیستم", "trayIcon": "آیکون سینی سیستم",
"showProxyGroupsInline": "Show Proxy Groups Inline", "showProxyGroupsInline": "Show Proxy Groups Inline",
"showOutboundModesInline": "Show Outbound Modes Inline",
"commonTrayIcon": "آیکون مشترک سینی سیستم", "commonTrayIcon": "آیکون مشترک سینی سیستم",
"systemProxyTrayIcon": "آیکون سینی پراکسی سیستم", "systemProxyTrayIcon": "آیکون سینی پراکسی سیستم",
"tunTrayIcon": "آیکون سینی Tun", "tunTrayIcon": "آیکون سینی Tun",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "Ciutkan bilah navigasi", "collapseNavBar": "Ciutkan bilah navigasi",
"trayIcon": "Ikon Tray", "trayIcon": "Ikon Tray",
"showProxyGroupsInline": "Show Proxy Groups Inline", "showProxyGroupsInline": "Show Proxy Groups Inline",
"showOutboundModesInline": "Show Outbound Modes Inline",
"commonTrayIcon": "Ikon Tray Umum", "commonTrayIcon": "Ikon Tray Umum",
"systemProxyTrayIcon": "Ikon Tray Proksi Sistem", "systemProxyTrayIcon": "Ikon Tray Proksi Sistem",
"tunTrayIcon": "Ikon Tray Tun", "tunTrayIcon": "Ikon Tray Tun",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "ナビゲーションバーを折りたたむ", "collapseNavBar": "ナビゲーションバーを折りたたむ",
"trayIcon": "トレイアイコン", "trayIcon": "トレイアイコン",
"showProxyGroupsInline": "Show Proxy Groups Inline", "showProxyGroupsInline": "Show Proxy Groups Inline",
"showOutboundModesInline": "Show Outbound Modes Inline",
"commonTrayIcon": "通常のトレイアイコン", "commonTrayIcon": "通常のトレイアイコン",
"systemProxyTrayIcon": "システムプロキシトレイアイコン", "systemProxyTrayIcon": "システムプロキシトレイアイコン",
"tunTrayIcon": "TUNモードトレイアイコン", "tunTrayIcon": "TUNモードトレイアイコン",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "내비게이션 바 접기", "collapseNavBar": "내비게이션 바 접기",
"trayIcon": "트레이 아이콘", "trayIcon": "트레이 아이콘",
"showProxyGroupsInline": "프록시 그룹 인라인 표시", "showProxyGroupsInline": "프록시 그룹 인라인 표시",
"showOutboundModesInline": "Show Outbound Modes Inline",
"commonTrayIcon": "공용 트레이 아이콘", "commonTrayIcon": "공용 트레이 아이콘",
"systemProxyTrayIcon": "시스템 프록시 트레이 아이콘", "systemProxyTrayIcon": "시스템 프록시 트레이 아이콘",
"tunTrayIcon": "TUN 트레이 아이콘", "tunTrayIcon": "TUN 트레이 아이콘",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "Свернуть панель навигации", "collapseNavBar": "Свернуть панель навигации",
"trayIcon": "Иконка в трее", "trayIcon": "Иконка в трее",
"showProxyGroupsInline": "Show Proxy Groups Inline", "showProxyGroupsInline": "Show Proxy Groups Inline",
"showOutboundModesInline": "Show Outbound Modes Inline",
"commonTrayIcon": "Общий значок в трее", "commonTrayIcon": "Общий значок в трее",
"systemProxyTrayIcon": "Значок системного прокси в трее", "systemProxyTrayIcon": "Значок системного прокси в трее",
"tunTrayIcon": "Значок TUN в трее", "tunTrayIcon": "Значок TUN в трее",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "Gezinme çubuğunu daralt", "collapseNavBar": "Gezinme çubuğunu daralt",
"trayIcon": "Tepsi Simgesi", "trayIcon": "Tepsi Simgesi",
"showProxyGroupsInline": "Show Proxy Groups Inline", "showProxyGroupsInline": "Show Proxy Groups Inline",
"showOutboundModesInline": "Show Outbound Modes Inline",
"commonTrayIcon": "Genel Tepsi Simgesi", "commonTrayIcon": "Genel Tepsi Simgesi",
"systemProxyTrayIcon": "Sistem Vekil Tepsi Simgesi", "systemProxyTrayIcon": "Sistem Vekil Tepsi Simgesi",
"tunTrayIcon": "Tun Tepsi Simgesi", "tunTrayIcon": "Tun Tepsi Simgesi",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "Навигация панелен җыю", "collapseNavBar": "Навигация панелен җыю",
"trayIcon": "Трей иконкасы", "trayIcon": "Трей иконкасы",
"showProxyGroupsInline": "Show Proxy Groups Inline", "showProxyGroupsInline": "Show Proxy Groups Inline",
"showOutboundModesInline": "Show Outbound Modes Inline",
"commonTrayIcon": "Гомуми трей иконкасы", "commonTrayIcon": "Гомуми трей иконкасы",
"systemProxyTrayIcon": "Системалы прокси иконкасы", "systemProxyTrayIcon": "Системалы прокси иконкасы",
"tunTrayIcon": "Tun (виртуаль адаптер) иконкасы", "tunTrayIcon": "Tun (виртуаль адаптер) иконкасы",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "收起导航栏", "collapseNavBar": "收起导航栏",
"trayIcon": "托盘图标", "trayIcon": "托盘图标",
"showProxyGroupsInline": "将代理组显示在托盘一级菜单", "showProxyGroupsInline": "将代理组显示在托盘一级菜单",
"showOutboundModesInline": "将出站模式显示在托盘一级菜单",
"commonTrayIcon": "常规托盘图标", "commonTrayIcon": "常规托盘图标",
"systemProxyTrayIcon": "系统代理托盘图标", "systemProxyTrayIcon": "系统代理托盘图标",
"tunTrayIcon": "TUN 模式托盘图标", "tunTrayIcon": "TUN 模式托盘图标",

View File

@ -212,6 +212,7 @@
"collapseNavBar": "收起導覽列", "collapseNavBar": "收起導覽列",
"trayIcon": "系統匣圖示", "trayIcon": "系統匣圖示",
"showProxyGroupsInline": "將代理組顯示在系統匣一級選單", "showProxyGroupsInline": "將代理組顯示在系統匣一級選單",
"showOutboundModesInline": "將出站模式顯示在系統匣一級選單",
"commonTrayIcon": "一般系統匣圖示", "commonTrayIcon": "一般系統匣圖示",
"systemProxyTrayIcon": "系統代理系統匣圖示", "systemProxyTrayIcon": "系統代理系統匣圖示",
"tunTrayIcon": "虛擬網路介面卡模式系統匣圖示", "tunTrayIcon": "虛擬網路介面卡模式系統匣圖示",

View File

@ -432,6 +432,7 @@ export const translationKeys = [
"settings.components.verge.layout.fields.collapseNavBar", "settings.components.verge.layout.fields.collapseNavBar",
"settings.components.verge.layout.fields.trayIcon", "settings.components.verge.layout.fields.trayIcon",
"settings.components.verge.layout.fields.showProxyGroupsInline", "settings.components.verge.layout.fields.showProxyGroupsInline",
"settings.components.verge.layout.fields.showOutboundModesInline",
"settings.components.verge.layout.fields.commonTrayIcon", "settings.components.verge.layout.fields.commonTrayIcon",
"settings.components.verge.layout.fields.systemProxyTrayIcon", "settings.components.verge.layout.fields.systemProxyTrayIcon",
"settings.components.verge.layout.fields.tunTrayIcon", "settings.components.verge.layout.fields.tunTrayIcon",

View File

@ -626,6 +626,7 @@ export interface TranslationResources {
navIcon: string; navIcon: string;
preferSystemTitlebar: string; preferSystemTitlebar: string;
proxyGroupIcon: string; proxyGroupIcon: string;
showOutboundModesInline: string;
showProxyGroupsInline: string; showProxyGroupsInline: string;
systemProxyTrayIcon: string; systemProxyTrayIcon: string;
toastPosition: string; toastPosition: string;

View File

@ -823,6 +823,7 @@ interface IVergeConfig {
// enable_tray_speed?: boolean; // enable_tray_speed?: boolean;
// enable_tray_icon?: boolean; // enable_tray_icon?: boolean;
tray_inline_proxy_groups?: boolean; tray_inline_proxy_groups?: boolean;
tray_inline_outbound_modes?: boolean;
enable_tun_mode?: boolean; enable_tun_mode?: boolean;
enable_auto_light_weight_mode?: boolean; enable_auto_light_weight_mode?: boolean;
auto_light_weight_minutes?: number; auto_light_weight_minutes?: number;