Files
BadNote/lib/editor/engine/stroke_store.dart
Akiba So 914951afb7 feat(engine): P0 stroke engine + persistence
Per the full-refactor plan §9 (input-independent half of P0):
- engine: canonical EditorStroke (lossless InkStroke round-trip) +
  stroke_geometry (single getStroke outline) + revision-gated StrokeStore
- render: static/live ink painters + ink_picture_cache (revision-keyed)
  + annotation_layer (RepaintBoundary)
- persistence: DB v6 (ink, notebook_pages) + editor_repository diff-write
  (UPSERT changed / DELETE removed in one txn; id-set after commit) +
  save_scheduler
- pdf_service export now FILLS the getStroke outline (R7 hairline fix)
Not yet wired into the live editor (input relocation pending pen-pressure
diagnostic). 28 new tests pass.
2026-06-21 23:41:01 +08:00

57 lines
1.7 KiB
Dart

// lib/editor/engine/stroke_store.dart
//
// Mutable, revision-tracked store for committed EditorStrokes.
//
// Every mutation bumps [revision] (monotonic int). Consumers use the revision
// as an O(1) repaint gate: if revision has not changed since the last paint,
// nothing needs to be redrawn (StaticInkPainter.shouldRepaint).
import 'stroke_model.dart';
/// Holds the ordered list of committed [EditorStroke]s for one ink host (e.g.
/// a page or annotation layer). Every mutating operation bumps [revision].
///
/// This class is intentionally NOT a ChangeNotifier / Listenable — callers
/// poll the revision number from within CustomPainter.shouldRepaint, so no
/// subscription machinery is needed here.
class StrokeStore {
final List<EditorStroke> _strokes = [];
int _revision = 0;
/// Monotonically increasing counter. Bumped on every mutation.
int get revision => _revision;
/// Unmodifiable ordered list of committed strokes.
List<EditorStroke> get committed => List.unmodifiable(_strokes);
/// Appends [stroke] and bumps the revision.
void add(EditorStroke stroke) {
_strokes.add(stroke);
_revision++;
}
/// Removes the stroke with the given [id] (no-op if not found) and bumps
/// the revision only when a stroke was actually removed.
void removeById(String id) {
final before = _strokes.length;
_strokes.removeWhere((s) => s.id == id);
if (_strokes.length != before) {
_revision++;
}
}
/// Replaces the entire stroke list and bumps the revision.
void replaceAll(List<EditorStroke> strokes) {
_strokes
..clear()
..addAll(strokes);
_revision++;
}
/// Clears all strokes and bumps the revision.
void clear() {
_strokes.clear();
_revision++;
}
}