feat(note): rebuild note editor on the pen-first canvas
Some checks failed
CI / Windows build (push) Has been cancelled

Notes now use the single performant inking engine (PenCanvas) instead of
the old ink_canvas, per "all note features on the pen-first canvas".

- ink_stroke_adapter: pure InkStroke<->PenStroke bridge (normalize against
  a logical note page; drop non-freehand shapes/text). Round-trip tested.
- pen_palette_widgets: shared M3 ToolButton/PaletteDivider/RoundIconButton
  so PDF + note editors use identical chrome (PenEditorScreen migrated to
  them; its private copies deleted).
- PenNoteScreen: PenCanvas over a white logical page, undo/redo, title,
  save -> Note.strokes (+ local OCR for search). Pressure curve, eraser
  size/mode and palm rejection all inherited from the shared canvas.
- Route home (new/open) + search note hits -> PenNoteScreen; remove the
  now-redundant "Pen Canvas (beta)" spike button; delete the dead old
  note_editor_screen.

Tests: ink_stroke_adapter (5) + pen_note_screen widget (load + commit, 2).
flutter analyze: 0 issues. Full suite: 265/265.
This commit is contained in:
2026-06-23 10:21:40 +08:00
parent 3507e929b1
commit dfe5f2a477
12 changed files with 8769 additions and 418 deletions

View File

@@ -7,10 +7,9 @@ import '../providers/document_provider.dart';
import '../providers/note_provider.dart';
import '../providers/ocr_provider.dart';
import '../editor/canvas/pen_editor_screen.dart';
import '../editor/pdf/spike_launcher.dart';
import '../services/pdf_service.dart';
import '../services/pptx_service.dart';
import 'note_editor_screen.dart';
import '../editor/canvas/pen_note_screen.dart';
import 'ppt_annotator_screen.dart';
import 'search_screen.dart';
import 'settings_screen.dart';
@@ -70,12 +69,6 @@ class HomeScreen extends ConsumerWidget {
).push(MaterialPageRoute(builder: (_) => const SearchScreen()));
},
),
// New pen-first canvas editor (beta).
IconButton(
icon: const Icon(Icons.draw_outlined),
tooltip: l.penCanvasBeta,
onPressed: () => openM1Spike(context),
),
],
),
floatingActionButton: FloatingActionButton(
@@ -196,7 +189,7 @@ class HomeScreen extends ConsumerWidget {
if (context.mounted) {
Navigator.of(
context,
).push(MaterialPageRoute(builder: (_) => NoteEditorScreen(note: note)));
).push(MaterialPageRoute(builder: (_) => PenNoteScreen(note: note)));
}
}
@@ -375,7 +368,7 @@ class _NoteTileState extends ConsumerState<_NoteTile> {
),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => NoteEditorScreen(note: note)),
MaterialPageRoute(builder: (_) => PenNoteScreen(note: note)),
);
},
onLongPress: () => _confirmDelete(context),
@@ -425,7 +418,7 @@ class _NoteTileState extends ConsumerState<_NoteTile> {
if (!mounted) return;
if (result == 'open') {
Navigator.of(this.context).push(
MaterialPageRoute(builder: (_) => NoteEditorScreen(note: widget.note)),
MaterialPageRoute(builder: (_) => PenNoteScreen(note: widget.note)),
);
} else if (result == 'delete') {
_confirmDelete(this.context);