147 lines
7.8 KiB
Markdown
147 lines
7.8 KiB
Markdown
---
|
|
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
|