diff --git a/src-tauri/src/autostart.rs b/src-tauri/src/autostart.rs new file mode 100644 index 0000000..0ca9c4b --- /dev/null +++ b/src-tauri/src/autostart.rs @@ -0,0 +1,17 @@ +use tauri::AppHandle; +use tauri_plugin_autostart::ManagerExt; + +#[tauri::command] +pub fn is_autostart_enabled_cmd(app: AppHandle) -> Result { + Ok(app.autolaunch().is_enabled().unwrap_or(false)) +} + +#[tauri::command] +pub fn set_autostart_cmd(app: AppHandle, enabled: bool) -> Result<(), String> { + let result = if enabled { + app.autolaunch().enable() + } else { + app.autolaunch().disable() + }; + result.map_err(|e| format!("Failed to set autostart: {}", e)) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index a5e9034..bb37efd 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,5 +1,6 @@ mod avatars; mod auth; +mod autostart; mod github; mod menu; mod models; @@ -11,7 +12,6 @@ mod updater; use tauri::tray::TrayIconBuilder; use tauri::{Emitter, Manager}; -use tauri_plugin_autostart::ManagerExt; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { @@ -44,7 +44,9 @@ pub fn run() { settings::get_settings_cmd, settings::save_settings_cmd, updater::check_for_update_cmd, - updater::install_update_cmd + updater::install_update_cmd, + autostart::is_autostart_enabled_cmd, + autostart::set_autostart_cmd ]) .setup(|app| { // Restore saved auth token from disk (if any) @@ -202,30 +204,6 @@ fn handle_menu_event(app: &tauri::AppHandle, id: &str) { }); } - "autostart_toggle" => { - let currently_enabled = app.autolaunch().is_enabled().unwrap_or(false); - let toggle_result = if currently_enabled { - app.autolaunch().disable() - } else { - app.autolaunch().enable() - }; - if let Err(e) = toggle_result { - eprintln!("[autostart] Failed to toggle autostart: {}", e); - } - - let prs = { - let state = app.state::(); - let val = state.prs.lock().unwrap().clone(); - val - }; - let state = app.state::(); - let tray_guard = state.tray.lock().unwrap(); - if let Some(tray) = tray_guard.as_ref() { - if let Ok(new_menu) = menu::build_pr_menu(app, &prs, &state.avatar_cache) { - let _ = tray.set_menu(Some(new_menu)); - } - } - } "sign_in" => { let app = app.clone(); diff --git a/src-tauri/src/menu.rs b/src-tauri/src/menu.rs index bfda46d..cde5643 100644 --- a/src-tauri/src/menu.rs +++ b/src-tauri/src/menu.rs @@ -1,6 +1,5 @@ use tauri::AppHandle; -use tauri::menu::{CheckMenuItem, IconMenuItem, Menu, MenuItem, PredefinedMenuItem}; -use tauri_plugin_autostart::ManagerExt; +use tauri::menu::{IconMenuItem, Menu, MenuItem, PredefinedMenuItem}; use crate::avatars::AvatarCache; use crate::models::{CheckStatus, PrState, PullRequest}; @@ -192,24 +191,13 @@ pub fn build_pr_menu( menu.append(&see_all)?; let refresh = MenuItem::with_id(app, "refresh", "Refresh", true, None::<&str>)?; menu.append(&refresh)?; + let sep2 = PredefinedMenuItem::separator(app)?; + menu.append(&sep2)?; let check_updates = MenuItem::with_id(app, "check_updates", "Check for Updates", true, None::<&str>)?; menu.append(&check_updates)?; - let autostart_enabled = app.autolaunch().is_enabled().unwrap_or(false); - let autostart_toggle = CheckMenuItem::with_id( - app, - "autostart_toggle", - "Launch at login", - true, - autostart_enabled, - None::<&str>, - )?; - menu.append(&autostart_toggle)?; - let settings = - MenuItem::with_id(app, "settings", "Settings...", true, None::<&str>)?; + let settings = MenuItem::with_id(app, "settings", "Settings", true, None::<&str>)?; menu.append(&settings)?; - let sep2 = PredefinedMenuItem::separator(app)?; - menu.append(&sep2)?; let logout = MenuItem::with_id(app, "logout", "Logout", true, None::<&str>)?; menu.append(&logout)?; let quit = MenuItem::with_id(app, "quit", "Quit PR Buddy", true, None::<&str>)?; diff --git a/src/lib/SettingsPage.svelte b/src/lib/SettingsPage.svelte index ae02737..8e13e1a 100644 --- a/src/lib/SettingsPage.svelte +++ b/src/lib/SettingsPage.svelte @@ -28,15 +28,34 @@ let loaded = $state(false); let currentTheme = $state("system"); let setThemePreference: (t: ThemePreference) => void = () => {}; + let launchAtLoginEnabled = $state(false); + let autoStartLoaded = $state(false); + let autoStartToggleCount = 0; // generation counter to discard stale reads/rollbacks // Serialize saves so rapid toggles don't race each other let saveChain = Promise.resolve(); + let autoStartChain = Promise.resolve(); onMount(() => { void loadSettings(); + void loadAutostartSetting(); void initTheme(); }); + async function loadAutostartSetting() { + const gen = autoStartToggleCount; + try { + const enabled = await invoke("is_autostart_enabled_cmd"); + // Only apply if user hasn't toggled while we were loading + if (autoStartToggleCount === gen) { + launchAtLoginEnabled = Boolean(enabled); + } + } catch (e) { + console.error("[settings] Failed to load autostart setting:", e); + } finally { + autoStartLoaded = true; + } + } async function initTheme() { if (typeof window !== "undefined" && typeof window.matchMedia !== "function") { @@ -92,6 +111,21 @@ void save(); } + function toggleLaunchAtLogin() { + const enabled = !launchAtLoginEnabled; + launchAtLoginEnabled = enabled; + const gen = ++autoStartToggleCount; + autoStartChain = autoStartChain + .then(async () => { await invoke("set_autostart_cmd", { enabled }); }) + .catch((e: unknown) => { + console.error("[settings] Failed to set autostart setting:", e); + // Only rollback if no newer toggle has happened since + if (autoStartToggleCount === gen) { + launchAtLoginEnabled = !enabled; + } + }); + } + function toggleRepo(repo: string) { const idx = settings.hidden_repos.indexOf(repo); if (idx >= 0) { @@ -143,6 +177,29 @@
{:else} + +
+

General

+ +
+

Theme