# Notification Feature Audit — Tasklist **Source:** Full codebase trace of notification system **Date:** June 2026 **Status legend:** `[ ]` Not started · `[~]` In progress · `[x]` Done · `[-]` Skipped --- ## Defects (Bugs) ### D1. Notification ID Range Collision — Adhan vs Report Reminders `[SEVERITY: High]` - [x] **D1.1** Move report reminder ID range from `700000+` to `2000000+` in `_reportReminderId()` - [x] **D1.2** Update `_cancelPrayerPending()` range guard to exclude the new report range explicitly - [x] **D1.3** Verify adhan IDs (100k–800k), iqamah IDs (800k–1.5M), report IDs (2M+), non-prayer IDs (900k–980k) are all disjoint ### D2. Streak Risk Only Checks Dzikir Petang, Not Pagi `[SEVERITY: Medium]` - [x] **D2.1** Fix `emitStreakRiskIfNeeded` to check both `!pagi` and `!petang` in dzikir risk logic - [x] **D2.2** Emit separate inbox items for pagi vs petang dzikir risk with correct deeplinks ### D3. `_cancelPrayerPending` Cancels Non-Prayer Notifications Too `[SEVERITY: Medium]` - [x] **D3.1** Narrow the ID range filter to only cancel adhan (100k–799k), iqamah (800k–1.5M), and report (2M+) IDs - [x] **D3.2** Exclude non-prayer range (900k–980k) from cancellation ### D4. Notification Tap Routes All Non-Prayer to `/notifications` Instead of Deep Link `[SEVERITY: Medium]` - [x] **D4.1** Update `routeForNotificationPayload` to parse deeplink from payload for `streak_risk` type - [x] **D4.2** Include deeplink in notification payload through `_pushNonPrayer` → `showNonPrayerAlert` chain ### D5. Timezone Not Updated on Device TZ Change `[SEVERITY: Medium]` - [x] **D5.1** Add `reconfigureTimeZoneIfNeeded()` method to detect and apply timezone changes - [x] **D5.2** Reset `_lastSyncSignature` on TZ change to force prayer notification resync ### D6. `_handleLaunchNotification` May Fire Before Router is Ready `[SEVERITY: Low]` - [x] **D6.1** Defer launch notification routing — store pending route, consume from `AppState.initState` with 800ms delay --- ## Gaps (Missing or Incomplete) ### G1. No Settings UI for Notification Preferences `[SEVERITY: High]` - [x] **G1.1** Settings UI already existed — added missing `streakRiskEnabled` toggle to notification group - [x] **G1.2** Added `weeklySummaryEnabled` toggle to notification group - [x] **G1.3** All other notification settings (alerts, inbox, checklist reminder, quiet hours, push cap) were already present ### G2. No Device Reboot Reschedule `[SEVERITY: High]` - [x] **G2.1** Verified `RECEIVE_BOOT_COMPLETED` permission in AndroidManifest.xml — already present - [x] **G2.2** Verified `ScheduledNotificationReceiver` and `ScheduledNotificationBootReceiver` — already declared - [x] **G2.3** `flutter_local_notifications` v21 handles reboot natively; `workmanager` periodic task resumes via `ExistingPeriodicWorkPolicy.update` ### G3. `mirrorAdzanToInbox` Setting Exists But Never Used `[SEVERITY: Medium]` - [x] **G3.1** Removed unused `mirrorAdzanToInbox` field from `AppSettings` and generated adapter - [x] **G3.2** Removed legacy `removeByType('prayer')` calls from `main.dart` and `notification_center_screen.dart` ### G4. No Analytics for `notif_push_opened` `[SEVERITY: Low]` - [x] **G4.1** Added `notif_push_opened` tracking in `_handleNotificationResponse` (foreground) and `consumePendingLaunchRoute` (launch) ### G5. No Analytics for `notif_settings_changed` `[SEVERITY: Low]` - [x] **G5.1** Added `notif_settings_changed` tracking in notification bell quick actions toggle --- ## Opportunities (Enhancements) ### O1. Rich Notification Actions — "Sudah Sholat" Button on Report Reminders - [x] **O1.1** Added `AndroidNotificationAction` with `action_prayed` / "Sudah Sholat" button to `_scheduleShalatReportReminder` - [x] **O1.2** Background handler (`notificationTapBackgroundHandler`) opens Hive and logs `ShalatLog(completed: true)` via `_markPrayedFromBackground` - [x] **O1.3** Foreground handler (`_handleNotificationResponse`) logs prayer via `_markPrayedFromForeground` - [x] **O1.4** Added `_resolvePrayerKeyFromName` to map display names back to canonical keys in background isolate ### O2. Notification Permission Check on App Resume via WidgetsBindingObserver - [x] **O2.1** Added `_checkNotificationPermissionOnResume()` with 30-second throttle to `_AppState.didChangeAppLifecycleState` - [x] **O2.2** Re-checks notification permissions and emits warnings via `emitPermissionWarningsIfNeeded` on resume ### O2b. Fix Stretched Notification Icon - [x] **O2b.1** Created `@drawable/ic_notification` — white crescent moon vector drawable (Android notification-safe) - [x] **O2b.2** Changed `AndroidInitializationSettings` from `@mipmap/ic_launcher` to `@drawable/ic_notification` - [x] **O2b.3** Added `icon: '@drawable/ic_notification'` to all 4 notification channels ### O3. Add Expired Item Cleanup to Background Sync - [x] **O3.1** Added `removeExpired()` call in `BackgroundSyncService.runSyncPass()` ### O4. Haptic Feedback on Quick Actions - [x] **O4.1** Added `HapticFeedback.selectionClick()` to all three notification bell quick action taps --- ## Progress Tracker | Category | Total | Done | Skipped | Remaining | |----------|-------|------|---------|------------| | Defects (D1–D6) | 11 | 11 | 0 | 0 | | Gaps (G1–G5) | 10 | 10 | 0 | 0 | | Opportunities (O1–O4) | 9 | 9 | 0 | 0 | | **TOTAL** | **30** | **30** | **0** | **0** | --- ## Files Changed | File | Changes | |------|---------| | `lib/data/services/notification_service.dart` | D1: ID range fix, D3: cancel range fix, D4: payload routing with deeplink, D5: TZ reconfig, D6: deferred launch routing, O1: rich notification action + background handler, O2b: icon fix | | `lib/data/services/notification_event_producer_service.dart` | D2: pagi+petang dzikir streak risk, D4: deeplink threading | | `lib/core/widgets/notification_bell_button.dart` | G5: analytics tracking, O4: haptic feedback | | `lib/data/services/background_sync_service.dart` | O3: expired inbox cleanup | | `lib/features/settings/presentation/settings_screen.dart` | G1: streak risk + weekly summary toggles | | `lib/data/local/models/app_settings.dart` | G3: removed `mirrorAdzanToInbox` field | | `lib/data/local/models/app_settings.g.dart` | G3: removed field 32 from adapter | | `lib/main.dart` | G3: removed legacy `removeByType('prayer')` | | `lib/features/notifications/presentation/notification_center_screen.dart` | G3: removed legacy cleanup | | `lib/app/app.dart` | D6: consume pending launch route on init, O2: permission check on resume | | `android/app/src/main/res/drawable/ic_notification.xml` | O2b: white crescent moon vector drawable for notification icon |