bug-001: fix tray menu, add autostart and crash recovery launcher
All checks were successful
Build Check / build (push) Successful in 4m2s

This commit is contained in:
2026-05-17 09:26:28 -05:00
parent 77ddf68c8f
commit 168dc9de83
9 changed files with 400 additions and 9 deletions

View File

@@ -74,12 +74,16 @@ pub struct TickrApp {
update_in_progress: bool,
update_result_rx: mpsc::Receiver<UpdateCheckResult>,
// Tray
// Tray — use our own channels fed by set_event_handler so events are
// delivered even when the window is hidden (the global receiver() only
// works reliably while the winit loop is actively processing messages).
#[allow(dead_code)]
tray_icon: Option<tray_icon::TrayIcon>,
tray_open_id: Option<tray_icon::menu::MenuId>,
tray_check_id: Option<tray_icon::menu::MenuId>,
tray_quit_id: Option<tray_icon::menu::MenuId>,
tray_ev_rx: mpsc::Receiver<tray_icon::TrayIconEvent>,
menu_ev_rx: mpsc::Receiver<tray_icon::menu::MenuEvent>,
window_visible: bool,
hide_to_tray: bool,
should_quit: bool,
@@ -108,6 +112,24 @@ impl TickrApp {
let (tray_icon, tray_open_id, tray_check_id, tray_quit_id) =
setup_tray(icon_rgba.clone(), icon_size, watchlist.tickers.len());
// Route tray events through our own sync channels + wake egui immediately.
// SyncSender is Send + Sync, satisfying the 'static closure requirement.
// (The global receiver() channel is NOT used — set_event_handler replaces it.)
let (tray_ev_tx, tray_ev_rx) = mpsc::sync_channel::<tray_icon::TrayIconEvent>(64);
let (menu_ev_tx, menu_ev_rx) = mpsc::sync_channel::<tray_icon::menu::MenuEvent>(64);
let ctx_tray = cc.egui_ctx.clone();
tray_icon::TrayIconEvent::set_event_handler(Some(move |e| {
let _ = tray_ev_tx.send(e);
ctx_tray.request_repaint();
}));
let ctx_menu = cc.egui_ctx.clone();
tray_icon::menu::MenuEvent::set_event_handler(Some(move |e| {
let _ = menu_ev_tx.send(e);
ctx_menu.request_repaint();
}));
// Spawn background check task
let (bg_cmd_tx, bg_cmd_rx) = tokio::sync::mpsc::unbounded_channel::<BgCmd>();
let (update_result_tx, update_result_rx) = mpsc::channel::<UpdateCheckResult>();
@@ -138,6 +160,8 @@ impl TickrApp {
tray_open_id,
tray_check_id,
tray_quit_id,
tray_ev_rx,
menu_ev_rx,
window_visible: start_visible,
hide_to_tray: false,
should_quit: false,
@@ -870,17 +894,16 @@ impl TickrApp {
}
fn poll_tray_events(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
use tray_icon::TrayIconEvent;
while let Ok(event) = TrayIconEvent::receiver().try_recv() {
// Drain icon-level events (single/double click → show window)
while let Ok(event) = self.tray_ev_rx.try_recv() {
match event {
TrayIconEvent::Click { .. } => self.show_window(ctx),
tray_icon::TrayIconEvent::Click { .. } => self.show_window(ctx),
_ => {}
}
}
use tray_icon::menu::MenuEvent;
while let Ok(event) = MenuEvent::receiver().try_recv() {
// Drain context-menu events
while let Ok(event) = self.menu_ev_rx.try_recv() {
if self.tray_open_id.as_ref() == Some(&event.id) {
self.show_window(ctx);
} else if self.tray_check_id.as_ref() == Some(&event.id) {