diff --git a/.planning/STATE.md b/.planning/STATE.md index cf343f6..7f1142a 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -4,7 +4,7 @@ milestone: v1.0 milestone_name: milestone status: completed stopped_at: Completed 07-task-sorting/07-02-PLAN.md -last_updated: "2026-03-16T21:40:24.558Z" +last_updated: "2026-03-16T21:43:23.009Z" last_activity: 2026-03-16 — Completed Phase 6 Plan 01 (task completion history) progress: total_phases: 3 diff --git a/.planning/phases/07-task-sorting/7-VERIFICATION.md b/.planning/phases/07-task-sorting/7-VERIFICATION.md new file mode 100644 index 0000000..356f737 --- /dev/null +++ b/.planning/phases/07-task-sorting/7-VERIFICATION.md @@ -0,0 +1,135 @@ +--- +phase: 07-task-sorting +verified: 2026-03-16T22:00:00Z +status: passed +score: 9/9 must-haves verified +re_verification: false +--- + +# Phase 7: Task Sorting Verification Report + +**Phase Goal:** Users can reorder task lists by the dimension most useful to them — name, how often the task recurs, or how much effort it requires +**Verified:** 2026-03-16T22:00:00Z +**Status:** passed +**Re-verification:** No — initial verification + +--- + +## Goal Achievement + +### Observable Truths + +| # | Truth | Status | Evidence | +|----|--------------------------------------------------------------------------------|------------|------------------------------------------------------------------------------------------------------| +| 1 | Sort preference persists across app restarts | VERIFIED | `SortPreferenceNotifier._loadPersisted()` reads `SharedPreferences.getString('task_sort_option')` on build; 2 restart-recovery tests pass | +| 2 | CalendarDayList tasks are sorted according to the active sort preference | VERIFIED | `calendarDayProvider` calls `ref.watch(sortPreferenceProvider)` and applies `_sortTasks(dayTasks, sortOption)` before returning `CalendarDayState` | +| 3 | TaskListScreen tasks are sorted according to the active sort preference | VERIFIED | `tasksInRoomProvider` calls `ref.watch(sortPreferenceProvider)` and applies `stream.map((tasks) => _sortTasksRaw(tasks, sortOption))` | +| 4 | Default sort is alphabetical (matches current CalendarDayList behavior) | VERIFIED | `SortPreferenceNotifier.build()` returns `TaskSortOption.alphabetical` synchronously; test "build() returns default state of alphabetical" confirms | +| 5 | A sort dropdown is visible in the HomeScreen AppBar showing the current label | VERIFIED | `HomeScreen.build()` returns `Scaffold(appBar: AppBar(actions: const [SortDropdown()]))` — wired and rendered | +| 6 | A sort dropdown is visible in the TaskListScreen AppBar | VERIFIED | `TaskListScreen.build()` AppBar actions list: `[const SortDropdown(), edit IconButton, delete IconButton]` | +| 7 | Tapping the dropdown shows three options: A-Z, Intervall, Aufwand | VERIFIED | `SortDropdown` builds `PopupMenuButton` from `TaskSortOption.values` (3 items), labels map to `l10n.sortAlphabetical/sortInterval/sortEffort` | +| 8 | Selecting a sort option updates the task list order immediately | VERIFIED | `onSelected` calls `ref.read(sortPreferenceProvider.notifier).setSortOption(value)`; providers watch `sortPreferenceProvider` and rebuild reactively | +| 9 | The sort preference persists across screen navigations and app restarts | VERIFIED | `@Riverpod(keepAlive: true)` prevents disposal during navigation; SharedPreferences stores and reloads value | + +**Score:** 9/9 truths verified + +--- + +## Required Artifacts + +### Plan 07-01 Artifacts + +| Artifact | Expected | Status | Details | +|----------|----------|--------|---------| +| `lib/features/tasks/domain/task_sort_option.dart` | `TaskSortOption` enum with alphabetical, interval, effort | VERIFIED | Exactly 3 values, comments match intent. No stubs. | +| `lib/features/tasks/presentation/sort_preference_notifier.dart` | `SortPreferenceNotifier` with SharedPreferences persistence | VERIFIED | `build()` returns `alphabetical` synchronously, `_loadPersisted()` async, `setSortOption()` sets state + persists. Pattern matches `ThemeNotifier`. | +| `lib/features/tasks/presentation/sort_preference_notifier.g.dart` | Generated Riverpod provider file | VERIFIED | Generated correctly; `sortPreferenceProvider` declared as `SortPreferenceNotifierProvider._()` with `isAutoDispose: false` (keepAlive). | +| `lib/features/home/presentation/calendar_providers.dart` | `calendarDayProvider` sorts `dayTasks` by active sort preference | VERIFIED | `ref.watch(sortPreferenceProvider)` present. `_sortTasks()` helper implements all 3 sort modes. `overdueTasks` intentionally unsorted. | +| `lib/features/tasks/presentation/task_providers.dart` | `tasksInRoomProvider` sorts tasks by active sort preference | VERIFIED | `ref.watch(sortPreferenceProvider)` present. `_sortTasksRaw()` helper + `stream.map()` applied correctly. | +| `test/features/tasks/presentation/sort_preference_notifier_test.dart` | Unit tests for sort preference persistence and default | VERIFIED | 7 tests: default alphabetical, setSortOption interval, setSortOption effort, persist to SharedPreferences, restart recovery (effort), restart recovery (interval), unknown value fallback. | + +### Plan 07-02 Artifacts + +| Artifact | Expected | Status | Details | +|----------|----------|--------|---------| +| `lib/features/tasks/presentation/sort_dropdown.dart` | Reusable `SortDropdown` `ConsumerWidget` | VERIFIED | `ConsumerWidget`, `PopupMenuButton`, Opacity check mark pattern, `ref.watch` for display, `ref.read` for mutation, `_label()` helper. | +| `lib/features/home/presentation/home_screen.dart` | HomeScreen with AppBar containing `SortDropdown` | VERIFIED | `Scaffold(appBar: AppBar(title: Text(l10n.tabHome), actions: const [SortDropdown()]))`. Existing Stack body preserved. | +| `lib/features/tasks/presentation/task_list_screen.dart` | TaskListScreen AppBar with `SortDropdown` before edit/delete | VERIFIED | `actions: [const SortDropdown(), IconButton(edit), IconButton(delete)]`. Correct order. | + +--- + +## Key Link Verification + +### Plan 07-01 Key Links + +| From | To | Via | Status | Details | +|------|----|-----|--------|---------| +| `calendar_providers.dart` | `sortPreferenceProvider` | `ref.watch(sortPreferenceProvider)` in `calendarDayProvider` | WIRED | Line 77: `final sortOption = ref.watch(sortPreferenceProvider);`. Applied at line 101: `dayTasks: _sortTasks(dayTasks, sortOption)`. | +| `task_providers.dart` | `sortPreferenceProvider` | `ref.watch(sortPreferenceProvider)` in `tasksInRoomProvider` | WIRED | Line 43: `final sortOption = ref.watch(sortPreferenceProvider);`. Applied at lines 44-46 via `stream.map`. | + +### Plan 07-02 Key Links + +| From | To | Via | Status | Details | +|------|----|-----|--------|---------| +| `sort_dropdown.dart` | `sortPreferenceProvider` | `ref.watch` for display, `ref.read` for mutation | WIRED | Line 21: `ref.watch(sortPreferenceProvider)`. Line 27: `ref.read(sortPreferenceProvider.notifier).setSortOption(value)`. | +| `home_screen.dart` | `sort_dropdown.dart` | `SortDropdown` widget in AppBar actions | WIRED | Import on line 7. Used in `AppBar(actions: const [SortDropdown()])` on line 37. | +| `task_list_screen.dart` | `sort_dropdown.dart` | `SortDropdown` widget in AppBar actions | WIRED | Import on line 7. Used in `actions: [const SortDropdown(), ...]` on line 31. | + +--- + +## Requirements Coverage + +| Requirement | Source Plan | Description | Status | Evidence | +|-------------|-------------|-------------|--------|----------| +| SORT-01 | 07-01, 07-02 | User can sort tasks alphabetically | SATISFIED | `TaskSortOption.alphabetical` is the default. `_sortTasks()` and `_sortTasksRaw()` implement case-insensitive A-Z sort. `SortDropdown` displays "A–Z" label (l10n). | +| SORT-02 | 07-01, 07-02 | User can sort tasks by frequency interval | SATISFIED | `TaskSortOption.interval` sort implemented: `intervalType.index` ascending with `intervalDays` tiebreaker. Displayed as "Intervall" in `SortDropdown`. | +| SORT-03 | 07-01, 07-02 | User can sort tasks by effort level | SATISFIED | `TaskSortOption.effort` sort implemented: `effortLevel.index` ascending (low=0, medium=1, high=2). Displayed as "Aufwand" in `SortDropdown`. | + +No orphaned requirements. All three SORT requirements are claimed by both plans and fully implemented. + +--- + +## Anti-Patterns Found + +None. All seven implementation files scanned — no TODO, FIXME, XXX, HACK, PLACEHOLDER, return null, return {}, return [], or empty arrow functions found. + +--- + +## Human Verification Required + +### 1. Visual check: Sort dropdown appearance in AppBar + +**Test:** Launch the app, navigate to HomeScreen. Verify the AppBar shows a sort icon (Icons.sort) followed by the current sort label text "A–Z". +**Expected:** Sort icon and "A–Z" text visible in the top-right AppBar area. +**Why human:** Widget rendering and visual layout cannot be verified programmatically. + +### 2. Popup menu interaction: Check marks on active option + +**Test:** Tap the sort dropdown, verify three items appear with a check mark next to the currently selected option and no check mark on the other two. +**Expected:** Check mark visible on "A–Z" (default), invisible (but space-preserving) on "Intervall" and "Aufwand". +**Why human:** Opacity(0) vs Opacity(1) rendering and visual alignment cannot be verified with grep. + +### 3. Reactive reorder on selection + +**Test:** With tasks loaded in HomeScreen, tap the sort dropdown and select "Aufwand". Verify the task list reorders immediately without a page reload. +**Expected:** Task list updates instantly, sorted low-effort first. +**Why human:** Real-time Riverpod reactive rebuild requires a running app to observe. + +### 4. Cross-screen persistence of sort preference + +**Test:** Select "Intervall" in HomeScreen, then navigate to a room's TaskListScreen. Verify the sort dropdown there also shows "Intervall". +**Expected:** Sort preference is shared across screens (same `sortPreferenceProvider`, `keepAlive: true`). +**Why human:** Cross-screen navigation state cannot be verified statically. + +--- + +## Gaps Summary + +None. All 9 observable truths verified. All artifacts exist, are substantive, and are correctly wired. All 3 requirements (SORT-01, SORT-02, SORT-03) are fully satisfied. All 5 commits (a9f2983, 13c7d62, 3697e4e, e5eccb7, a3e4d02) confirmed present in git log. No anti-patterns detected in implementation files. + +The phase delivers its stated goal: users can reorder task lists by name (A–Z), frequency interval, or effort level via a persistent, reactive sort preference accessible from both HomeScreen and TaskListScreen AppBars. + +--- + +_Verified: 2026-03-16T22:00:00Z_ +_Verifier: Claude (gsd-verifier)_