| 25 |
25 |
|
#[cfg(not(any(target_os = "ios", target_os = "android")))]
|
| 26 |
26 |
|
use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent};
|
| 27 |
27 |
|
|
|
28 |
+ |
/// Report a fatal startup error to the user, then exit.
|
|
29 |
+ |
///
|
|
30 |
+ |
/// Never returns, and must not panic. This runs inside NSApp's
|
|
31 |
+ |
/// `didFinishLaunching` callback, which is nounwind, so a panic here aborts the
|
|
32 |
+ |
/// process and reduces the message to a bare SIGABRT with no diagnostic text.
|
|
33 |
+ |
///
|
|
34 |
+ |
/// Uses rfd rather than tauri-plugin-dialog because Tauri's event loop has not
|
|
35 |
+ |
/// started yet at this point in setup: the plugin's `show` has no loop to paint
|
|
36 |
+ |
/// from or deliver its callback to, and its `blocking_show` is documented as
|
|
37 |
+ |
/// unsafe to call on the main thread. rfd drives a native modal directly.
|
|
38 |
+ |
#[cfg(not(any(target_os = "ios", target_os = "android")))]
|
|
39 |
+ |
fn fatal_startup_error(message: &str) -> ! {
|
|
40 |
+ |
tracing::error!("{}", message);
|
|
41 |
+ |
|
|
42 |
+ |
rfd::MessageDialog::new()
|
|
43 |
+ |
.set_level(rfd::MessageLevel::Error)
|
|
44 |
+ |
.set_title("GoingsOn cannot start")
|
|
45 |
+ |
.set_description(message)
|
|
46 |
+ |
.show();
|
|
47 |
+ |
|
|
48 |
+ |
std::process::exit(1);
|
|
49 |
+ |
}
|
|
50 |
+ |
|
|
51 |
+ |
/// Mobile has no rfd backend, so the error goes to the log and the process exits.
|
|
52 |
+ |
#[cfg(any(target_os = "ios", target_os = "android"))]
|
|
53 |
+ |
fn fatal_startup_error(message: &str) -> ! {
|
|
54 |
+ |
tracing::error!("{}", message);
|
|
55 |
+ |
std::process::exit(1);
|
|
56 |
+ |
}
|
|
57 |
+ |
|
| 28 |
58 |
|
/// Set up the macOS menu bar tray icon showing "GO" in Reglo.
|
| 29 |
59 |
|
#[cfg(not(any(target_os = "ios", target_os = "android")))]
|
| 30 |
60 |
|
fn setup_tray(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
| 304 |
334 |
|
// Initialize database
|
| 305 |
335 |
|
let app_handle = app.handle().clone();
|
| 306 |
336 |
|
tauri::async_runtime::block_on(async move {
|
| 307 |
|
- |
let state = AppState::new(&app_handle).await
|
| 308 |
|
- |
.expect("Failed to initialize app state");
|
|
337 |
+ |
let state = match AppState::new(&app_handle).await {
|
|
338 |
+ |
Ok(state) => state,
|
|
339 |
+ |
Err(e) => fatal_startup_error(&e),
|
|
340 |
+ |
};
|
| 309 |
341 |
|
// Reclaim orphaned attachment blobs before the schedulers spawn
|
| 310 |
342 |
|
// and before the UI can create attachments — race-free here.
|
| 311 |
343 |
|
blob_gc::reconcile(&state.pool, &state.data_dir).await;
|