feat: add custom messages for cant-do error reasons#288
Conversation
- Add handling for 10 specific cant-do reasons in snackbar notifications - Implement custom messages for: pending_order_exists, not_allowed_by_status, invalid_invoice, invalid_trade_index, is_not_your_order, invalid_signature, invalid_peer, invalid_pubkey, order_already_canceled, out_of_range_sats_amount
WalkthroughThe PR adds reason-specific cantDo notification handling, shortens several localization strings (EN/ES/IT), updates two localization method signatures used in the trade detail widget, and adds a sendNotification stub to test mocks. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant App
participant NotificationListener
participant I18n as S
participant UI as Snackbar
User->>App: Trigger action/event
App-->>NotificationListener: Emit notification { action: cantDo, values: { reason, action } }
NotificationListener->>NotificationListener: Inspect values['action']== 'cantDo' and values['reason']
alt Recognized reason (e.g., pending_order_exists, out_of_range_sats_amount, not_allowed_by_status)
NotificationListener->>I18n: Request localized message for that reason
else Unknown reason
NotificationListener->>I18n: Request generic mapped title
end
NotificationListener->>UI: Show Snackbar with localized message
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
✨ Finishing Touches🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
lib/features/trades/widgets/mostro_message_detail_widget.dart (2)
241-269: Make cantDo fallback user-friendly and aligned with PRThe default currently leaks internal state/action text. Per PR goals, fall back to a generic “Action not allowed” message.
- default: - return '${tradeState.status.toString()} - ${tradeState.action}'; // This is a fallback message for developers + default: + // Generic fallback for unmapped cant-do reasons + return S.of(context)!.notificationCantDoMessage;
241-269: Pass real min/max to outOfRangeFiatAmount (avoid literal placeholders in UI)Currently it renders "{fiat_min}" / "{fiat_max}" literally. Use configured bounds when available; otherwise fall back to the generic cant-do message.
- case CantDoReason.outOfRangeFiatAmount: - return S.of(context)!.outOfRangeFiatAmount('{fiat_min}', '{fiat_max}'); + case CantDoReason.outOfRangeFiatAmount: + final mi = ref.read(orderRepositoryProvider).mostroInstance; + final min = mi?.minOrderAmount?.toString(); + final max = mi?.maxOrderAmount?.toString(); + if (min != null && max != null) { + return S.of(context)!.outOfRangeFiatAmount(min, max); + } + return S.of(context)!.notificationCantDoMessage;
🧹 Nitpick comments (5)
lib/l10n/intl_es.arb (1)
139-141: Minor wording consistency: “sats” lowercase.Most strings elsewhere use “sats”. Consider “La cantidad de sats…”.
lib/l10n/intl_en.arb (1)
140-140: Style nit: use “sats” (lowercase) for consistency.“The sats amount is out of the allowed range.”
lib/shared/widgets/notification_listener_widget.dart (2)
41-60: Replace long if-else chain with a map for clarity and maintainability.This reduces branching and makes adding new reasons trivial.
- if (cantDoReason == 'pending_order_exists') { - message = S.of(context)!.pendingOrderExists; - } else if (cantDoReason == 'not_allowed_by_status') { - message = S.of(context)!.notAllowedByStatus; - } else if (cantDoReason == 'invalid_invoice') { - message = S.of(context)!.invalidInvoice; - } else if (cantDoReason == 'invalid_trade_index') { - message = S.of(context)!.invalidTradeIndex; - } else if (cantDoReason == 'is_not_your_order') { - message = S.of(context)!.isNotYourOrder; - } else if (cantDoReason == 'invalid_signature') { - message = S.of(context)!.invalidSignature; - } else if (cantDoReason == 'invalid_peer') { - message = S.of(context)!.invalidPeer; - } else if (cantDoReason == 'invalid_pubkey') { - message = S.of(context)!.invalidPubkey; - } else if (cantDoReason == 'order_already_canceled') { - message = S.of(context)!.orderAlreadyCanceled; - } else if (cantDoReason == 'out_of_range_sats_amount') { - message = S.of(context)!.outOfRangeSatsAmount; - } else { - // Use generic cant-do message for other reasons - message = NotificationMessageMapper.getLocalizedTitle(context, next.action!); - } + final reasons = <String, String>{ + 'pending_order_exists': S.of(context)!.pendingOrderExists, + 'not_allowed_by_status': S.of(context)!.notAllowedByStatus, + 'invalid_invoice': S.of(context)!.invalidInvoice, + 'invalid_trade_index': S.of(context)!.invalidTradeIndex, + 'is_not_your_order': S.of(context)!.isNotYourOrder, + 'invalid_signature': S.of(context)!.invalidSignature, + 'invalid_peer': S.of(context)!.invalidPeer, + 'invalid_pubkey': S.of(context)!.invalidPubkey, + 'order_already_canceled': S.of(context)!.orderAlreadyCanceled, + 'out_of_range_sats_amount': S.of(context)!.outOfRangeSatsAmount, + }; + message = (cantDoReason != null && reasons.containsKey(cantDoReason)) + ? reasons[cantDoReason]! + : NotificationMessageMapper.getLocalizedTitle(context, next.action!);
62-67: Optional: handle additional likely reason ‘out_of_range_fiat_amount’.If protocol may send it, map to S.of(context)!.outOfRangeFiatAmount to keep parity.
Would you like me to add this mapping now?
lib/features/trades/widgets/mostro_message_detail_widget.dart (1)
241-269: Deduplicate cantDo reason-to-message mappingCant-do reason mapping is now in multiple places (this widget and notification listener). Extract a single mapper (e.g., CantDoReasonLocalizer.map(reason, context, values)) and reuse to avoid drift.
I can sketch a small helper and update both call sites if you want.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
lib/features/trades/widgets/mostro_message_detail_widget.dart(1 hunks)lib/l10n/intl_en.arb(2 hunks)lib/l10n/intl_es.arb(2 hunks)lib/l10n/intl_it.arb(2 hunks)lib/shared/widgets/notification_listener_widget.dart(2 hunks)test/mocks.mocks.dart(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
lib/l10n/intl_{en,es,it}.arb
📄 CodeRabbit inference engine (CLAUDE.md)
Add new localization keys to all three ARB files (en, es, it)
Files:
lib/l10n/intl_es.arblib/l10n/intl_en.arblib/l10n/intl_it.arb
{lib/*.dart,lib/!(generated)/**/*.dart}
📄 CodeRabbit inference engine (CLAUDE.md)
{lib/*.dart,lib/!(generated)/**/*.dart}: Use localized strings; replace hardcoded user-facing text withS.of(context).keyName
Preferconstconstructors andconstwhere possible
Use latest Flutter/Dart APIs (e.g.,withValues()instead of deprecatedwithOpacity())
Files:
lib/shared/widgets/notification_listener_widget.dartlib/features/trades/widgets/mostro_message_detail_widget.dart
{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}
📄 CodeRabbit inference engine (CLAUDE.md)
{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}: Checkmountedbefore usingBuildContextafterawait(async gaps)
Remove unused imports and dependencies
Files:
lib/shared/widgets/notification_listener_widget.dartlib/features/trades/widgets/mostro_message_detail_widget.darttest/mocks.mocks.dart
**/*.dart
📄 CodeRabbit inference engine (CLAUDE.md)
All code comments, variable names, and function names must be in English
Files:
lib/shared/widgets/notification_listener_widget.dartlib/features/trades/widgets/mostro_message_detail_widget.darttest/mocks.mocks.dart
**/*.mocks.dart
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.mocks.dart: Never manually edit Mockito-generated*.mocks.dartfiles
Do not add ignore comments to*.mocks.dart; regenerate instead if analyzer issues appear
Files:
test/mocks.mocks.dart
test/mocks.mocks.dart
📄 CodeRabbit inference engine (CLAUDE.md)
test/mocks.mocks.dart: Do not manually modifytest/mocks.mocks.dart(auto-generated by Mockito)
Do not add additional ignore directives; file already has file-level ignores
Files:
test/mocks.mocks.dart
test/**
📄 CodeRabbit inference engine (CLAUDE.md)
Place unit tests under
test/
Files:
test/mocks.mocks.dart
🧠 Learnings (5)
📚 Learning: 2025-08-28T20:32:34.625Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.625Z
Learning: Applies to lib/l10n/intl_{en,es,it}.arb : Add new localization keys to all three ARB files (en, es, it)
Applied to files:
lib/l10n/intl_es.arblib/l10n/intl_it.arb
📚 Learning: 2025-05-06T15:49:26.443Z
Learnt from: chebizarro
PR: MostroP2P/mobile#74
File: lib/services/mostro_service.dart:70-76
Timestamp: 2025-05-06T15:49:26.443Z
Learning: In the Mostro Mobile codebase, Riverpod code generation is used with `Riverpod` annotations. Providers like `eventStorageProvider` are generated in `.g.dart` files from annotated functions in the main provider files. These providers are accessible by importing the main provider file (e.g., `mostro_service_provider.dart`), not by importing a separate provider file.
Applied to files:
lib/shared/widgets/notification_listener_widget.dart
📚 Learning: 2025-08-28T20:32:34.625Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.625Z
Learning: Use Riverpod for state management with Notifiers encapsulating business logic; access data only through repositories
Applied to files:
lib/shared/widgets/notification_listener_widget.dart
📚 Learning: 2025-08-15T01:37:12.243Z
Learnt from: Catrya
PR: MostroP2P/mobile#270
File: lib/shared/widgets/order_filter.dart:133-135
Timestamp: 2025-08-15T01:37:12.243Z
Learning: The MostroP2P/mobile project requires Flutter >=3.27.0 as specified in pubspec.yaml, which supports the Color.withValues() method, so usage of withValues() throughout the codebase is valid and should not be flagged as a compatibility issue.
Applied to files:
lib/shared/widgets/notification_listener_widget.dart
📚 Learning: 2025-08-28T20:32:34.625Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.625Z
Learning: Applies to test/mocks.mocks.dart : Do not manually modify `test/mocks.mocks.dart` (auto-generated by Mockito)
Applied to files:
test/mocks.mocks.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (5)
lib/l10n/intl_es.arb (1)
124-147: Generic messages parity and usage verified
intl_it.arb includes the same four no-argument keys, and no call sites invoke them with placeholders.lib/l10n/intl_en.arb (1)
124-147: Generic no-arg messages verified, Italian locale in sync. Verified there are no remaining calls passing arguments to notAllowedByStatus or outOfRangeSatsAmount, and intl_it.arb contains matching no-arg entries.lib/shared/widgets/notification_listener_widget.dart (1)
4-4: UnifyActionimport path:notification_listener_widget.dartimports frompackage:mostro_mobile/data/models/enums/action.dartwhile mocks/tests import viapackage:mostro_mobile/data/enums.dart. Confirm thatdata/enums.dartre-exports the sameActionenum; otherwise, consolidate to one import to prevent duplicate types.lib/features/trades/widgets/mostro_message_detail_widget.dart (1)
251-256: Approve zero-arg localized getters Verified via ripgrep that there are no remaining calls toS.of(context)!.notAllowedByStatus(orS.of(context)!.outOfRangeSatsAmount(; changes approved.lib/l10n/intl_it.arb (1)
124-124: All four translation keys are present in intl_en.arb, intl_es.arb, and intl_it.arb—please regenerate l10n
Run your locale generation command (e.g.flutter pub run intl_utils:generate).
fix #269
cant-doreasons in snackbar notificationspending_order_exists,not_allowed_by_status,invalid_invoice,invalid_trade_index,is_not_your_order,invalid_signature,invalid_peer,invalid_pubkey,order_already_canceled,out_of_range_sats_amountcant-doit will continue to be seen as before: "Action not allowed"Summary by CodeRabbit
New Features
Style
Tests