11#![ cfg_attr( not( debug_assertions) , windows_subsystem = "windows" ) ]
22
3- use magic_context_dashboard_lib:: { commands, db , AppState } ;
3+ use magic_context_dashboard_lib:: { commands, AppState } ;
44use tauri:: {
5- menu:: MenuBuilder ,
5+ menu:: { MenuBuilder , MenuItemBuilder , SubmenuBuilder } ,
66 tray:: { MouseButton , MouseButtonState , TrayIconBuilder , TrayIconEvent } ,
7- Manager ,
7+ Emitter , Manager ,
88} ;
99
1010const OPEN_DASHBOARD_MENU_ID : & str = "open_dashboard" ;
11- const TRIGGER_DREAMER_MENU_ID : & str = "trigger_dreamer " ;
11+ const CHECK_UPDATES_MENU_ID : & str = "check_updates " ;
1212const QUIT_MENU_ID : & str = "quit" ;
1313
1414fn show_main_window ( app : & tauri:: AppHandle ) {
@@ -19,24 +19,6 @@ fn show_main_window(app: &tauri::AppHandle) {
1919 }
2020}
2121
22- fn trigger_dreamer ( app : & tauri:: AppHandle ) -> Result < ( ) , String > {
23- let state = app. state :: < AppState > ( ) ;
24- let path = state. get_db_path ( ) ?;
25- let conn = db:: open_readwrite ( & path) . map_err ( |e| e. to_string ( ) ) ?;
26- // Resolve a real project identity from the memories table instead of using "."
27- // Include both active and permanent memories — a project with only permanent memories is still valid
28- let project_path: String = conn
29- . query_row (
30- "SELECT project_path FROM memories WHERE status IN ('active', 'permanent') GROUP BY project_path ORDER BY MAX(updated_at) DESC LIMIT 1" ,
31- [ ] ,
32- |row| row. get ( 0 ) ,
33- )
34- . map_err ( |_| "No project found — write a memory first to enable dreamer from tray" . to_string ( ) ) ?;
35- db:: enqueue_dream ( & conn, & project_path, "Manual trigger from dashboard tray" )
36- . map ( |_| ( ) )
37- . map_err ( |e| e. to_string ( ) )
38- }
39-
4022fn main ( ) {
4123 tauri:: Builder :: default ( )
4224 // shell plugin removed — no shell:default capability needed
@@ -90,10 +72,45 @@ fn main() {
9072 commands:: get_db_health,
9173 ] )
9274 . setup ( |app| {
75+ // ── macOS app menu bar ──
76+ let app_handle_for_menu = app. app_handle ( ) . clone ( ) ;
77+ let check_updates_item = MenuItemBuilder :: with_id ( "app_check_updates" , "Check for Updates..." )
78+ . build ( app) ?;
79+ let app_submenu = SubmenuBuilder :: new ( app, "Magic Context" )
80+ . about ( None )
81+ . item ( & check_updates_item)
82+ . separator ( )
83+ . hide ( )
84+ . hide_others ( )
85+ . show_all ( )
86+ . separator ( )
87+ . quit ( )
88+ . build ( ) ?;
89+ let edit_submenu = SubmenuBuilder :: new ( app, "Edit" )
90+ . undo ( )
91+ . redo ( )
92+ . separator ( )
93+ . cut ( )
94+ . copy ( )
95+ . paste ( )
96+ . select_all ( )
97+ . build ( ) ?;
98+ let app_menu = MenuBuilder :: new ( app)
99+ . item ( & app_submenu)
100+ . item ( & edit_submenu)
101+ . build ( ) ?;
102+ app. set_menu ( app_menu) ?;
103+ app. on_menu_event ( move |_app, event| {
104+ if event. id ( ) . as_ref ( ) == "app_check_updates" {
105+ let _ = app_handle_for_menu. emit ( "check-for-updates" , ( ) ) ;
106+ }
107+ } ) ;
108+
109+ // ── System tray ──
93110 let tray_app_handle = app. app_handle ( ) . clone ( ) ;
94111 let tray_menu = MenuBuilder :: new ( app)
95112 . text ( OPEN_DASHBOARD_MENU_ID , "Open Dashboard" )
96- . text ( TRIGGER_DREAMER_MENU_ID , "Trigger Dreamer " )
113+ . text ( CHECK_UPDATES_MENU_ID , "Check for Updates... " )
97114 . separator ( )
98115 . text ( QUIT_MENU_ID , "Quit" )
99116 . build ( ) ?;
@@ -103,10 +120,9 @@ fn main() {
103120 . show_menu_on_left_click ( false )
104121 . on_menu_event ( |app, event| match event. id ( ) . as_ref ( ) {
105122 OPEN_DASHBOARD_MENU_ID => show_main_window ( app) ,
106- TRIGGER_DREAMER_MENU_ID => {
107- if let Err ( error) = trigger_dreamer ( app) {
108- eprintln ! ( "failed to trigger dreamer from tray: {error}" ) ;
109- }
123+ CHECK_UPDATES_MENU_ID => {
124+ show_main_window ( app) ;
125+ let _ = app. emit ( "check-for-updates" , ( ) ) ;
110126 }
111127 QUIT_MENU_ID => app. exit ( 0 ) ,
112128 _ => { }
0 commit comments