From e18664ea8c61ba43db783c27c6f02973e5ac9311 Mon Sep 17 00:00:00 2001 From: garrettmills Date: Tue, 7 Jul 2026 20:55:05 -0500 Subject: [PATCH] Persist last-opened library file across restarts; fix path-switch bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remember which library.db was last chosen (via a small config.json in the app-data dir) so relaunching the app reopens the same file instead of always defaulting to library.db. - Fix set_library_path returning a hard error (and thus never updating the topbar) whenever the reference catalog fails to reopen against the new path — e.g. a stale reference.db schema. Picking a library file and successfully reattaching the reference db are separate concerns; the chosen path now always persists and is reported back, with the catalog reopened best-effort. Co-Authored-By: Claude Sonnet 5 --- src-tauri/src/commands.rs | 8 ++++-- src-tauri/src/state.rs | 52 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 9913fb0..f728103 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -40,8 +40,12 @@ pub fn get_status(db: Db) -> Res { #[tauri::command] pub fn set_library_path(db: Db, path: String) -> Res { let mut s = db.lock().unwrap(); - s.library_path = PathBuf::from(path); - s.reopen()?; + s.set_library_path(PathBuf::from(path)); + // Best-effort reopen: the chosen path must stick (and be reported back) + // even if the reference db can't currently be attached (e.g. stale + // schema pending an "Update card data" run) — that's a separate concern + // from which library file is open. + let _ = s.reopen(); Ok(status_of(&s)) } diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index ba17812..fa4c24b 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -1,11 +1,37 @@ //! App state: the open [`Catalog`] and fuzzy [`NameIndex`], plus the db paths. -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use mtgc_core::{Catalog, NameIndex}; +use serde::{Deserialize, Serialize}; + +/// Small app-shell preferences persisted across restarts (distinct from the +/// user's library data) — currently just which library file was last open. +#[derive(Default, Serialize, Deserialize)] +struct PersistedConfig { + library_path: Option, +} + +fn config_path(data_dir: &Path) -> PathBuf { + data_dir.join("config.json") +} + +fn load_config(data_dir: &Path) -> PersistedConfig { + std::fs::read_to_string(config_path(data_dir)) + .ok() + .and_then(|s| serde_json::from_str(&s).ok()) + .unwrap_or_default() +} + +fn save_config(data_dir: &Path, cfg: &PersistedConfig) { + if let Ok(s) = serde_json::to_string_pretty(cfg) { + let _ = std::fs::write(config_path(data_dir), s); + } +} /// Managed application state, guarded by a `Mutex` in Tauri's state store. pub struct AppState { + data_dir: PathBuf, pub library_path: PathBuf, pub reference_path: PathBuf, pub catalog: Option, @@ -16,12 +42,18 @@ pub struct AppState { } impl AppState { - /// Initialize with default paths under the app data dir and open the catalog - /// if a reference db already exists. + /// Initialize with the last-opened library path (or the default under the + /// app data dir, on first run) and open the catalog if a reference db + /// already exists. pub fn new(data_dir: PathBuf) -> Self { + let cfg = load_config(&data_dir); + let library_path = cfg + .library_path + .unwrap_or_else(|| data_dir.join("library.db")); let mut s = Self { - library_path: data_dir.join("library.db"), reference_path: data_dir.join("reference.db"), + library_path, + data_dir, catalog: None, index: None, ingest_cancel: None, @@ -31,6 +63,18 @@ impl AppState { s } + /// Point at a different library file and persist it so the next launch + /// reopens the same one. + pub fn set_library_path(&mut self, path: PathBuf) { + self.library_path = path.clone(); + save_config( + &self.data_dir, + &PersistedConfig { + library_path: Some(path), + }, + ); + } + /// (Re)open the catalog + rebuild the name index. Only opens when a reference /// db exists — attaching a non-existent file would create an empty (tableless) /// db and make every query fail.