Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
2026-06-15 17:11:01 +02:00
|
|
|
import 'package:http/http.dart' as http;
|
|
|
|
|
import 'package:http/testing.dart';
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
|
import 'package:todo/data/note.dart';
|
2026-06-15 22:11:08 +02:00
|
|
|
import 'package:todo/sync/local_backup.dart';
|
|
|
|
|
import 'package:todo/sync/notes_markdown.dart';
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
import 'package:todo/ui/capture_screen.dart';
|
2026-06-15 17:11:01 +02:00
|
|
|
import 'package:todo/ui/settings_screen.dart';
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
|
|
|
|
|
import 'fake_note_repository.dart';
|
2026-06-15 22:57:05 +02:00
|
|
|
import 'fake_secure_storage.dart';
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
// A real CRDT DB schedules sqflite timers that never drain under the
|
|
|
|
|
// widget tester's fake clock, so these tests inject a timer-free fake.
|
|
|
|
|
// (NOTE: avoid pumpAndSettle — the autofocused field's cursor blink never
|
|
|
|
|
// settles; pump explicit frames instead.)
|
2026-06-15 17:11:01 +02:00
|
|
|
Future<FakeNoteRepository> pumpCapture(
|
|
|
|
|
WidgetTester tester, {
|
|
|
|
|
Map<String, Object> prefs = const {},
|
|
|
|
|
http.Client? httpClient,
|
2026-06-15 22:11:08 +02:00
|
|
|
List<Note> seed = const [],
|
|
|
|
|
LocalBackup? localBackup,
|
2026-06-15 17:11:01 +02:00
|
|
|
}) async {
|
|
|
|
|
SharedPreferences.setMockInitialValues(prefs);
|
2026-06-15 22:57:05 +02:00
|
|
|
installFakeSecureStorage();
|
2026-06-15 17:11:01 +02:00
|
|
|
// Tall surface so a pushed settings screen builds its whole ListView.
|
|
|
|
|
tester.view.physicalSize = const Size(1200, 2800);
|
|
|
|
|
tester.view.devicePixelRatio = 1.0;
|
|
|
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
|
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
|
|
2026-06-15 22:11:08 +02:00
|
|
|
final repo = FakeNoteRepository(seed);
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
addTearDown(repo.close);
|
2026-06-15 22:11:08 +02:00
|
|
|
// Default to an in-memory, no-op backup so tests never touch real disk
|
|
|
|
|
// (the production backup writes ~/todo/BACKLOG.md on the Linux test host).
|
|
|
|
|
final backup =
|
|
|
|
|
localBackup ??
|
|
|
|
|
LocalBackup(
|
|
|
|
|
reader: () async => null,
|
|
|
|
|
writer: (_) async {},
|
|
|
|
|
debounce: Duration.zero,
|
|
|
|
|
);
|
2026-06-15 17:11:01 +02:00
|
|
|
await tester.pumpWidget(
|
|
|
|
|
MaterialApp(
|
2026-06-15 22:11:08 +02:00
|
|
|
home: CaptureScreen(
|
|
|
|
|
repository: repo,
|
|
|
|
|
httpClient: httpClient,
|
|
|
|
|
localBackup: backup,
|
|
|
|
|
),
|
2026-06-15 17:11:01 +02:00
|
|
|
),
|
|
|
|
|
);
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
await tester.pump(); // flush initial stream + settings load
|
|
|
|
|
return repo;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-15 17:11:01 +02:00
|
|
|
// Seeds a fully configured GitHub sync so the configured `_sync` path runs.
|
|
|
|
|
const configuredPrefs = {
|
|
|
|
|
'sync.owner': 'o',
|
|
|
|
|
'sync.repo': 'r',
|
|
|
|
|
'sync.token': 'tok',
|
|
|
|
|
};
|
|
|
|
|
|
Add full note view/editor with templates and Markdown render
Notes were previously only openable via a quick-actions sheet; you
could not read or edit a note in full. Add a shared NoteEditor used by
both the capture and detail screens, plus selectable templates and a
rendered Markdown view.
- note_template.dart: pure assemble/parse layer over a Markdown subset
(# title, ## sections + italic guidance, dropping empty sections).
assemble(parse(text)) is idempotent for conforming text; non-conforming
/ legacy / freeform text is reported so the UI falls back to raw,
untouched. Two templates: llm-design-spec (default) and blank.
- note_editor.dart: View / Guided / Raw modes. Guided is an inline
Stepper (one step per section with its guidance); View renders the
note via MarkdownView; Raw is the verbatim text. Guided is offered
only for structured templates; switching to it is blocked when the
raw text no longer conforms.
- markdown_view.dart: lean read-only renderer for the note subset,
wrapped in a SelectionArea for copy-out.
- note_detail_screen.dart: full-screen note; opens in View, edits
persist immediately, priority/status dropdowns, delete.
- capture_screen / notes_list_screen wired to the new editor and detail
screen (tap a note opens it; quick actions move to the overflow button).
The editor is a view over plain text, so CRDT storage and Markdown
export/sync are unaffected. 138 tests, 100% line coverage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:59:31 +02:00
|
|
|
testWidgets('opens the guided editor with section guidance', (tester) async {
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
await pumpCapture(tester);
|
|
|
|
|
|
Add full note view/editor with templates and Markdown render
Notes were previously only openable via a quick-actions sheet; you
could not read or edit a note in full. Add a shared NoteEditor used by
both the capture and detail screens, plus selectable templates and a
rendered Markdown view.
- note_template.dart: pure assemble/parse layer over a Markdown subset
(# title, ## sections + italic guidance, dropping empty sections).
assemble(parse(text)) is idempotent for conforming text; non-conforming
/ legacy / freeform text is reported so the UI falls back to raw,
untouched. Two templates: llm-design-spec (default) and blank.
- note_editor.dart: View / Guided / Raw modes. Guided is an inline
Stepper (one step per section with its guidance); View renders the
note via MarkdownView; Raw is the verbatim text. Guided is offered
only for structured templates; switching to it is blocked when the
raw text no longer conforms.
- markdown_view.dart: lean read-only renderer for the note subset,
wrapped in a SelectionArea for copy-out.
- note_detail_screen.dart: full-screen note; opens in View, edits
persist immediately, priority/status dropdowns, delete.
- capture_screen / notes_list_screen wired to the new editor and detail
screen (tap a note opens it; quick actions move to the overflow button).
The editor is a view over plain text, so CRDT storage and Markdown
export/sync are unaffected. 138 tests, 100% line coverage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:59:31 +02:00
|
|
|
// The guided stepper shows the design-spec sections and the title step's
|
|
|
|
|
// guidance, with no note persisted yet.
|
|
|
|
|
expect(find.text('Guided'), findsOneWidget);
|
|
|
|
|
expect(find.textContaining('imperative'), findsOneWidget); // title helper
|
|
|
|
|
expect(find.text('what'), findsOneWidget); // a section step header
|
|
|
|
|
expect(find.text('done'), findsOneWidget);
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
expect(find.text('0 saved'), findsOneWidget);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('saving the untouched template creates no note', (tester) async {
|
|
|
|
|
final repo = await pumpCapture(tester);
|
|
|
|
|
|
|
|
|
|
await tester.tap(find.text('Save'));
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
expect(await repo.listNotes(), isEmpty);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('typing into the template persists a note with defaults', (
|
|
|
|
|
tester,
|
|
|
|
|
) async {
|
|
|
|
|
final repo = await pumpCapture(tester);
|
|
|
|
|
|
Add full note view/editor with templates and Markdown render
Notes were previously only openable via a quick-actions sheet; you
could not read or edit a note in full. Add a shared NoteEditor used by
both the capture and detail screens, plus selectable templates and a
rendered Markdown view.
- note_template.dart: pure assemble/parse layer over a Markdown subset
(# title, ## sections + italic guidance, dropping empty sections).
assemble(parse(text)) is idempotent for conforming text; non-conforming
/ legacy / freeform text is reported so the UI falls back to raw,
untouched. Two templates: llm-design-spec (default) and blank.
- note_editor.dart: View / Guided / Raw modes. Guided is an inline
Stepper (one step per section with its guidance); View renders the
note via MarkdownView; Raw is the verbatim text. Guided is offered
only for structured templates; switching to it is blocked when the
raw text no longer conforms.
- markdown_view.dart: lean read-only renderer for the note subset,
wrapped in a SelectionArea for copy-out.
- note_detail_screen.dart: full-screen note; opens in View, edits
persist immediately, priority/status dropdowns, delete.
- capture_screen / notes_list_screen wired to the new editor and detail
screen (tap a note opens it; quick actions move to the overflow button).
The editor is a view over plain text, so CRDT storage and Markdown
export/sync are unaffected. 138 tests, 100% line coverage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:59:31 +02:00
|
|
|
// The first field in the guided stepper is the title section.
|
|
|
|
|
await tester.enterText(find.byType(TextField).first, 'My idea');
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
final notes = await repo.listNotes();
|
|
|
|
|
expect(notes, hasLength(1));
|
|
|
|
|
expect(notes.single.text, contains('My idea'));
|
|
|
|
|
expect(notes.single.priority, Priority.medium);
|
|
|
|
|
expect(notes.single.status, Status.todo);
|
|
|
|
|
expect(find.text('1 saved'), findsOneWidget);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('save after editing shows a snackbar and resets the template', (
|
|
|
|
|
tester,
|
|
|
|
|
) async {
|
|
|
|
|
final repo = await pumpCapture(tester);
|
|
|
|
|
|
Add full note view/editor with templates and Markdown render
Notes were previously only openable via a quick-actions sheet; you
could not read or edit a note in full. Add a shared NoteEditor used by
both the capture and detail screens, plus selectable templates and a
rendered Markdown view.
- note_template.dart: pure assemble/parse layer over a Markdown subset
(# title, ## sections + italic guidance, dropping empty sections).
assemble(parse(text)) is idempotent for conforming text; non-conforming
/ legacy / freeform text is reported so the UI falls back to raw,
untouched. Two templates: llm-design-spec (default) and blank.
- note_editor.dart: View / Guided / Raw modes. Guided is an inline
Stepper (one step per section with its guidance); View renders the
note via MarkdownView; Raw is the verbatim text. Guided is offered
only for structured templates; switching to it is blocked when the
raw text no longer conforms.
- markdown_view.dart: lean read-only renderer for the note subset,
wrapped in a SelectionArea for copy-out.
- note_detail_screen.dart: full-screen note; opens in View, edits
persist immediately, priority/status dropdowns, delete.
- capture_screen / notes_list_screen wired to the new editor and detail
screen (tap a note opens it; quick actions move to the overflow button).
The editor is a view over plain text, so CRDT storage and Markdown
export/sync are unaffected. 138 tests, 100% line coverage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:59:31 +02:00
|
|
|
await tester.enterText(find.byType(TextField).first, 'A real idea');
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
await tester.pump();
|
|
|
|
|
await tester.tap(find.text('Save'));
|
|
|
|
|
await tester.pump(); // build the snackbar
|
|
|
|
|
|
|
|
|
|
expect(find.text('Idea saved locally'), findsOneWidget);
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
expect(await repo.listNotes(), hasLength(1));
|
Add full note view/editor with templates and Markdown render
Notes were previously only openable via a quick-actions sheet; you
could not read or edit a note in full. Add a shared NoteEditor used by
both the capture and detail screens, plus selectable templates and a
rendered Markdown view.
- note_template.dart: pure assemble/parse layer over a Markdown subset
(# title, ## sections + italic guidance, dropping empty sections).
assemble(parse(text)) is idempotent for conforming text; non-conforming
/ legacy / freeform text is reported so the UI falls back to raw,
untouched. Two templates: llm-design-spec (default) and blank.
- note_editor.dart: View / Guided / Raw modes. Guided is an inline
Stepper (one step per section with its guidance); View renders the
note via MarkdownView; Raw is the verbatim text. Guided is offered
only for structured templates; switching to it is blocked when the
raw text no longer conforms.
- markdown_view.dart: lean read-only renderer for the note subset,
wrapped in a SelectionArea for copy-out.
- note_detail_screen.dart: full-screen note; opens in View, edits
persist immediately, priority/status dropdowns, delete.
- capture_screen / notes_list_screen wired to the new editor and detail
screen (tap a note opens it; quick actions move to the overflow button).
The editor is a view over plain text, so CRDT storage and Markdown
export/sync are unaffected. 138 tests, 100% line coverage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:59:31 +02:00
|
|
|
// The editor reset to a fresh guided template (title guidance shown again).
|
|
|
|
|
expect(find.textContaining('imperative'), findsOneWidget);
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('tapping Sync while unconfigured prompts for a token', (
|
|
|
|
|
tester,
|
|
|
|
|
) async {
|
|
|
|
|
await pumpCapture(tester); // empty prefs → no token → not configured
|
|
|
|
|
|
|
|
|
|
await tester.tap(find.byTooltip('Sync'));
|
|
|
|
|
await tester.pump(); // settings load + snackbar
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
expect(find.textContaining('Add a GitHub token'), findsOneWidget);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('the notes-list button navigates to the list screen', (
|
|
|
|
|
tester,
|
|
|
|
|
) async {
|
|
|
|
|
await pumpCapture(tester);
|
|
|
|
|
|
|
|
|
|
await tester.tap(find.byTooltip('Notes'));
|
|
|
|
|
await tester.pump();
|
|
|
|
|
await tester.pump(const Duration(milliseconds: 300)); // route transition
|
|
|
|
|
|
|
|
|
|
expect(find.text('Notes'), findsOneWidget); // list screen app bar title
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('changing the priority dropdown updates the saved note', (
|
|
|
|
|
tester,
|
|
|
|
|
) async {
|
|
|
|
|
final repo = await pumpCapture(tester);
|
|
|
|
|
|
Add full note view/editor with templates and Markdown render
Notes were previously only openable via a quick-actions sheet; you
could not read or edit a note in full. Add a shared NoteEditor used by
both the capture and detail screens, plus selectable templates and a
rendered Markdown view.
- note_template.dart: pure assemble/parse layer over a Markdown subset
(# title, ## sections + italic guidance, dropping empty sections).
assemble(parse(text)) is idempotent for conforming text; non-conforming
/ legacy / freeform text is reported so the UI falls back to raw,
untouched. Two templates: llm-design-spec (default) and blank.
- note_editor.dart: View / Guided / Raw modes. Guided is an inline
Stepper (one step per section with its guidance); View renders the
note via MarkdownView; Raw is the verbatim text. Guided is offered
only for structured templates; switching to it is blocked when the
raw text no longer conforms.
- markdown_view.dart: lean read-only renderer for the note subset,
wrapped in a SelectionArea for copy-out.
- note_detail_screen.dart: full-screen note; opens in View, edits
persist immediately, priority/status dropdowns, delete.
- capture_screen / notes_list_screen wired to the new editor and detail
screen (tap a note opens it; quick actions move to the overflow button).
The editor is a view over plain text, so CRDT storage and Markdown
export/sync are unaffected. 138 tests, 100% line coverage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:59:31 +02:00
|
|
|
await tester.enterText(find.byType(TextField).first, 'Prioritised idea');
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
await tester.tap(
|
|
|
|
|
find.byWidgetPredicate((w) => w is DropdownButton<Priority>),
|
|
|
|
|
);
|
|
|
|
|
await tester.pump();
|
|
|
|
|
await tester.pump(const Duration(milliseconds: 400)); // menu open
|
|
|
|
|
await tester.tap(find.text('High').last);
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
expect((await repo.listNotes()).single.priority, Priority.high);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('changing the status dropdown updates the saved note', (
|
|
|
|
|
tester,
|
|
|
|
|
) async {
|
|
|
|
|
final repo = await pumpCapture(tester);
|
|
|
|
|
|
Add full note view/editor with templates and Markdown render
Notes were previously only openable via a quick-actions sheet; you
could not read or edit a note in full. Add a shared NoteEditor used by
both the capture and detail screens, plus selectable templates and a
rendered Markdown view.
- note_template.dart: pure assemble/parse layer over a Markdown subset
(# title, ## sections + italic guidance, dropping empty sections).
assemble(parse(text)) is idempotent for conforming text; non-conforming
/ legacy / freeform text is reported so the UI falls back to raw,
untouched. Two templates: llm-design-spec (default) and blank.
- note_editor.dart: View / Guided / Raw modes. Guided is an inline
Stepper (one step per section with its guidance); View renders the
note via MarkdownView; Raw is the verbatim text. Guided is offered
only for structured templates; switching to it is blocked when the
raw text no longer conforms.
- markdown_view.dart: lean read-only renderer for the note subset,
wrapped in a SelectionArea for copy-out.
- note_detail_screen.dart: full-screen note; opens in View, edits
persist immediately, priority/status dropdowns, delete.
- capture_screen / notes_list_screen wired to the new editor and detail
screen (tap a note opens it; quick actions move to the overflow button).
The editor is a view over plain text, so CRDT storage and Markdown
export/sync are unaffected. 138 tests, 100% line coverage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:59:31 +02:00
|
|
|
await tester.enterText(find.byType(TextField).first, 'Status idea');
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
await tester.tap(
|
|
|
|
|
find.byWidgetPredicate((w) => w is DropdownButton<Status>),
|
|
|
|
|
);
|
|
|
|
|
await tester.pump();
|
|
|
|
|
await tester.pump(const Duration(milliseconds: 400)); // menu open
|
|
|
|
|
await tester.tap(find.text('In progress').last);
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
expect((await repo.listNotes()).single.status, Status.inProgress);
|
|
|
|
|
});
|
2026-06-15 17:11:01 +02:00
|
|
|
|
|
|
|
|
testWidgets('Sync with a configured token runs the sync service', (
|
|
|
|
|
tester,
|
|
|
|
|
) async {
|
|
|
|
|
// Empty remote directory (404) → the service has nothing to merge and
|
|
|
|
|
// pushes this device's own changeset (PUT).
|
|
|
|
|
final mock = MockClient((req) async {
|
|
|
|
|
if (req.method == 'PUT') return http.Response('{}', 200);
|
|
|
|
|
return http.Response('', 404);
|
|
|
|
|
});
|
|
|
|
|
await pumpCapture(tester, prefs: configuredPrefs, httpClient: mock);
|
|
|
|
|
|
|
|
|
|
await tester.tap(find.byTooltip('Sync'));
|
|
|
|
|
await tester.pump(); // setState(_syncing = true)
|
|
|
|
|
await tester.pump(); // service runs, snackbar scheduled
|
|
|
|
|
await tester.pump(); // snackbar builds
|
|
|
|
|
|
|
|
|
|
expect(find.textContaining('Synced: merged 0 device'), findsOneWidget);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('Sync surfaces a failure from the sync service', (tester) async {
|
|
|
|
|
final mock = MockClient((_) async => throw Exception('offline'));
|
|
|
|
|
await pumpCapture(tester, prefs: configuredPrefs, httpClient: mock);
|
|
|
|
|
|
|
|
|
|
await tester.tap(find.byTooltip('Sync'));
|
|
|
|
|
await tester.pump();
|
|
|
|
|
await tester.pump();
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
expect(find.textContaining('Sync failed'), findsOneWidget);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('returning from settings adopts the saved configuration', (
|
|
|
|
|
tester,
|
|
|
|
|
) async {
|
|
|
|
|
await pumpCapture(tester);
|
|
|
|
|
|
|
|
|
|
await tester.tap(find.byTooltip('Sync settings'));
|
|
|
|
|
await tester.pumpAndSettle(); // route transition
|
|
|
|
|
expect(find.text('Connect GitHub'), findsOneWidget); // settings is up
|
|
|
|
|
|
|
|
|
|
// Saving pops a SyncSettings back to the capture screen (covers the
|
|
|
|
|
// result-adoption branch in _openSettings). Scope to the settings route —
|
|
|
|
|
// the capture screen's own "Save" is still mounted behind it.
|
|
|
|
|
await tester.tap(
|
|
|
|
|
find.descendant(
|
|
|
|
|
of: find.byType(SettingsScreen),
|
|
|
|
|
matching: find.text('Save'),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
await tester.pumpAndSettle(); // save + pop transition
|
|
|
|
|
|
|
|
|
|
expect(find.text('Connect GitHub'), findsNothing); // back on capture
|
|
|
|
|
expect(find.byTooltip('Sync settings'), findsOneWidget);
|
|
|
|
|
});
|
2026-06-15 22:02:39 +02:00
|
|
|
|
|
|
|
|
// A MockClient that records request methods and answers the sync flow:
|
|
|
|
|
// 404 for the (empty) changeset listing, 200 for the device's own PUT.
|
|
|
|
|
MockClient recordingMock(List<String> methods) => MockClient((req) async {
|
|
|
|
|
methods.add(req.method);
|
|
|
|
|
if (req.method == 'PUT') return http.Response('{}', 200);
|
|
|
|
|
return http.Response('', 404);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('auto-syncs on launch when configured', (tester) async {
|
|
|
|
|
final methods = <String>[];
|
|
|
|
|
await pumpCapture(
|
|
|
|
|
tester,
|
|
|
|
|
prefs: configuredPrefs,
|
|
|
|
|
httpClient: recordingMock(methods),
|
|
|
|
|
);
|
|
|
|
|
await tester.pump(); // settings load → auto-sync (pull) …
|
|
|
|
|
await tester.pump(); // … then push
|
|
|
|
|
|
|
|
|
|
expect(methods, contains('PUT')); // this device pushed its changeset
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('does not auto-sync when unconfigured', (tester) async {
|
|
|
|
|
final methods = <String>[];
|
|
|
|
|
await pumpCapture(tester, httpClient: recordingMock(methods)); // no token
|
|
|
|
|
await tester.pump();
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
expect(methods, isEmpty);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('auto-syncs again when the app is backgrounded', (tester) async {
|
|
|
|
|
final methods = <String>[];
|
|
|
|
|
await pumpCapture(
|
|
|
|
|
tester,
|
|
|
|
|
prefs: configuredPrefs,
|
|
|
|
|
httpClient: recordingMock(methods),
|
|
|
|
|
);
|
|
|
|
|
await tester.pump();
|
|
|
|
|
await tester.pump();
|
|
|
|
|
methods.clear();
|
|
|
|
|
|
|
|
|
|
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.paused);
|
|
|
|
|
await tester.pump();
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
expect(methods, contains('PUT'));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('auto-sync failure is silent (no snackbar)', (tester) async {
|
|
|
|
|
final mock = MockClient((_) async => throw Exception('offline'));
|
|
|
|
|
await pumpCapture(tester, prefs: configuredPrefs, httpClient: mock);
|
|
|
|
|
await tester.pump();
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
expect(find.textContaining('Sync failed'), findsNothing);
|
|
|
|
|
expect(find.textContaining('Synced'), findsNothing);
|
|
|
|
|
});
|
2026-06-15 22:11:08 +02:00
|
|
|
|
|
|
|
|
testWidgets('recovers notes from the local backup into an empty DB', (
|
|
|
|
|
tester,
|
|
|
|
|
) async {
|
|
|
|
|
final markdown = NotesMarkdown.export([
|
|
|
|
|
Note(
|
|
|
|
|
id: 'r1',
|
|
|
|
|
text: '# Recovered idea',
|
|
|
|
|
priority: Priority.medium,
|
|
|
|
|
status: Status.todo,
|
|
|
|
|
createdAt: DateTime(2026, 6, 15),
|
|
|
|
|
updatedAt: DateTime(2026, 6, 15),
|
|
|
|
|
),
|
|
|
|
|
]);
|
|
|
|
|
final backup = LocalBackup(
|
|
|
|
|
reader: () async => markdown,
|
|
|
|
|
writer: (_) async {},
|
|
|
|
|
debounce: Duration.zero,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
final repo = await pumpCapture(tester, localBackup: backup);
|
|
|
|
|
await tester.pump(); // recover → import
|
|
|
|
|
|
|
|
|
|
final notes = await repo.listNotes();
|
|
|
|
|
expect(notes, hasLength(1));
|
|
|
|
|
expect(notes.single.text, contains('Recovered idea'));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('does not recover when the DB already has notes', (tester) async {
|
|
|
|
|
final backup = LocalBackup(
|
|
|
|
|
reader: () async => NotesMarkdown.export([
|
|
|
|
|
Note(
|
|
|
|
|
id: 'r1',
|
|
|
|
|
text: '# From backup',
|
|
|
|
|
priority: Priority.medium,
|
|
|
|
|
status: Status.todo,
|
|
|
|
|
createdAt: DateTime(2026, 6, 15),
|
|
|
|
|
updatedAt: DateTime(2026, 6, 15),
|
|
|
|
|
),
|
|
|
|
|
]),
|
|
|
|
|
writer: (_) async {},
|
|
|
|
|
debounce: Duration.zero,
|
|
|
|
|
);
|
|
|
|
|
final seeded = Note(
|
|
|
|
|
id: 'local',
|
|
|
|
|
text: '# Existing',
|
|
|
|
|
priority: Priority.medium,
|
|
|
|
|
status: Status.todo,
|
|
|
|
|
createdAt: DateTime(2026, 6, 15),
|
|
|
|
|
updatedAt: DateTime(2026, 6, 15),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
final repo = await pumpCapture(tester, seed: [seeded], localBackup: backup);
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
// The backup is ignored because the DB was not empty.
|
|
|
|
|
final notes = await repo.listNotes();
|
|
|
|
|
expect(notes, hasLength(1));
|
|
|
|
|
expect(notes.single.id, 'local');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
testWidgets('writes the local backup as notes change', (tester) async {
|
|
|
|
|
final writes = <String>[];
|
|
|
|
|
final backup = LocalBackup(
|
|
|
|
|
reader: () async => null,
|
|
|
|
|
writer: (md) async => writes.add(md),
|
|
|
|
|
debounce: Duration.zero,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await pumpCapture(tester, localBackup: backup);
|
|
|
|
|
await tester.enterText(find.byType(TextField).first, 'Backed up idea');
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
|
|
|
|
expect(writes, isNotEmpty);
|
|
|
|
|
expect(writes.last, contains('Backed up idea'));
|
|
|
|
|
});
|
Add list filters/sort, status, priority rework, export/import, structured template
Notes list & filtering:
- Text-search filter plus independent date-range filters for both created
and last-updated (AND-combined), a priority filter, and a new status
filter. Default view hides Done/Abandoned and renders as "unfiltered"
(no badge for the default state); fixed badge clipping.
- NoteSort options wired into the list UI; watchCount() for the "N saved".
Status & priority:
- New Status enum (toDo/inProgress/Done/Abandoned) as a settable + filterable
attribute on every note, with capture-screen dropdown.
- Removed "None" priority: every note is Low/Medium/High, default Medium.
Schema migration v2->v3 rewrites legacy priority 0 -> Medium.
Export / import:
- NotesMarkdown round-trippable single-file format with HTML-comment markers.
- Settings "Export notes" (mobile share sheet / desktop writes ~/todo/BACKLOG.md)
and "Import notes" (file picker + safe newer-wins merge by id).
Structured template:
- Every new note pre-fills the richer what/where/must/nice/out/done/depends/
estimate/refs scaffold.
Tests:
- New fast (~5s), deterministic suite via FakeNoteRepository (no DB timers) and
injected http/file-selector/url-launcher fakes. 86 tests, 96.2% line coverage
(note.dart & sync_service.dart at 100%, settings 98.7%). Mobile-only share
branch excluded via coverage:ignore (unreachable on the Linux test host).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:52:59 +02:00
|
|
|
}
|