Skip to content

feat(phase15): notifications center — card widget, Sembast ... - #66

Merged
grunch merged 3 commits into
mainfrom
006-mostro-p2p-client
Mar 30, 2026
Merged

feat(phase15): notifications center — card widget, Sembast ...#66
grunch merged 3 commits into
mainfrom
006-mostro-p2p-client

Conversation

@grunch

@grunch grunch commented Mar 30, 2026

Copy link
Copy Markdown
Member
  • notification_model: add ratingReceived, paymentReceived, invoiceRequest, orderTaken types; add detail field, toJson/fromJson, factory constructors
  • notifications_provider: SembastNotificationsStore (loadAll/save/delete); notificationsProviderWithDb; bridge stubs onTradeUpdated/onNewMessage
  • notification_card.dart: circular type icon, bold title/subtitle, detail section (blue border), green unread dot, overflow menu
  • notifications_screen: use NotificationCard widget; type-based tap navigation (rate, invoice, pay, trade, dispute)
  • push_notification_service.dart: platform-gated FCM stubs, NotificationListenerWidget routes tap payloads to GoRouter

Summary by CodeRabbit

  • New Features
    • Four new notification types: rating received, payment received, invoice request, and order taken
    • Local persistence of notifications across app sessions
    • Push notification handling on mobile with in-app tap routing
  • UI
    • Enhanced notification card with details, relative timestamps, unread indicator, and quick-action menu (mark read / delete)
    • Improved navigation from notifications to relevant order/dispute screens
  • Chores
    • Project task list updated to mark related notification work as completed

grunch added 2 commits March 30, 2026 20:31
…e, push service

- notification_model: add ratingReceived, paymentReceived, invoiceRequest, orderTaken types; add detail field, toJson/fromJson, factory constructors
- notifications_provider: SembastNotificationsStore (loadAll/save/delete); notificationsProviderWithDb; bridge stubs onTradeUpdated/onNewMessage
- notification_card.dart: circular type icon, bold title/subtitle, detail section (blue border), green unread dot, overflow menu
- notifications_screen: use NotificationCard widget; type-based tap navigation (rate, invoice, pay, trade, dispute)
- push_notification_service.dart: platform-gated FCM stubs, NotificationListenerWidget routes tap payloads to GoRouter
… UX feedback

- notifications_provider: fix _open() race with Completer; upsert save() via Finder instead of always add(); await all store ops with try/catch error logging; load persisted notifications on startup via loadInitialData(); add unreadNotificationCountProviderWithDb
- notifications_screen: _handleTap shows SnackBar when required orderId/disputeId is null instead of silent no-op
- push_notification_service: validate orderId/disputeId against alphanumeric+hyphen/underscore pattern before constructing routes
@coderabbitai

coderabbitai Bot commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

Pull request was closed or merged during review

Walkthrough

This PR adds a DB-backed notification system: extended NotificationModel (new types, detail field, JSON, factories), a Sembast-backed store and updated NotificationsNotifier (async persistence), a reusable NotificationCard widget, push-notification routing infrastructure, and screen wiring to use the new card.

Changes

Cohort / File(s) Summary
Notification model
lib/features/notifications/models/notification_model.dart
Added enum values (ratingReceived, paymentReceived, invoiceRequest, orderTaken), optional detail: Map<String,String>?, JSON serialization (toJson/fromJson), and factory constructors for common notification types plus backupReminder.
Persistence & provider
lib/features/notifications/providers/notifications_provider.dart
Added SembastNotificationsStore and sembastNotificationsStoreProvider. Added notificationsProviderWithDb. NotificationsNotifier now accepts optional store, exposes loadInitialData(), and converts core methods (add, markAsRead, delete, deleteAll) to async with persistence; added onTradeUpdated/onNewMessage stubs.
UI widget
lib/features/notifications/widgets/notification_card.dart
New public NotificationCard widget with unread indicator, icon mapping, title/message, optional detail block, relative timestamp, and overflow menu actions (Mark as read, Delete).
Screen integration
lib/features/notifications/screens/notifications_screen.dart
Replaced private card with public NotificationCard, added onTap routing by NotificationType (uses AppRoute.*Path(...)), removed prior local context-menu and relative-time helpers, expanded icon mapping for new types.
Push notification service
lib/features/notifications/services/push_notification_service.dart
Added PushNotificationService singleton with initialize() (platform-gated stubs) and routeFromPayload() for payload→route parsing/validation. Added NotificationListenerWidget to handle push-tap navigation.
Spec update
specs/004-mostro-p2p-client/tasks.md
Marked tasks T103–T106 as completed.
Dependencies
pubspec.yaml
Added sembast_web and uuid dependencies; assets section unchanged beyond re-adding assets/images/.

Sequence Diagram(s)

sequenceDiagram
    participant App as User/App
    participant PushSvc as PushNotificationService
    participant Payload as Push Payload
    participant NotifListener as NotificationListenerWidget
    participant Router as GoRouter
    participant Provider as NotificationsNotifier
    participant Store as SembastNotificationsStore
    participant UI as NotificationCard

    App->>PushSvc: initialize()
    PushSvc-->>PushSvc: register platform listeners (stubbed)
    Note over Payload: Push arrives (tap)
    PushSvc->>NotifListener: deliver payload
    NotifListener->>PushSvc: routeFromPayload(payload)
    PushSvc-->>Router: return route path
    NotifListener->>Router: context.push(route)

    Note over App,Provider: User opens notifications
    App->>Provider: loadInitialData()
    Provider->>Store: loadAll()
    Store-->>Provider: notifications[]
    Provider->>UI: render NotificationCard(s)

    UI->>Provider: onTap / onMarkRead / onDelete
    Provider->>Store: save() / deleteRecord()
    Store-->>Provider: persisted
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰
I hopped through code to add a bell,
Sembast keeps tales it learned to tell,
Cards that shimmer, taps that steer,
Payloads route the way that's clear,
A tiny rabbit cheers—hip, hop, swell!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title references the main features added (notifications center, card widget, Sembast) but is truncated with '…' and lacks the full scope of changes. Complete the title to clearly describe the full feature set, e.g., 'feat(phase15): notifications center with card widget, Sembast persistence, and push routing'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 006-mostro-p2p-client

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/features/notifications/screens/notifications_screen.dart (1)

22-36: ⚠️ Potential issue | 🟠 Major

The screen is still wired to the in-memory provider.

Every read/write path here uses notificationsProvider, so notificationsProviderWithDb never hydrates or persists the actual notifications screen. After restart, the list will still reset even though the store exists.

🛠️ Suggested fix
-    final notifications = ref.watch(notificationsProvider);
+    final notifications = ref.watch(notificationsProviderWithDb);
...
-                  ref.read(notificationsProvider.notifier).markAllAsRead();
+                  ref.read(notificationsProviderWithDb.notifier).markAllAsRead();
-                  ref.read(notificationsProvider.notifier).deleteAll();
+                  ref.read(notificationsProviderWithDb.notifier).deleteAll();
...
-                ref.read(notificationsProvider.notifier).markAsRead(n.id),
+                ref.read(notificationsProviderWithDb.notifier).markAsRead(n.id),
-                ref.read(notificationsProvider.notifier).delete(n.id),
+                ref.read(notificationsProviderWithDb.notifier).delete(n.id),

Also applies to: 91-96

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/features/notifications/screens/notifications_screen.dart` around lines 22
- 36, The UI is wired to the in-memory notificationsProvider instead of the
persistent notificationsProviderWithDb; update all refs in this file (every
ref.watch(...) and ref.read(...).notifier usage) to use
notificationsProviderWithDb so the screen hydrates and persists state across
restarts (e.g., change ref.watch(notificationsProvider) and
ref.read(notificationsProvider.notifier).markAllAsRead()/deleteAll() to use
notificationsProviderWithDb and its notifier methods); also verify the notifier
exposes markAllAsRead and deleteAll used here and apply the same replacement for
the other occurrences around lines 91-96.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/features/notifications/models/notification_model.dart`:
- Around line 94-155: The factory constructors
(NotificationModel.ratingReceived, paymentReceived, invoiceRequest, orderTaken,
backupReminder) currently generate IDs from
DateTime.now().microsecondsSinceEpoch which can collide; change the id
generation to a collision-resistant value (e.g., UUID v4 or secure random
string) and use that in each factory instead of the timestamp alone — for
example, use the uuid package (Uuid().v4()) or combine timestamp with a random
suffix so NotificationModel.id is unique across rapid bursts and won’t cause
save() upserts to overwrite other notifications.

In `@lib/features/notifications/providers/notifications_provider.dart`:
- Around line 187-191: The two bridge hook stubs onTradeUpdated and onNewMessage
are empty so Rust events never become NotificationModel entries; implement each
to build a NotificationModel (include type/tag like "trade_update" or
"new_message", orderId, status for trades, message text/summary for messages,
timestamps, and any ids) and pass it into the provider's add(...) method
(NotificationsProvider.add or the existing add function) so the notification is
stored/emitted; ensure you populate required fields used elsewhere
(icon/title/body/timestamp) and rely on add/notifyListeners to update the
center/bell UI.
- Around line 28-31: The web branch currently uses databaseFactoryMemory which
discards data on refresh; add the sembast_web dependency to pubspec.yaml and
switch the web code to use databaseFactoryWeb.openDatabase(_dbName) instead of
databaseFactoryMemory.openDatabase(_dbName). Also add the necessary import for
sembast_web (so the symbol databaseFactoryWeb is available) in
lib/features/notifications/providers/notifications_provider.dart and ensure any
platform-conditional logic still compiles for non-web targets.

In `@lib/features/notifications/services/push_notification_service.dart`:
- Around line 88-92: NotificationListenerWidget currently leaves initState()
empty so _handlePayload() never runs; subscribe to
FirebaseMessaging.onMessageOpenedApp in initState (e.g., assign a
StreamSubscription to a field like _openedAppSubscription) and in the listener
call _handlePayload(message.data) (or message.data ?? {}), and then cancel the
subscription in dispose() to avoid leaks; ensure you import FirebaseMessaging
and use the exact symbols NotificationListenerWidget, initState, _handlePayload,
onMessageOpenedApp and dispose when adding the subscription and cleanup.
- Around line 51-63: The routeFromPayload function currently uses string
literals that don't match the app's NotificationModel.type.name values and omits
the orderTaken case; update routeFromPayload to handle the serialized enum names
(use the same strings produced by NotificationType.*.name) and add a branch for
"orderTaken" that returns the correct route (reference function routeFromPayload
and the NotificationType.orderTaken enum/name and NotificationModel.type.name to
align values); ensure other cases use the enum-backed names so payloads from
NotificationModel.type.name map correctly.

In `@lib/features/notifications/widgets/notification_card.dart`:
- Around line 248-251: The branch that maps NotificationType.invoiceRequest,
NotificationType.orderUpdate, and NotificationType.orderTaken uses the invoice
glyph (Icons.description) causing orderTaken to show the wrong icon; update the
mapping for NotificationType.orderTaken in the tuple returned by the
match/branch so that orderTaken uses the add-circle icon (e.g.,
Icons.add_circle) with the same color (Colors.green) to match the rest of the PR
and keep iconography consistent for NotificationType.orderTaken.
- Around line 26-117: Replace the non-accessible GestureDetector wrapper with a
Material + InkWell (or wrap with FocusableActionDetector+Semantics) so the
notification card supports keyboard focus, ripple, and proper semantics; update
the widget that builds the tap surface (the top-level GestureDetector around the
Stack in notification_card.dart) to use Material + InkWell (forward existing
onTap, preserve padding/shape/borderRadius) and ensure it exposes focus/hover
states. Also fix the icon inconsistency by changing the mapping for the
orderTaken case in _TypeIconCircle (or wherever notification.type -> icon is
defined) to match the icon used in notifications_screen.dart (use the same
symbol, e.g., Icons.add_circle_outline) so both screens show the same icon for
orderTaken.

---

Outside diff comments:
In `@lib/features/notifications/screens/notifications_screen.dart`:
- Around line 22-36: The UI is wired to the in-memory notificationsProvider
instead of the persistent notificationsProviderWithDb; update all refs in this
file (every ref.watch(...) and ref.read(...).notifier usage) to use
notificationsProviderWithDb so the screen hydrates and persists state across
restarts (e.g., change ref.watch(notificationsProvider) and
ref.read(notificationsProvider.notifier).markAllAsRead()/deleteAll() to use
notificationsProviderWithDb and its notifier methods); also verify the notifier
exposes markAllAsRead and deleteAll used here and apply the same replacement for
the other occurrences around lines 91-96.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5618831e-ae77-45c3-8f53-b8c779fdb0cf

📥 Commits

Reviewing files that changed from the base of the PR and between 93d2315 and 944fccf.

📒 Files selected for processing (6)
  • lib/features/notifications/models/notification_model.dart
  • lib/features/notifications/providers/notifications_provider.dart
  • lib/features/notifications/screens/notifications_screen.dart
  • lib/features/notifications/services/push_notification_service.dart
  • lib/features/notifications/widgets/notification_card.dart
  • specs/004-mostro-p2p-client/tasks.md

Comment thread lib/features/notifications/models/notification_model.dart
Comment thread lib/features/notifications/providers/notifications_provider.dart Outdated
Comment thread lib/features/notifications/providers/notifications_provider.dart Outdated
Comment thread lib/features/notifications/services/push_notification_service.dart
Comment thread lib/features/notifications/services/push_notification_service.dart
Comment thread lib/features/notifications/widgets/notification_card.dart Outdated
Comment thread lib/features/notifications/widgets/notification_card.dart
@coderabbitai

coderabbitai Bot commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 5 file(s) based on 7 unresolved review comments.

Files modified:

  • lib/features/notifications/models/notification_model.dart
  • lib/features/notifications/providers/notifications_provider.dart
  • lib/features/notifications/services/push_notification_service.dart
  • lib/features/notifications/widgets/notification_card.dart
  • pubspec.yaml

Commit: 46f115c459257bd455e4131bcf5dc1dde16b6721

The changes have been pushed to the 006-mostro-p2p-client branch.

Time taken: 7m 8s

Fixed 5 file(s) based on 7 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
@grunch
grunch merged commit 049cab6 into main Mar 30, 2026
1 check was pending
@grunch
grunch deleted the 006-mostro-p2p-client branch March 30, 2026 23:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant