Build NotificationCenterScreen with Full History
epic-push-notification-delivery-ui-task-012 — Implement the full-screen NotificationCenterScreen displaying paginated notification history using NotificationListItemWidget cards. Include read/unread visual differentiation (bold title, accent dot), pull-to-refresh, infinite scroll pagination, mark-all-read action in app bar, and swipe-to-dismiss individual items. Show empty state illustration when no notifications exist. Apply WCAG 2.2 AA semantics and design token system throughout.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Model pagination as offset+limit (page * 20). Cubit holds a List
For mark-all-read, update the local list in state (map all items to read: true) before the Supabase call completes (optimistic). Use Dismissible's confirmDismiss to show the SnackBar and handle undo logic cleanly. All visual styles (bold weight, accent dot size/color, card padding) must use design tokens — define named token constants rather than inline values.
Testing Requirements
Unit tests: test NotificationCenterCubit state machine — initial load success, load failure, load-more (pagination), mark-as-read, mark-all-read, dismiss, undo-dismiss. Use bloc_test with mocked NotificationRepository. Widget tests: render screen with a list of 5 mock notifications (mix of read/unread), verify bold styling on unread items, verify empty state when list is empty, verify AppBar 'Mark all as read' button triggers correct cubit event. Test swipe-to-dismiss renders SnackBar.
Test infinite scroll by pumping a scroll event near the bottom and verifying load-more event fires. Integration test: real paginated Supabase query with 25 seed records — verify two pages load. Accessibility test: verify Semantics labels on 3 notification items. Target 85% coverage on cubit and 75% on widget.
The notification badge widget depends on a persistent Supabase Realtime websocket subscription for live unread count updates. On mobile, network transitions (WiFi to cellular, background app state) can silently drop the websocket, resulting in a stale badge count that does not update until the next app foreground — reducing trust in the notification system.
Mitigation & Contingency
Mitigation: Implement connection lifecycle management in the badge widget's BLoC that re-subscribes on app foreground and on network reconnection events. Add a fallback polling query (every 60 seconds when app is foregrounded) to reconcile the badge count if the Realtime subscription is interrupted.
Contingency: If Realtime reliability proves insufficient in production, replace the live subscription with a polling approach using a configurable interval, accepting slightly delayed badge updates in exchange for reliability.
The notification list item widget requires merged semantics combining title, body, timestamp, read state, and role-context icon into a single VoiceOver/TalkBack announcement. Getting the merged semantics structure right for both iOS (VoiceOver) and Android (TalkBack) simultaneously is non-trivial and common to break silently when widgets are refactored.
Mitigation & Contingency
Mitigation: Use the project's existing semantics-wrapper-widget pattern with explicit Semantics widgets and excludeSemantics on decorative children. Write accessibility widget tests using Flutter's SemanticsController to assert the exact announcement string. Test on physical devices with VoiceOver and TalkBack enabled before release.
Contingency: If merged semantics cannot be achieved cleanly on both platforms, implement platform-specific semantic trees using defaultTargetPlatform branching, ensuring each platform receives an optimal announcement even if the implementation differs.