feat: implement V1 flow gaps — dispute, invoice, countdown, UI polish - #87
Conversation
- Wire DISPUTE button to disputes_api.openDispute() in all 3 trade status contexts (active buyer, active seller, fiat-sent seller); upsert result into DisputeNotifier and navigate to dispute chat - Add waitingInvoice/waitingPayment TradeStatus values; map waitingBuyerInvoice → ADD INVOICE (buyer) and waitingPayment → PAY INVOICE (seller) action buttons in TradeDetailScreen - Replace hardcoded hold invoice mock with real TradeInfo.holdInvoice and TradeInfo.order.amountSats in PayLightningInvoiceScreen; show loading state while invoice is not yet available from the daemon - Fetch real expiresAt from getOrder() on screen open instead of hardcoded 900s countdown; falls back to default on error - Add tradeInfoProvider (FutureProvider.family) to trades_providers for looking up TradeInfo by orderId across the app - ChatRoomsScreen mobile AppBar: hamburger drawer toggle, Mostro logo, notification bell — matching HomeScreen pattern - Compact time format in trades list: "4m"/"2h"/"3d" instead of verbose - Redirect /relays to /settings (remove _Stub placeholder)
- Hide raw exception details in PayLightningInvoiceScreen error state; log via debugPrint and show a generic user-facing message - Guard NwcPaymentWidget behind amountSats > 0 check so it is only instantiated when the hold invoice amount is known - Localize waiting-invoice/waiting-payment instruction strings in TradeDetailScreen (en/es/it/fr/de) - Localize "Could not open dispute" error snackbar in TradeDetailScreen - Remove unused flutter/material.dart import from app_routes.dart
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 14 minutes and 23 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (14)
WalkthroughRefactors chat drawer behavior and pay-invoice flow to load real trade data via a new Changes
Sequence DiagramsequenceDiagram
actor User
participant TradeDetailScreen
participant disputes_api
participant DisputeNotifier
participant Router
User->>TradeDetailScreen: Tap "Open Dispute"
TradeDetailScreen->>disputes_api: openDispute(orderId)
alt Success
disputes_api-->>TradeDetailScreen: DisputeItem
TradeDetailScreen->>DisputeNotifier: upsert(disputeItem)
TradeDetailScreen->>Router: navigate to dispute details
Router-->>User: Show dispute screen
else Failure
disputes_api-->>TradeDetailScreen: Exception
TradeDetailScreen->>User: show snackbar (openDisputeFailed)
TradeDetailScreen->>TradeDetailScreen: debugPrint(error)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/features/trades/screens/trade_detail_screen.dart (1)
417-430:⚠️ Potential issue | 🟡 MinorProgress indicator calculation may be inaccurate after loading real
expiresAt.The progress indicator divides
_remainingby the hardcoded_kCountdownSeconds(900s), but_loadExpiresAt()may set_remainingto a different total duration from the server. If the real countdown is longer than 900s, the indicator starts at 100%; if shorter, it starts partially filled.Consider tracking the initial/total duration alongside the remaining time.
Proposed fix
class _TradeDetailScreenState extends ConsumerState<TradeDetailScreen> { Timer? _countdownTimer; Duration _remaining = const Duration(seconds: _kCountdownSeconds); + Duration _total = const Duration(seconds: _kCountdownSeconds); // In _loadExpiresAt(): setState(() { - _remaining = diff > 0 ? Duration(seconds: diff) : Duration.zero; + _remaining = diff > 0 ? Duration(seconds: diff) : Duration.zero; + _total = _remaining; }); // In build(), update the indicator: CircularProgressIndicator( - value: (_remaining.inSeconds / _kCountdownSeconds).clamp(0.0, 1.0), + value: _total.inSeconds > 0 + ? (_remaining.inSeconds / _total.inSeconds).clamp(0.0, 1.0) + : 0.0,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/features/trades/screens/trade_detail_screen.dart` around lines 417 - 430, The progress indicator uses _remaining / _kCountdownSeconds which breaks when _loadExpiresAt() sets a different total duration; add a new field (e.g. _totalCountdownSeconds or _initialDurationSeconds) initialized to _kCountdownSeconds and set it inside _loadExpiresAt() to the server-provided total seconds, then change the CircularProgressIndicator value to (_remaining.inSeconds / _totalCountdownSeconds).clamp(0.0,1.0) and guard against division by zero (fall back to 1.0 or _kCountdownSeconds). Update references to _kCountdownSeconds in the widget and expiry-loading logic to use the new field (_remaining, _loadExpiresAt, and the CircularProgressIndicator) so the indicator reflects the actual total duration.
🧹 Nitpick comments (2)
lib/features/chat/screens/chat_rooms_screen.dart (1)
17-26: Consider usingStatefulWidgetinstead ofConsumerStatefulWidget.The
_ChatRoomsScreenState.build()method doesn't useref— the Riverpod provider access happens in the child_MessagesTabwidget which is already aConsumerWidget. Using a plainStatefulWidgetwould be slightly more accurate and avoids the unnecessaryWidgetRefoverhead.That said, this is harmless and keeping
ConsumerStatefulWidgetprovides flexibility if provider access is needed in the parent later.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/features/chat/screens/chat_rooms_screen.dart` around lines 17 - 26, The parent widget ChatRoomsScreen is declared as a ConsumerStatefulWidget but its state _ChatRoomsScreenState does not use ref; change ChatRoomsScreen to extend StatefulWidget and change _ChatRoomsScreenState to extend State<ChatRoomsScreen> (also update the createState signature accordingly) so the parent no longer carries the unused WidgetRef overhead — leave provider access in the child _MessagesTab (which is already a ConsumerWidget).lib/features/order/screens/pay_lightning_invoice_screen.dart (1)
70-88: Consider localizing the "Waiting for hold invoice..." message.The waiting state text on line 81 is hardcoded. While the PR adds
tradeWaitingPaymentSellerInstructionfor the seller's instruction, this specific waiting message could benefit from a dedicated localization key for full i18n coverage.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/features/order/screens/pay_lightning_invoice_screen.dart` around lines 70 - 88, The hardcoded waiting text in PayLightningInvoiceScreen (inside the build branch guarded by invoice.isEmpty || amountSats <= 0) should be replaced with a localized string: add a new i18n key (e.g., tradeWaitingForHoldInvoice or tradeWaitingPaymentInvoice) to your localization resources and use the app's localization accessor (e.g., AppLocalizations.of(context) or S.of(context)) to render that key instead of the literal 'Waiting for hold invoice...'; update any ARB/JSON and generated localization classes accordingly so the widget displays the localized message.
🤖 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/order/screens/pay_lightning_invoice_screen.dart`:
- Around line 57-64: Replace the hardcoded English error message in the error
handler of PayLightningInvoiceScreen with the localized string for
tradeLoadError: import AppLocalizations (import
'package:mostro/l10n/app_localizations.dart';) and call
AppLocalizations.of(context)!.tradeLoadError when building the Scaffold body
text; ensure the change is made in the error: (e, st) { ... } block that returns
the Scaffold so the displayed message is localized.
---
Outside diff comments:
In `@lib/features/trades/screens/trade_detail_screen.dart`:
- Around line 417-430: The progress indicator uses _remaining /
_kCountdownSeconds which breaks when _loadExpiresAt() sets a different total
duration; add a new field (e.g. _totalCountdownSeconds or
_initialDurationSeconds) initialized to _kCountdownSeconds and set it inside
_loadExpiresAt() to the server-provided total seconds, then change the
CircularProgressIndicator value to (_remaining.inSeconds /
_totalCountdownSeconds).clamp(0.0,1.0) and guard against division by zero (fall
back to 1.0 or _kCountdownSeconds). Update references to _kCountdownSeconds in
the widget and expiry-loading logic to use the new field (_remaining,
_loadExpiresAt, and the CircularProgressIndicator) so the indicator reflects the
actual total duration.
---
Nitpick comments:
In `@lib/features/chat/screens/chat_rooms_screen.dart`:
- Around line 17-26: The parent widget ChatRoomsScreen is declared as a
ConsumerStatefulWidget but its state _ChatRoomsScreenState does not use ref;
change ChatRoomsScreen to extend StatefulWidget and change _ChatRoomsScreenState
to extend State<ChatRoomsScreen> (also update the createState signature
accordingly) so the parent no longer carries the unused WidgetRef overhead —
leave provider access in the child _MessagesTab (which is already a
ConsumerWidget).
In `@lib/features/order/screens/pay_lightning_invoice_screen.dart`:
- Around line 70-88: The hardcoded waiting text in PayLightningInvoiceScreen
(inside the build branch guarded by invoice.isEmpty || amountSats <= 0) should
be replaced with a localized string: add a new i18n key (e.g.,
tradeWaitingForHoldInvoice or tradeWaitingPaymentInvoice) to your localization
resources and use the app's localization accessor (e.g.,
AppLocalizations.of(context) or S.of(context)) to render that key instead of the
literal 'Waiting for hold invoice...'; update any ARB/JSON and generated
localization classes accordingly so the widget displays the localized message.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2539fef7-578d-43df-9b7b-4a38a59d3874
📒 Files selected for processing (11)
lib/core/app_routes.dartlib/features/chat/screens/chat_rooms_screen.dartlib/features/order/screens/pay_lightning_invoice_screen.dartlib/features/trades/providers/trades_providers.dartlib/features/trades/screens/trade_detail_screen.dartlib/features/trades/widgets/trades_list_item.dartlib/l10n/app_de.arblib/l10n/app_en.arblib/l10n/app_es.arblib/l10n/app_fr.arblib/l10n/app_it.arb
- Localize error and waiting-for-invoice strings in PayLightningInvoiceScreen - Add tradeWaitingForHoldInvoice key to all 5 language files - Fix countdown CircularProgressIndicator ratio: track actual total duration in _totalCountdownSeconds (set from server expiresAt) instead of the hardcoded constant so the arc is correct after _loadExpiresAt - Downgrade ChatRoomsScreen from ConsumerStatefulWidget to StatefulWidget since the state class does not consume any Riverpod providers directly
status contexts (active buyer, active seller, fiat-sent seller);
upsert result into DisputeNotifier and navigate to dispute chat
waitingBuyerInvoice → ADD INVOICE (buyer) and waitingPayment →
PAY INVOICE (seller) action buttons in TradeDetailScreen
and TradeInfo.order.amountSats in PayLightningInvoiceScreen; show
loading state while invoice is not yet available from the daemon
hardcoded 900s countdown; falls back to default on error
for looking up TradeInfo by orderId across the app
notification bell — matching HomeScreen pattern
Summary by CodeRabbit