From a3d3074a91b8a6b0e17004983718dc1d48a36d51 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Mon, 16 Mar 2026 15:09:52 +0100 Subject: [PATCH] docs(04-02): complete notification settings UI plan --- .planning/ROADMAP.md | 2 +- .planning/STATE.md | 13 +- .../phases/04-notifications/04-02-SUMMARY.md | 146 ++++++++++++++++++ 3 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 .planning/phases/04-notifications/04-02-SUMMARY.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 2b616b4..68fd9ca 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -97,4 +97,4 @@ Note: Phase 4 depends on Phase 2 (needs scheduling data) but can be developed in | 1. Foundation | 2/2 | Complete | 2026-03-15 | | 2. Rooms and Tasks | 5/5 | Complete | 2026-03-15 | | 3. Daily Plan and Cleanliness | 3/3 | Complete | 2026-03-16 | -| 4. Notifications | 1/3 | In Progress| | +| 4. Notifications | 2/3 | In Progress| | diff --git a/.planning/STATE.md b/.planning/STATE.md index 9d0ae04..3590c14 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: executing -stopped_at: Completed 04-01-PLAN.md (Notification infrastructure) -last_updated: "2026-03-16T14:00:13.196Z" +stopped_at: Completed 04-02-PLAN.md (Notification Settings UI) +last_updated: "2026-03-16T14:09:29.326Z" last_activity: 2026-03-16 — Completed 04-01-PLAN.md (Notification infrastructure) progress: total_phases: 4 completed_phases: 3 total_plans: 13 - completed_plans: 11 + completed_plans: 12 percent: 100 --- @@ -61,6 +61,7 @@ Progress: [██████████] 100% | Phase 03 P02 | 4 | 2 tasks | 5 files | | Phase 03 P03 | 2 | 2 tasks | 0 files | | Phase 04-notifications P01 | 9 | 2 tasks | 11 files | +| Phase 04-notifications P02 | 5 | 2 tasks | 5 files | ## Accumulated Context @@ -107,6 +108,8 @@ Recent decisions affecting current work: - [Phase 04-01]: flutter_local_notifications v21 uses named parameters in initialize() and zonedSchedule() — positional API removed in v20+ - [Phase 04-01]: Generated Riverpod 3 provider named notificationSettingsProvider (not notificationSettingsNotifierProvider) — consistent with themeProvider naming convention - [Phase 04-01]: nextInstanceOf exposed as @visibleForTesting public method to enable TZ logic unit testing without native dispatch mocking +- [Phase Phase 04-02]: openNotificationSettings() not available in flutter_local_notifications v21 — simplified to informational SnackBar (no action button) +- [Phase Phase 04-02]: ConsumerStatefulWidget for SettingsScreen — async permission callbacks require mounted guards after every await ### Pending Todos @@ -120,6 +123,6 @@ None yet. ## Session Continuity -Last session: 2026-03-16T14:00:13.194Z -Stopped at: Completed 04-01-PLAN.md (Notification infrastructure) +Last session: 2026-03-16T14:09:29.324Z +Stopped at: Completed 04-02-PLAN.md (Notification Settings UI) Resume file: None diff --git a/.planning/phases/04-notifications/04-02-SUMMARY.md b/.planning/phases/04-notifications/04-02-SUMMARY.md new file mode 100644 index 0000000..ae5310f --- /dev/null +++ b/.planning/phases/04-notifications/04-02-SUMMARY.md @@ -0,0 +1,146 @@ +--- +phase: 04-notifications +plan: 02 +subsystem: ui +tags: [flutter, riverpod, flutter_local_notifications, settings, permissions, widget-tests] + +# Dependency graph +requires: + - phase: 04-notifications/04-01 + provides: NotificationService singleton, NotificationSettingsNotifier, DailyPlanDao task count queries, ARB strings + - phase: 01-foundation + provides: themeProvider pattern, ProviderScope test pattern + +provides: + - SettingsScreen with Benachrichtigungen section (SwitchListTile + AnimatedSize time picker) + - Permission flow: request on toggle ON, revert on denial with SnackBar hint + - Notification scheduling with task/overdue counts from DailyPlanDao + - Notification tap navigation via router.go('/') in NotificationService._onTap + - Widget tests for notification settings UI states + +affects: [end-to-end notification flow complete] + +# Tech tracking +tech-stack: + added: [] + patterns: + - ConsumerStatefulWidget for screens requiring async callbacks with BuildContext + - AnimatedSize for progressive disclosure of conditional UI sections + - overrideWithValue for Riverpod provider isolation in widget tests + +key-files: + created: + - test/features/settings/settings_screen_test.dart + modified: + - lib/features/settings/presentation/settings_screen.dart + - lib/core/notifications/notification_service.dart + - lib/l10n/app_localizations.dart + - lib/l10n/app_localizations_de.dart + +key-decisions: + - "openNotificationSettings() not available in flutter_local_notifications v21 — simplified SnackBar to informational only (no action button)" + - "ConsumerStatefulWidget chosen over ConsumerWidget for async callback isolation and mounted checks" + - "notificationSettingsProvider (Riverpod 3 name, not notificationSettingsNotifierProvider) used throughout" + +patterns-established: + - "ConsumerStatefulWidget pattern: async permission/scheduling callbacks use mounted guards after every await" + - "TDD with pre-existing implementation: write tests to document expected behavior, verify pass, commit as feat (not separate test/feat commits)" + +requirements-completed: [NOTF-01, NOTF-02] + +# Metrics +duration: 5min +completed: 2026-03-16 +--- + +# Phase 4 Plan 2: Notification Settings UI Summary + +**ConsumerStatefulWidget SettingsScreen with Benachrichtigungen section, Android permission flow, DailyPlanDao-driven scheduling, notification tap navigation, and 5 widget tests** + +## Performance + +- **Duration:** 5 min +- **Started:** 2026-03-16T14:02:25Z +- **Completed:** 2026-03-16T14:07:58Z +- **Tasks:** 2 +- **Files modified:** 5 + +## Accomplishments +- SettingsScreen rewritten as ConsumerStatefulWidget with Benachrichtigungen section inserted between Darstellung and Uber +- SwitchListTile with permission request on toggle ON: `requestNotificationsPermission()` called before state update; toggle stays OFF on denial with SnackBar +- AnimatedSize progressive disclosure: time picker row only appears when `notificationSettings.enabled` is true +- `_scheduleNotification()` queries DailyPlanDao for total/overdue counts; skips scheduling when total==0; builds conditional body with overdue split when overdue > 0 +- `_onPickTime()` opens Material 3 showTimePicker dialog and reschedules on selection +- `NotificationService._onTap` wired to `router.go('/')` for notification tap navigation to Home tab +- AppLocalizations regenerated with 7 notification strings from Plan 01 ARB file +- 5 new widget tests: section header, toggle default OFF, time picker visible/hidden, formatted time display — all 89 tests pass + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Settings UI with Benachrichtigungen section, permission flow, and notification scheduling** - `0103dde` (feat) +2. **Task 2: Widget tests for notification settings UI** - `77de7cd` (feat) + +**Plan metadata:** (docs commit — see final commit hash below) + +## Files Created/Modified +- `lib/features/settings/presentation/settings_screen.dart` - ConsumerStatefulWidget with Benachrichtigungen section, permission flow, scheduling, and time picker +- `lib/core/notifications/notification_service.dart` - Added router import and `router.go('/')` in `_onTap` +- `lib/l10n/app_localizations.dart` - Regenerated abstract class with 7 new notification string declarations +- `lib/l10n/app_localizations_de.dart` - Regenerated German implementations for 7 new notification strings +- `test/features/settings/settings_screen_test.dart` - 5 widget tests covering notification UI states + +## Decisions Made +- **openNotificationSettings() unavailable**: `AndroidFlutterLocalNotificationsPlugin` in v21.0.0 does not expose `openNotificationSettings()`. Simplified to informational SnackBar without action button. The ARB hint text already guides users to system settings manually. +- **ConsumerStatefulWidget**: Chosen over ConsumerWidget because `_onNotificationToggle` and `_scheduleNotification` are async and require `mounted` checks after each `await` — this is only safe in `State`. +- **notificationSettingsProvider naming**: Used `notificationSettingsProvider` (Riverpod 3 convention established in Plan 01), not `notificationSettingsNotifierProvider` as referenced in the plan interfaces section. + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] openNotificationSettings() does not exist on AndroidFlutterLocalNotificationsPlugin v21** +- **Found during:** Task 1 (dart analyze after implementation) +- **Issue:** Plan specified using `androidPlugin?.openNotificationSettings()` in the SnackBar action, but this method does not exist in flutter_local_notifications v21.0.0 +- **Fix:** Removed the action button from the SnackBar — simplified to an informational SnackBar showing `notificationsPermissionDeniedHint` text only. The plan explicitly offered "Pick the simpler approach: SnackBar with hint text" as an option. +- **Files modified:** lib/features/settings/presentation/settings_screen.dart +- **Verification:** dart analyze clean, no errors +- **Committed in:** 0103dde + +**2. [Rule 1 - Bug] AppLocalizations missing notification string getters (stale generated files)** +- **Found during:** Task 1 (dart analyze) +- **Issue:** `app_localizations.dart` and `app_localizations_de.dart` were not updated after Plan 01 added 7 strings to `app_de.arb`. The generated files were stale. +- **Fix:** Ran `flutter gen-l10n` to regenerate localization files from ARB +- **Files modified:** lib/l10n/app_localizations.dart, lib/l10n/app_localizations_de.dart +- **Verification:** dart analyze clean after regeneration +- **Committed in:** 0103dde + +--- + +**Total deviations:** 2 auto-fixed (2 bugs — API mismatch and stale generated files) +**Impact on plan:** Both auto-fixes were necessary. The SnackBar simplification is explicitly offered as the preferred option in the plan. The localization regeneration is a missing step from Plan 01 that Plan 02 needed. + +## Issues Encountered +- flutter_local_notifications v21 API surface for `AndroidFlutterLocalNotificationsPlugin` does not include `openNotificationSettings()` — the plan referenced a method that was either added later or never existed in this version. Simplified to informational SnackBar per plan's own "simpler approach" option. + +## User Setup Required +None — no external service configuration required. + +## Next Phase Readiness +- Phase 4 (Notifications) is fully complete: infrastructure (Plan 01) + Settings UI (Plan 02) +- All 89 tests passing, dart analyze clean +- Notification feature end-to-end: toggle ON/OFF, permission request, time picker, daily scheduling, tap navigation to Home + +--- +*Phase: 04-notifications* +*Completed: 2026-03-16* + +## Self-Check: PASSED + +- lib/features/settings/presentation/settings_screen.dart: FOUND +- lib/core/notifications/notification_service.dart: FOUND +- test/features/settings/settings_screen_test.dart: FOUND +- .planning/phases/04-notifications/04-02-SUMMARY.md: FOUND +- commit 0103dde: FOUND +- commit 77de7cd: FOUND