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

@@ -212,6 +212,7 @@ class BadnoteSidecar {
this.version = kBadnoteSidecarVersion,
this.sourceFile,
this.docType,
this.title,
this.pageCount,
this.rotation = 0,
this.createdAt,
@@ -234,6 +235,10 @@ class BadnoteSidecar {
/// `pdf` / `pptx` / `notebook` etc.
final String? docType;
/// Display title for a standalone (non-file-backed) notebook (`docType ==
/// 'notebook'`). Null for file-backed sidecars, whose title is the filename.
final String? title;
final int? pageCount;
final int rotation;
final DateTime? createdAt;
@@ -252,6 +257,7 @@ class BadnoteSidecar {
'badnoteSidecarVersion': version,
if (sourceFile != null) 'sourceFile': sourceFile,
if (docType != null) 'docType': docType,
if (title != null) 'title': title,
if (pageCount != null) 'pageCount': pageCount,
'rotation': rotation,
if (createdAt != null) 'createdAt': createdAt!.toIso8601String(),
@@ -293,6 +299,7 @@ class BadnoteSidecar {
kBadnoteSidecarVersion,
sourceFile: json['sourceFile'] as String?,
docType: json['docType'] as String?,
title: json['title'] as String?,
pageCount: (json['pageCount'] as num?)?.toInt(),
rotation: (json['rotation'] as num?)?.toInt() ?? 0,
createdAt: json['createdAt'] == null