feat(note): page background templates (rnote-style)
Some checks failed
CI / Windows build (push) Has been cancelled
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:
@@ -24,6 +24,7 @@ import '../layout/viewport_fit.dart';
|
||||
import '../notebook/ink_stroke_adapter.dart';
|
||||
import '../ui/pen_settings_page.dart';
|
||||
import 'editor_tool.dart';
|
||||
import 'note_background.dart';
|
||||
import 'pen_canvas.dart';
|
||||
import 'pen_palette_widgets.dart';
|
||||
import 'pen_stroke.dart';
|
||||
@@ -83,6 +84,10 @@ class _PenNoteScreenState extends ConsumerState<PenNoteScreen> {
|
||||
/// The active drawing color (the active brush's remembered color).
|
||||
Color get _color => _brushColors[_activeColorBrush] ?? Colors.black;
|
||||
|
||||
/// The page-background template painted behind the ink (rnote-style). Default
|
||||
/// blank; persisted per-notebook in the sidecar.
|
||||
NoteBackground _background = NoteBackground.blank;
|
||||
|
||||
bool _allowFingerDrawing = false;
|
||||
bool _dirty = false;
|
||||
bool _needsCenter = true;
|
||||
@@ -151,6 +156,7 @@ class _PenNoteScreenState extends ConsumerState<PenNoteScreen> {
|
||||
if (title != null && title.isNotEmpty) {
|
||||
_titleController.text = title;
|
||||
}
|
||||
_background = noteBackgroundFromName(repo.loadedBackground);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -288,6 +294,7 @@ class _PenNoteScreenState extends ConsumerState<PenNoteScreen> {
|
||||
for (final s in _strokes) EditorStroke.fromPenStroke(s),
|
||||
];
|
||||
repo.scheduleTitleSave(title);
|
||||
repo.scheduleBackgroundSave(_background.name);
|
||||
repo.scheduleStrokeSave(_notePageIndex, editorStrokes);
|
||||
await repo.flush();
|
||||
|
||||
@@ -475,8 +482,10 @@ class _PenNoteScreenState extends ConsumerState<PenNoteScreen> {
|
||||
allowFingerDrawing: _allowFingerDrawing,
|
||||
onStrokeComplete: _commitStroke,
|
||||
onEraseStroke: _eraseStroke,
|
||||
// A white sheet with a soft shadow — the note "paper".
|
||||
pageWidget: Container(
|
||||
// A white sheet with a soft shadow — the note "paper" — overlaid with
|
||||
// the selected background template, painted in page-pixel space (so it
|
||||
// scales with zoom) and BEHIND the ink layers.
|
||||
pageWidget: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
@@ -487,6 +496,10 @@ class _PenNoteScreenState extends ConsumerState<PenNoteScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
child: CustomPaint(
|
||||
painter: NoteBackgroundPainter(_background),
|
||||
size: Size.infinite,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -570,6 +583,55 @@ class _PenNoteScreenState extends ConsumerState<PenNoteScreen> {
|
||||
PaletteDivider(cs: cs),
|
||||
for (final c in _palette) _colorDot(c, cs),
|
||||
PaletteDivider(cs: cs),
|
||||
// Page-background template picker (rnote-style: blank / dots / ruled
|
||||
// / grid / cornell). Persists per-notebook in the sidecar.
|
||||
PopupMenuButton<NoteBackground>(
|
||||
tooltip: 'Page background',
|
||||
initialValue: _background,
|
||||
onSelected: (b) {
|
||||
setState(() {
|
||||
_background = b;
|
||||
_dirty = true;
|
||||
});
|
||||
},
|
||||
itemBuilder: (context) => [
|
||||
for (final b in NoteBackground.values)
|
||||
PopupMenuItem<NoteBackground>(
|
||||
value: b,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(noteBackgroundIcon(b), size: 20),
|
||||
const SizedBox(width: 10),
|
||||
Text(noteBackgroundLabel(b)),
|
||||
if (b == _background) ...[
|
||||
const SizedBox(width: 8),
|
||||
Icon(Icons.check, size: 18, color: cs.primary),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 8),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
noteBackgroundIcon(_background),
|
||||
size: 22,
|
||||
color: cs.onSurfaceVariant,
|
||||
),
|
||||
Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 18,
|
||||
color: cs.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
PaletteDivider(cs: cs),
|
||||
ToolButton(
|
||||
icon: _allowFingerDrawing ? Icons.touch_app : Icons.do_not_touch,
|
||||
selected: _allowFingerDrawing,
|
||||
|
||||
Reference in New Issue
Block a user