feat(note): page background templates (rnote-style)
Some checks failed
CI / Windows build (push) Has been cancelled

A blank note can show a page-background template painted behind the
ink, picked from the toolbar and persisted per notebook.

- NoteBackground: blank / dots / ruled / grid / cornell, drawn in
  page space (scales with zoom), subtle grey. Cornell = left margin +
  bottom summary rule over a ruled body.
- Stored as the enum name in the notebook sidecar (back-compat:
  missing/unknown -> blank), saved/loaded via SidecarRepository so it
  restores on reopen.
- Picker added to the note tool palette.

PDF backgrounds skipped (PDFs have their own page content). analyze
clean, 386 tests green.
This commit is contained in:
2026-06-24 23:47:29 +08:00
parent 46589a4c87
commit c800295c12
6 changed files with 303 additions and 2 deletions

View File

@@ -224,6 +224,7 @@ class BadnoteSidecar {
Map<int, String>? legacyAnnotations,
this.ocrText,
this.legacyId,
this.background,
}) : strokes = strokes ?? <int, List<EditorStroke>>{},
highlights = highlights ?? <int, List<SidecarHighlight>>{},
bookmarks = bookmarks ?? <Bookmark>[],
@@ -278,6 +279,12 @@ class BadnoteSidecar {
/// its folder name collided). Null for all freshly authored sidecars.
final String? legacyId;
/// The page-background template for a standalone notebook, stored as the
/// [NoteBackground] enum `name` (e.g. `dots`, `cornell`). Kept as a raw String
/// here so the storage model stays UI-decoupled; the editor decodes it via
/// `noteBackgroundFromName` (missing/unknown → blank, back-compat).
final String? background;
Map<String, dynamic> toJson() => {
'badnoteSidecarVersion': version,
if (sourceFile != null) 'sourceFile': sourceFile,
@@ -306,6 +313,7 @@ class BadnoteSidecar {
},
if (ocrText != null && ocrText!.isNotEmpty) 'ocrText': ocrText,
if (legacyId != null) 'legacyId': legacyId,
if (background != null) 'background': background,
};
factory BadnoteSidecar.fromJson(Map<String, dynamic> json) {
@@ -361,6 +369,7 @@ class BadnoteSidecar {
}(),
ocrText: json['ocrText'] as String?,
legacyId: json['legacyId'] as String?,
background: json['background'] as String?,
);
}
}