use tauri::{ menu::{CheckMenuItem, Menu, MenuItem, PredefinedMenuItem, Submenu}, tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}, Emitter, Listener, Manager, Runtime, }; use serde::{Deserialize, Serialize}; use crate::tool::powerplan::PowerPlanMode; #[derive(Debug, Clone, Serialize, Deserialize)] struct LaunchOption { option: String, name: String, } pub fn create_tray(app: &tauri::AppHandle) -> tauri::Result<()> { // 托盘菜单项目 let separator = &PredefinedMenuItem::separator(app).unwrap(); let show_i = &MenuItem::with_id(app, "show", "显示主界面", true, None::<&str>)?; let quit_i = &MenuItem::with_id(app, "quit", "退出", true, None::<&str>)?; let kill_game_i = &MenuItem::with_id(app, "kill_game", "关闭CS2", true, None::<&str>)?; let kill_steam_i = &MenuItem::with_id(app, "kill_steam", "关闭Steam", true, None::<&str>)?; let launch_ww_i = &MenuItem::with_id(app, "launch_ww", "启动国际服", true, None::<&str>)?; let launch_pw_i = &MenuItem::with_id(app, "launch_pw", "启动国服", true, None::<&str>)?; let power_plan_extreme = CheckMenuItem::with_id( app, "power_plan_extreme", "卓越性能", true, false, None::<&str>, )?; let power_plan_high = CheckMenuItem::with_id(app, "power_plan_high", "高性能", true, false, None::<&str>)?; let power_plan_balanced = CheckMenuItem::with_id( app, "power_plan_balanced", "平衡", true, false, None::<&str>, )?; let power_plan_powersave = CheckMenuItem::with_id( app, "power_plan_powersave", "节能", true, false, None::<&str>, )?; // 创建启动项子菜单(初始为空,后续会动态更新) let launch_option_submenu = Submenu::with_id(app, "launch_option_submenu", "启动项: 游戏", true)?; // 创建托盘菜单 let menu = Menu::with_items( app, &[ &power_plan_extreme, &power_plan_high, &power_plan_balanced, &power_plan_powersave, separator, &launch_option_submenu, launch_ww_i, launch_pw_i, separator, kill_game_i, kill_steam_i, separator, show_i, quit_i, ], )?; let _ = app.listen("tray://get_powerplan", move |event| { if let Ok(payload) = event.payload().parse::() { match payload { x if x == PowerPlanMode::Other as i32 => { let _ = power_plan_powersave.set_checked(false); let _ = power_plan_balanced.set_checked(false); let _ = power_plan_high.set_checked(false); let _ = power_plan_extreme.set_checked(false); } x if x == PowerPlanMode::PowerSaving as i32 => { let _ = power_plan_powersave.set_checked(true); let _ = power_plan_balanced.set_checked(false); let _ = power_plan_high.set_checked(false); let _ = power_plan_extreme.set_checked(false); } x if x == PowerPlanMode::Balanced as i32 => { let _ = power_plan_powersave.set_checked(false); let _ = power_plan_balanced.set_checked(true); let _ = power_plan_high.set_checked(false); let _ = power_plan_extreme.set_checked(false); } x if x == PowerPlanMode::HighPerformance as i32 => { let _ = power_plan_powersave.set_checked(false); let _ = power_plan_balanced.set_checked(false); let _ = power_plan_high.set_checked(true); let _ = power_plan_extreme.set_checked(false); } x if x == PowerPlanMode::Extreme as i32 => { let _ = power_plan_powersave.set_checked(false); let _ = power_plan_balanced.set_checked(false); let _ = power_plan_high.set_checked(false); let _ = power_plan_extreme.set_checked(true); } _ => {} } } }); // 监听启动项列表更新事件 let launch_option_submenu_clone = launch_option_submenu.clone(); let _ = app.listen("tray://update_launch_options", move |event| { if let Ok(data) = serde_json::from_str::(event.payload()) { if let (Some(options), Some(current_index)) = ( data.get("options").and_then(|v| v.as_array()), data.get("currentIndex").and_then(|v| v.as_u64()), ) { let current_index = current_index as usize; // 获取当前启动项名称 let current_name = options .get(current_index) .and_then(|opt| opt.get("name")) .and_then(|n| n.as_str()) .map(|s| s.to_string()) .unwrap_or_else(|| format!("{}", current_index + 1)); // 更新子菜单标题 let _ = launch_option_submenu_clone.set_text(format!("启动项: {}", current_name)); // 清空现有子菜单项 - 先收集所有项目,然后移除 if let Ok(items) = launch_option_submenu_clone.items() { let items_to_remove: Vec<_> = items.iter().collect(); for item in items_to_remove { let _ = launch_option_submenu_clone.remove(item); } } // 创建新的子菜单项 for (index, option) in options.iter().enumerate() { if let Some(name) = option.get("name").and_then(|n| n.as_str()) { let display_name = if name.is_empty() { format!("{}", index + 1) } else { name.to_string() }; let item_id = format!("launch_option_{}", index); let app_handle = launch_option_submenu_clone.app_handle(); if let Ok(item) = CheckMenuItem::with_id( app_handle, &item_id, &display_name, true, index == current_index, None::<&str>, ) { let _ = launch_option_submenu_clone.append(&item); } } } } } }); let _ = TrayIconBuilder::with_id("tray") .icon(app.default_window_icon().unwrap().clone()) .menu(&menu) .show_menu_on_left_click(false) .on_menu_event(move |app, event| match event.id.as_ref() { "quit" => { app.exit(0); } "show" => { if let Some(window) = app.get_webview_window("main") { let _ = window.show(); let _ = window.set_focus(); } } "launch_ww" => { let _ = app.emit("tray://launch_game", "worldwide"); } "launch_pw" => { let _ = app.emit("tray://launch_game", "perfectworld"); } "kill_game" => { let _ = app.emit("tray://kill_game", None::<()>); } "kill_steam" => { let _ = app.emit("tray://kill_steam", None::<()>); } "power_plan_extreme" => { let _ = app.emit("tray://set_powerplan", PowerPlanMode::Extreme as i32); // let _ = power_plan_extreme.set_checked(true); } "power_plan_high" => { let _ = app.emit( "tray://set_powerplan", PowerPlanMode::HighPerformance as i32, ); // let _ = power_plan_high.set_checked(true); } "power_plan_balanced" => { let _ = app.emit("tray://set_powerplan", PowerPlanMode::Balanced as i32); // let _ = power_plan_balanced.set_checked(true); } "power_plan_powersave" => { let _ = app.emit("tray://set_powerplan", PowerPlanMode::PowerSaving as i32); // let _ = power_plan_powersave.set_checked(true); } id if id.starts_with("launch_option_") => { // 提取索引 if let Ok(index) = id.replace("launch_option_", "").parse::() { let _ = app.emit("tray://set_launch_index", index); } } _ => {} }) .on_tray_icon_event(|tray, event| { if let TrayIconEvent::Click { button: MouseButton::Left, button_state: MouseButtonState::Up, .. } = event { let app = tray.app_handle(); if let Some(window) = app.get_webview_window("main") { let _ = window.show(); let _ = window.set_focus(); } } }) .build(app); Ok(()) }