Scaffold notification preferences screen layout
epic-scenario-push-engagement-ui-task-001 — Create the base Flutter screen for notification-preferences-screen including app bar, scrollable body, and section grouping for per-scenario toggle controls. Apply design token system for spacing, typography, and colours. Ensure the screen is registered in the route configuration.
Acceptance Criteria
Technical Requirements
Implementation Notes
Follow the existing screen file structure already established in the project (e.g., lib/features/settings/settings_screen.dart as a reference). Use the project's design token constants (AppSpacing, AppColors, AppTypography or equivalent) — do not introduce new constants for this screen. Register the route in the same place all other routes are registered — do not create a new routing file. Keep the screen stateless for now (StatelessWidget) — state management will be added in the next task.
Use const where possible on all static children. Section grouping can be a simple Padding + Text header above a Card or a simple Container — match the visual pattern of existing settings sections in the app.
Testing Requirements
Write one basic widget test that pumps NotificationPreferencesScreen inside a MaterialApp with the app's theme and verifies: (1) the AppBar title text is present, (2) the section header labels are present, (3) no RenderFlex overflow errors are thrown on a 320x568 viewport (smallest common iPhone size). No BLoC/Riverpod mocks needed for this scaffold task. Run `flutter analyze` and ensure zero warnings before marking the task done.
The in-app notification banner depends on a Supabase Realtime subscription to detect new notification records. If the subscription reconnects slowly after an app resume from background, or if Realtime delivery is delayed under high load, the banner may not appear within the 2-second acceptance criterion.
Mitigation & Contingency
Mitigation: Implement an explicit subscription reconnect handler on app foreground events using Flutter's AppLifecycleState.resumed hook, and add a polling fallback that queries for unread notifications once per app foreground event as a safety net against missed Realtime events.
Contingency: If Realtime proves unreliable in production, promote the polling fallback to the primary mechanism with a 30-second interval, accepting slight latency in exchange for reliability.
Cold-start deep linking (app not running when push notification is tapped) requires deferred navigation after the Flutter engine and Supabase session are fully initialised. If the deep link is consumed before authentication completes, the router may navigate to a protected route without a valid session, causing an error or redirect loop.
Mitigation & Contingency
Mitigation: Implement a deferred navigation queue in scenario-deep-link-router that holds the parsed deep-link target until the auth session restoration lifecycle event fires, following the existing deep-link-handler pattern used in the BankID and Vipps authentication flows.
Contingency: If deferred navigation is not achievable within the epic's scope, fall back to navigating the user to the notification centre (which is always accessible post-login) where the relevant notification record is visible and tappable.