From 0d0ecee06e136024e3c3a3f79962a56ef6052fc3 Mon Sep 17 00:00:00 2001 From: Yuri Karamian Date: Mon, 8 Jun 2026 01:12:32 +0200 Subject: [PATCH] Add 'Restore last session on launch' setting (reopen last note + view) --- src-tauri/src/commands.rs | 2 + src-tauri/src/types.rs | 12 +++++ src/lib/api.ts | 2 + src/lib/components/AppLayout.svelte | 59 ++++++++++++++++++++++++- src/lib/components/SettingsPanel.svelte | 14 +++++- src/lib/types.ts | 4 ++ 6 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 43d7d7d..dc18883 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -831,10 +831,12 @@ pub fn set_general_settings( close_to_tray: bool, enable_wiki_links: bool, show_note_dates: bool, + restore_last_session: bool, ) -> Result<(), String> { let mut config = state.config.lock().map_err(|e| e.to_string())?; config.compact_notes = compact_notes; config.show_note_dates = show_note_dates; + config.restore_last_session = restore_last_session; config.time_format = time_format; config.gpu_acceleration = gpu_acceleration; config.autostart = autostart; diff --git a/src-tauri/src/types.rs b/src-tauri/src/types.rs index 186230b..127bcc7 100644 --- a/src-tauri/src/types.rs +++ b/src-tauri/src/types.rs @@ -131,6 +131,8 @@ pub struct AppConfig { pub close_to_tray: bool, #[serde(default = "default_true")] pub enable_wiki_links: bool, + #[serde(default)] + pub restore_last_session: bool, // WebDAV sync (opt-in; all off by default). Endpoint is fully user-configured. #[serde(default)] pub sync_provider: Option, @@ -219,6 +221,7 @@ impl Default for AppConfig { show_tray_icon: false, close_to_tray: false, enable_wiki_links: true, + restore_last_session: false, sync_provider: None, webdav_url: None, webdav_username: None, @@ -245,6 +248,12 @@ pub struct VaultState { pub notebook_order: std::collections::HashMap, #[serde(default)] pub sort_mode: String, + #[serde(default)] + pub last_view_mode: String, + #[serde(default)] + pub last_notebook: Option, + #[serde(default)] + pub last_tag: Option, } impl Default for VaultState { @@ -258,6 +267,9 @@ impl Default for VaultState { notebook_sort_mode: String::new(), notebook_order: std::collections::HashMap::new(), sort_mode: String::new(), + last_view_mode: String::new(), + last_notebook: None, + last_tag: None, } } } diff --git a/src/lib/api.ts b/src/lib/api.ts index c23cf8b..79e244a 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -226,6 +226,7 @@ export async function setGeneralSettings( closeToTray: boolean, enableWikiLinks: boolean, showNoteDates: boolean, + restoreLastSession: boolean, ): Promise { return invoke("set_general_settings", { compactNotes, @@ -242,6 +243,7 @@ export async function setGeneralSettings( closeToTray, enableWikiLinks, showNoteDates, + restoreLastSession, }); } diff --git a/src/lib/components/AppLayout.svelte b/src/lib/components/AppLayout.svelte index 4b9e61c..149600f 100644 --- a/src/lib/components/AppLayout.svelte +++ b/src/lib/components/AppLayout.svelte @@ -33,6 +33,8 @@ quickAccessPaths, tags, notes, + notebooks, + rootNoteCount, viewMode, sortMode, activeTag, @@ -53,7 +55,16 @@ import { debounce } from '$lib/utils/debounce'; import { openNoteWindow } from '$lib/utils/window'; import { get } from 'svelte/store'; - import type { VaultState, FileEvent } from '$lib/types'; + import type { VaultState, FileEvent, NotebookEntry } from '$lib/types'; + + function findNotebookByPath(list: NotebookEntry[], relPath: string): NotebookEntry | null { + for (const nb of list) { + if (nb.relative_path === relPath) return nb; + const found = findNotebookByPath(nb.children, relPath); + if (found) return found; + } + return null; + } let sidebar: Sidebar; let noteList: NoteList; @@ -186,7 +197,10 @@ collapsed_notebooks: $collapsedNotebooks, notebook_sort_mode: $notebookSortMode, notebook_order: $notebookOrder, - sort_mode: $sortMode + sort_mode: $sortMode, + last_view_mode: $viewMode, + last_notebook: $activeNotebook?.relative_path ?? null, + last_tag: $activeTag }; try { await saveVaultState(state); @@ -428,8 +442,18 @@ persistState(); }); + $effect(() => { + $viewMode; + $activeNotebook; + $activeTag; + persistState(); + }); + onMount(async () => { let lastNotePath: string | null = null; + let lastViewMode = ''; + let lastNotebook: string | null = null; + let lastTag: string | null = null; try { const state = await loadVaultState(); $sidebarWidth = state.sidebar_width; @@ -440,6 +464,9 @@ $notebookOrder = state.notebook_order ?? {}; if (state.sort_mode === 'created' || state.sort_mode === 'title' || state.sort_mode === 'modified') $sortMode = state.sort_mode; lastNotePath = state.last_open_note ?? null; + lastViewMode = state.last_view_mode ?? ''; + lastNotebook = state.last_notebook ?? null; + lastTag = state.last_tag ?? null; } catch (_) {} // On mobile, prefetch last-opened note so first tap is instant @@ -457,6 +484,34 @@ // Run sidebar and note list refresh in parallel await Promise.all([sidebar?.refresh(), noteList?.refresh()]); + // Restore the last session (view + open note) if enabled. + if ($appConfig?.restore_last_session) { + const vault = $appConfig?.active_vault; + if (lastViewMode === 'notebook' && lastNotebook === '' && vault) { + $viewMode = 'notebook'; + $activeNotebook = { name: 'Unfiled Notes', path: vault, relative_path: '', children: [], note_count: $rootNoteCount }; + $activeTag = null; + await noteList?.refresh(); + } else if (lastViewMode === 'notebook' && lastNotebook) { + const nb = findNotebookByPath($notebooks, lastNotebook); + if (nb) { $viewMode = 'notebook'; $activeNotebook = nb; $activeTag = null; await noteList?.refresh(); } + } else if (lastViewMode === 'tag' && lastTag) { + $viewMode = 'tag'; $activeTag = lastTag; $activeNotebook = null; await noteList?.refresh(); + } else if (lastViewMode === 'quickaccess') { + $viewMode = 'quickaccess'; $activeNotebook = null; $activeTag = null; await noteList?.refresh(); + } + // Open the last note on desktop (mobile reopens it via its own prefetch path below). + if (!isMobile && lastNotePath) { + try { + const content = await readNote(lastNotePath); + $activeNote = content; + $activeNotePath = lastNotePath; + $editorDirty = false; + editor?.loadNote(lastNotePath, content.content); + } catch (_) {} + } + } + // On mobile, derive tags from the scanned notes (avoids a separate full-scan Rust call) if (isMobile) { const tagMap = new Map(); diff --git a/src/lib/components/SettingsPanel.svelte b/src/lib/components/SettingsPanel.svelte index 375ae0c..3c2c04f 100644 --- a/src/lib/components/SettingsPanel.svelte +++ b/src/lib/components/SettingsPanel.svelte @@ -458,6 +458,7 @@ // General settings let compactNotes = $state($appConfig?.compact_notes ?? false); let showNoteDates = $state($appConfig?.show_note_dates ?? true); + let restoreLastSession = $state($appConfig?.restore_last_session ?? false); let timeFormat = $state($appConfig?.time_format ?? 'relative'); let gpuAcceleration = $state($appConfig?.gpu_acceleration ?? true); let autostart = $state($appConfig?.autostart ?? false); @@ -514,6 +515,7 @@ if ($appConfig) { $appConfig.compact_notes = compactNotes; $appConfig.show_note_dates = showNoteDates; + $appConfig.restore_last_session = restoreLastSession; $appConfig.time_format = timeFormat; $appConfig.gpu_acceleration = gpuAcceleration; $appConfig.autostart = autostart; @@ -527,7 +529,7 @@ $appConfig.close_to_tray = closeToTray; $appConfig.enable_wiki_links = enableWikiLinks; } - setGeneralSettings(compactNotes, timeFormat, gpuAcceleration, autostart, pdfPreview, pdfHeight, titleMode, hideTitleInBody, showLineNumbers, defaultViewMode, showTrayIcon, closeToTray, enableWikiLinks, showNoteDates) + setGeneralSettings(compactNotes, timeFormat, gpuAcceleration, autostart, pdfPreview, pdfHeight, titleMode, hideTitleInBody, showLineNumbers, defaultViewMode, showTrayIcon, closeToTray, enableWikiLinks, showNoteDates, restoreLastSession) .catch((e) => console.error('Failed to save general settings:', e)); } @@ -649,6 +651,7 @@ if ($appConfig) { compactNotes = $appConfig.compact_notes ?? false; showNoteDates = $appConfig.show_note_dates ?? true; + restoreLastSession = $appConfig.restore_last_session ?? false; timeFormat = $appConfig.time_format ?? 'relative'; gpuAcceleration = $appConfig.gpu_acceleration ?? true; autostart = $appConfig.autostart ?? false; @@ -881,6 +884,15 @@ +
diff --git a/src/lib/types.ts b/src/lib/types.ts index 6c23885..380a93d 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -83,6 +83,7 @@ export interface AppConfig { default_view_mode: boolean; show_tray_icon: boolean; enable_wiki_links: boolean; + restore_last_session: boolean; sync_provider: string | null; webdav_url: string | null; webdav_username: string | null; @@ -102,6 +103,9 @@ export interface VaultState { notebook_sort_mode?: string; notebook_order?: Record; sort_mode?: string; + last_view_mode?: string; + last_notebook?: string | null; + last_tag?: string | null; } export interface SearchResult {