diff --git a/src/App.tsx b/src/App.tsx index 3e67076..0da9eef 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -452,6 +452,32 @@ export default function App() { }, [tab, refreshSync]); + /** + * Point the app at `path` and bring the whole UI into line with it. + * + * Switching documents changes the entire library underneath every view, so + * refreshing the sync panel alone isn't enough: the path bar reads + * `status.library_path`, the sidebar reads `libStats`, and each tab is + * holding rows fetched from the *previous* library. Returns a short " — N + * cards, M decks" suffix so the caller can confirm what actually opened. + */ + async function adoptDocument(path: string): Promise { + setSync(await api.syncSetDocument(path)); + // The path bar comes from get_status, which nothing else re-fetches. + setStatus(await api.getStatus()); + setDeckRefreshSignal((v) => v + 1); + if (!readyRef.current) return ""; + try { + const stats = await api.getLibraryStats(); + setLibStats(stats); + return ` — ${stats.unique_cards} card${stats.unique_cards === 1 ? "" : "s"}, ${ + stats.deck_count + } deck${stats.deck_count === 1 ? "" : "s"}`; + } catch { + return ""; + } + } + /** Choose where the library lives. Android grants a folder through the system * picker (SAF has no path to hand back); desktop picks the JSON file itself. */ async function pickLibrary() { @@ -474,7 +500,8 @@ export default function App() { }); if (typeof path !== "string") return; setSyncBusy(true); - setSync(await api.syncSetDocument(path)); + const opened = await adoptDocument(path); + setSyncTest({ ok: true, message: `Opened ${path}${opened}.` }); } catch (err) { setSyncTest({ ok: false, message: String(err) }); } finally { @@ -495,8 +522,8 @@ export default function App() { setSyncBusy(true); // Pointing at a file that doesn't exist yet moves the current library // there rather than starting empty — see sync_set_document. - setSync(await api.syncSetDocument(path)); - setSyncTest({ ok: true, message: `Your library is now kept at ${path}.` }); + const moved = await adoptDocument(path); + setSyncTest({ ok: true, message: `Your library is now kept at ${path}${moved}.` }); } catch (err) { setSyncTest({ ok: false, message: String(err) }); } finally { @@ -795,12 +822,17 @@ export default function App() { ) : tab === "add" ? ( - ) : tab === "library" ? ( - + ) : /* Keyed on the library document: switching to a different one + replaces every card, deck and id these views are holding, so + they're remounted rather than left to reconcile state that + belongs to a library that's no longer open. Stable across + ordinary status refreshes, so it costs nothing otherwise. */ + tab === "library" ? ( + ) : tab === "search" ? ( - + ) : tab === "decks" ? ( - + ) : ( // The per-install status page: card data, library sync, and the // collection summary. On mobile it's the only home for the