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.
This commit is contained in:
56
lib/editor/engine/stroke_store.dart
Normal file
56
lib/editor/engine/stroke_store.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user