托盘图标功能

master
cysamurai 1 month ago
parent 7825fb0ec6
commit 1c5469fa96

@ -1,7 +1,7 @@
{
"name": "call-client",
"private": true,
"version": "0.1.2",
"version": "0.1.3",
"type": "module",
"scripts": {
"dev": "vite",

@ -392,7 +392,7 @@ dependencies = [
[[package]]
name = "call-client"
version = "0.1.2"
version = "0.1.3"
dependencies = [
"chrono",
"fs2",
@ -2173,12 +2173,46 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "libappindicator"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db2d3cb96d092b4824cb306c9e544c856a4cb6210c1081945187f7f1924b47e8"
dependencies = [
"glib",
"gtk",
"gtk-sys",
"libappindicator-sys",
"log",
]
[[package]]
name = "libappindicator-sys"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1b3b6681973cea8cc3bce7391e6d7d5502720b80a581c9a95c9cbaf592826aa"
dependencies = [
"gtk-sys",
"libloading",
"once_cell",
]
[[package]]
name = "libc"
version = "0.2.183"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
[[package]]
name = "libloading"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "libredox"
version = "0.1.15"
@ -4276,6 +4310,7 @@ dependencies = [
"core-foundation 0.9.4",
"core-graphics",
"crossbeam-channel",
"dirs-next",
"dispatch",
"gdk",
"gdk-pixbuf",
@ -4290,6 +4325,7 @@ dependencies = [
"instant",
"jni",
"lazy_static",
"libappindicator",
"libc",
"log",
"ndk",

@ -1,6 +1,6 @@
[package]
name = "call-client"
version = "0.1.2"
version = "0.1.3"
description = "A Tauri App"
authors = ["you"]
edition = "2021"
@ -22,7 +22,7 @@ default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]
[dependencies]
tauri = { version = "1", features = ["api-all"] }
tauri = { version = "1", features = ["api-all", "system-tray"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
fs2 = "0.4"

@ -1,8 +1,61 @@
use tauri::{AppHandle, Manager, WindowBuilder, WindowUrl};
use tauri::{AppHandle, Manager, PhysicalPosition, Window, WindowBuilder, WindowUrl};
use tauri::State;
use crate::{commands::logger::app_log, commands::sync::cleanup_screen_sync, state::AppState};
/// 托盘「叫号窗口」:`main` 已显示且未最小化则最小化;否则显示并置于主屏中央再聚焦。
pub fn toggle_main_call_window_from_tray(app: &AppHandle) {
if ensure_main_window(app.clone()).is_err() {
return;
}
let Some(main) = app.get_window("main") else {
return;
};
let visible = main.is_visible().unwrap_or(false);
let minimized = main.is_minimized().unwrap_or(false);
if minimized {
let _ = main.unminimize();
let _ = main.show();
let _ = center_window_on_primary_monitor(&main);
let _ = main.set_focus();
return;
}
if visible {
let _ = main.minimize();
return;
}
let _ = main.show();
let _ = center_window_on_primary_monitor(&main);
let _ = main.set_focus();
}
/// 将窗口置于主显示器工作区大致中央(无可用 monitor 信息时回退 `center()`)。
fn center_window_on_primary_monitor(window: &Window) {
let Ok(Some(monitor)) = window.primary_monitor() else {
let _ = window.center();
return;
};
let mon_pos = monitor.position();
let mon_size = monitor.size();
let Ok(outer) = window.outer_size() else {
let _ = window.center();
return;
};
let w = outer.width as i32;
let h = outer.height as i32;
let screen_w = mon_size.width as i32;
let screen_h = mon_size.height as i32;
let x = mon_pos.x + (screen_w - w) / 2;
let y = mon_pos.y + (screen_h - h) / 2;
let _ = window.set_position(PhysicalPosition::new(x, y));
}
pub fn ensure_main_window(app: AppHandle) -> Result<(), String> {
if app.get_window("main").is_some() {
return Ok(());

@ -11,16 +11,23 @@ use commands::{
events::{emit_to_window, list_windows},
logger::{app_log, get_log_paths},
session::{session_clear, session_get, session_set},
sync::{start_screen_sync, stop_screen_sync},
sync::{cleanup_screen_sync, start_screen_sync, stop_screen_sync},
update::{check_apt_update, setup_zyyun_apt_source, upgrade_call_client_via_apt},
window::{
close_taxer_info_window, close_ticket_window, ensure_main_window, focus_window,
open_login_window, open_main_window, open_taxer_info_window, open_ticket_window, quit_app,
toggle_main_call_window_from_tray,
},
};
use fs2::FileExt;
use state::AppState;
use tauri::Manager;
use tauri::{
CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu,
};
const TRAY_MENU_SHOW_ID: &str = "tray_show_window";
const TRAY_MENU_TICKETS_ID: &str = "tray_open_ticket_list";
const TRAY_MENU_QUIT_ID: &str = "tray_quit";
#[allow(dead_code)]
struct SingleInstanceLock(File);
@ -48,7 +55,37 @@ fn acquire_single_instance_lock(app: &tauri::App) -> Result<SingleInstanceLock,
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let tray_menu = SystemTrayMenu::new()
.add_item(CustomMenuItem::new(
TRAY_MENU_SHOW_ID,
"显示/隐藏叫号窗口",
))
.add_item(CustomMenuItem::new(
TRAY_MENU_TICKETS_ID,
"打开票号列表",
))
.add_item(CustomMenuItem::new(TRAY_MENU_QUIT_ID, "退出"));
let system_tray = SystemTray::new().with_menu(tray_menu);
tauri::Builder::default()
.system_tray(system_tray)
.on_system_tray_event(|app, event| match event {
SystemTrayEvent::DoubleClick { .. } | SystemTrayEvent::LeftClick { .. } => {
toggle_main_call_window_from_tray(app);
}
SystemTrayEvent::MenuItemClick { id, .. } if id.as_str() == TRAY_MENU_SHOW_ID => {
toggle_main_call_window_from_tray(app);
}
SystemTrayEvent::MenuItemClick { id, .. } if id.as_str() == TRAY_MENU_TICKETS_ID => {
let _ = open_ticket_window(app.clone());
}
SystemTrayEvent::MenuItemClick { id, .. } if id.as_str() == TRAY_MENU_QUIT_ID => {
let state = app.state::<AppState>();
cleanup_screen_sync(&state);
app.exit(0);
}
_ => {}
})
.manage(AppState::default())
.setup(|app| {
match acquire_single_instance_lock(app) {

@ -2,7 +2,7 @@
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"package": {
"productName": "call-client",
"version": "0.1.2"
"version": "0.1.3"
},
"build": {
"beforeDevCommand": "npm run dev",
@ -55,6 +55,9 @@
"alwaysOnTop": true
}
],
"systemTray": {
"iconPath": "icons/icon.ico"
},
"security": {
"csp": null
},

Loading…
Cancel
Save