1use tauri::{
8 menu::{Menu, MenuItem},
9 tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
10 App, Wry,
11};
12
13pub struct TrayMenuItemSpec {
15 pub id: &'static str,
16 pub label: String,
17 pub enabled: bool,
18}
19
20impl TrayMenuItemSpec {
21 #[must_use]
22 pub fn new(id: &'static str, label: impl Into<String>) -> Self {
23 Self {
24 id,
25 label: label.into(),
26 enabled: true,
27 }
28 }
29}
30
31pub fn build_tray_menu(app: &App, items: &[TrayMenuItemSpec]) -> tauri::Result<Menu<Wry>> {
33 let mut menu_items = Vec::with_capacity(items.len());
34 for item in items {
35 menu_items.push(MenuItem::with_id(
36 app,
37 item.id,
38 &item.label,
39 item.enabled,
40 None::<&str>,
41 )?);
42 }
43 let refs: Vec<&dyn tauri::menu::IsMenuItem<tauri::Wry>> = menu_items
44 .iter()
45 .map(|item| item as &dyn tauri::menu::IsMenuItem<tauri::Wry>)
46 .collect();
47 Menu::with_items(app, &refs)
48}
49
50pub fn install_tray(
55 app: &App,
56 tooltip: &str,
57 menu: &Menu<Wry>,
58 on_menu_item: impl Fn(&tauri::AppHandle, &str) + Send + Sync + 'static,
59 on_left_click: impl Fn(&tauri::AppHandle) + Send + Sync + 'static,
60) -> tauri::Result<()> {
61 let icon = app.default_window_icon().cloned();
62 let mut tray = TrayIconBuilder::new()
63 .tooltip(tooltip)
64 .menu(menu)
65 .show_menu_on_left_click(false)
66 .on_menu_event(move |app, event| on_menu_item(app, event.id().as_ref()))
67 .on_tray_icon_event(move |tray, event| {
68 if let TrayIconEvent::Click {
69 button: MouseButton::Left,
70 button_state: MouseButtonState::Up,
71 ..
72 } = event
73 {
74 on_left_click(tray.app_handle());
75 }
76 });
77
78 if let Some(icon) = icon {
79 tray = tray.icon(icon);
80 }
81 tray.build(app)?;
82 Ok(())
83}