feat(pdf): anchored scratch links replace board
Some checks failed
CI / Windows build (push) Has been cancelled
Some checks failed
CI / Windows build (push) Has been cancelled
Replace the rejected standalone sticky-card board with the real feature: place a link anchor anywhere on a PDF page, tap it to open split view whose right pane is THAT anchor's own infinite scratchpad (keyed by anchor id) — like a paper sticky-note tab. - ScratchLink model + scratch_links table (id, doc, page, nx, ny). - PDF editor: "place link" tool drops/loads/shows tappable markers; tap opens SplitViewScreen for that anchor; long-press deletes. - SplitViewScreen rebuilt on pdfrx (was syncfusion), right scratchpad keyed by scratchLinkId, new brush palette (was AnnotationToolbar). - Remove board_screen + its test + the home board entry. analyze clean, tests green.
This commit is contained in:
@@ -11,10 +11,8 @@ import '../services/pdf_service.dart';
|
||||
import '../services/pptx_service.dart';
|
||||
import '../editor/canvas/pen_note_screen.dart';
|
||||
import '../editor/canvas/pen_slide_screen.dart';
|
||||
import 'board_screen.dart';
|
||||
import 'search_screen.dart';
|
||||
import 'settings_screen.dart';
|
||||
import 'split_view_screen.dart';
|
||||
|
||||
// [M1] Relative date helper — no new package dependencies.
|
||||
String _formatDate(DateTime d) {
|
||||
@@ -61,15 +59,6 @@ class HomeScreen extends ConsumerWidget {
|
||||
tooltip: l.importPpt,
|
||||
onPressed: () => _importPptx(context),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.dashboard_customize),
|
||||
tooltip: l.boardOpen,
|
||||
onPressed: () {
|
||||
Navigator.of(
|
||||
context,
|
||||
).push(MaterialPageRoute(builder: (_) => const BoardScreen()));
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.search),
|
||||
tooltip: l.search,
|
||||
@@ -502,32 +491,18 @@ class _DocumentTileState extends ConsumerState<_DocumentTile> {
|
||||
'${document.docType.toUpperCase()} · ${document.pageCount} pages · $dateStr',
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
// [H2] Trailing row: split-view (PDF only) + remove
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (isPdf)
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.vertical_split,
|
||||
color: _hovering
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: subtleColor.withValues(alpha: 0.4),
|
||||
),
|
||||
tooltip: 'Open in Split View',
|
||||
onPressed: () => _openSplitView(context),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.delete_outline,
|
||||
color: _hovering
|
||||
? Theme.of(context).colorScheme.error
|
||||
: subtleColor.withValues(alpha: 0.4),
|
||||
),
|
||||
tooltip: 'Remove document',
|
||||
onPressed: () => _confirmDelete(context),
|
||||
),
|
||||
],
|
||||
// [H2] Trailing remove button. Split view is now reached only by
|
||||
// tapping a scratch-link anchor inside the PDF editor, so the
|
||||
// standalone split-view entry was removed.
|
||||
trailing: IconButton(
|
||||
icon: Icon(
|
||||
Icons.delete_outline,
|
||||
color: _hovering
|
||||
? Theme.of(context).colorScheme.error
|
||||
: subtleColor.withValues(alpha: 0.4),
|
||||
),
|
||||
tooltip: 'Remove document',
|
||||
onPressed: () => _confirmDelete(context),
|
||||
),
|
||||
// [L2] Routing bug fix: route by docType
|
||||
onTap: () => _openDocument(context),
|
||||
@@ -577,19 +552,7 @@ class _DocumentTileState extends ConsumerState<_DocumentTile> {
|
||||
}
|
||||
}
|
||||
|
||||
void _openSplitView(BuildContext context) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => SplitViewScreen(
|
||||
filePath: widget.document.filePath,
|
||||
documentId: widget.document.id,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showContextMenu(BuildContext context, Offset position) async {
|
||||
final isPdf = widget.document.docType == 'pdf';
|
||||
final result = await showMenu<String>(
|
||||
context: context,
|
||||
position: RelativeRect.fromLTRB(
|
||||
@@ -609,17 +572,6 @@ class _DocumentTileState extends ConsumerState<_DocumentTile> {
|
||||
],
|
||||
),
|
||||
),
|
||||
if (isPdf)
|
||||
PopupMenuItem(
|
||||
value: 'split',
|
||||
child: Row(
|
||||
children: const [
|
||||
Icon(Icons.vertical_split),
|
||||
SizedBox(width: 8),
|
||||
Text('Open in Split View'),
|
||||
],
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 'remove',
|
||||
child: Row(
|
||||
@@ -641,15 +593,12 @@ class _DocumentTileState extends ConsumerState<_DocumentTile> {
|
||||
if (!mounted) return;
|
||||
if (result == 'open') {
|
||||
_openDocument(this.context);
|
||||
} else if (result == 'split') {
|
||||
_openSplitView(this.context);
|
||||
} else if (result == 'remove') {
|
||||
_confirmDelete(this.context);
|
||||
}
|
||||
}
|
||||
|
||||
void _showDocumentMenu(BuildContext context) {
|
||||
final isPdf = widget.document.docType == 'pdf';
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (ctx) {
|
||||
@@ -657,16 +606,6 @@ class _DocumentTileState extends ConsumerState<_DocumentTile> {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (isPdf)
|
||||
ListTile(
|
||||
leading: const Icon(Icons.vertical_split),
|
||||
title: const Text('Open in Split View'),
|
||||
subtitle: const Text('PDF reference + scratchpad'),
|
||||
onTap: () {
|
||||
Navigator.of(ctx).pop();
|
||||
_openSplitView(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.delete_outline, color: Colors.red),
|
||||
title: const Text(
|
||||
|
||||
Reference in New Issue
Block a user