Persist last-opened library file across restarts; fix path-switch bug

- 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 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 20:55:05 -05:00
parent 2ea3c56511
commit e18664ea8c
2 changed files with 54 additions and 6 deletions

View File

@@ -40,8 +40,12 @@ pub fn get_status(db: Db) -> Res<Status> {
#[tauri::command]
pub fn set_library_path(db: Db, path: String) -> Res<Status> {
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))
}

View File

@@ -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<PathBuf>,
}
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<Catalog>,
@@ -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.