--- 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