feat(storage): notes are vault sidecar notebooks
All checks were successful
CI / Windows build (push) Successful in 12m55s

Phase 4. Standalone notes move off SQLite into the vault, like the
PDF annotations.

- "Create notebook" makes a vault folder with a notebook.badnote.json
  (BadnoteSidecar docType 'notebook' + a title field), opened via
  SidecarRepository.
- PenNoteScreen loads/saves its strokes (page 0) + title to that
  sidecar instead of the SQLite Note model.
- note_provider lists notes from a vault scan (VaultService.scanNotes
  = folders with notebook.badnote.json and no source file); the doc
  scan still excludes them. Delete removes the folder.

PDF/slide editors unchanged; pre-existing SQLite notes migrate in
Phase 5. analyze clean, tests green.
This commit is contained in:
2026-06-24 22:48:18 +08:00
parent 2f0fda5f95
commit f4f0853eae
14 changed files with 598 additions and 70 deletions

View File

@@ -87,8 +87,18 @@ class SidecarRepository {
/// The current in-memory sidecar (for tests / inspection).
BadnoteSidecar get sidecar => _sidecar;
/// The standalone-notebook title loaded from the sidecar, or null.
String? get loadedTitle => _sidecar.title;
// ── Mutations (synchronous in-memory update + debounced atomic write) ──────
/// Replace the standalone-notebook title and schedule a save. No-op if the
/// title is unchanged.
void scheduleTitleSave(String title) {
if (_sidecar.title == title) return;
_replace(title: title);
}
/// Replace the committed strokes for [pageIndex] and schedule a save.
void scheduleStrokeSave(int pageIndex, List<EditorStroke> strokes) {
final next = Map<int, List<EditorStroke>>.from(_sidecar.strokes);
@@ -176,6 +186,7 @@ class SidecarRepository {
/// given fields replaced, then arm the debounce timer. Snapshot is captured
/// synchronously here so a later edit can't corrupt an in-flight write.
void _replace({
String? title,
Map<int, List<EditorStroke>>? strokes,
Map<int, List<SidecarHighlight>>? highlights,
List<SidecarScratchLink>? scratchLinks,
@@ -185,6 +196,7 @@ class SidecarRepository {
version: _sidecar.version,
sourceFile: _sidecar.sourceFile,
docType: _sidecar.docType,
title: title ?? _sidecar.title,
pageCount: _sidecar.pageCount,
rotation: _sidecar.rotation,
createdAt: _sidecar.createdAt,