Skip to content

feat(navigation): auto-open invoice screens on daemon request - #289

Merged
Catrya merged 7 commits into
mainfrom
auto-navigate-invoice-screens
Aug 7, 2026
Merged

feat(navigation): auto-open invoice screens on daemon request#289
Catrya merged 7 commits into
mainfrom
auto-navigate-invoice-screens

Conversation

@Catrya

@Catrya Catrya commented Aug 7, 2026

Copy link
Copy Markdown
Member

Closes #283
When the daemon sends add-invoice or pay-invoice, the app only navigated
automatically if the user happened to be sitting on MyOrderScreen (maker) or
in the take-order flow (taker) — the navigation logic was local to those
screens. If the message arrived while the user was anywhere else (home, chats,
another trade), nothing happened on screen:they
must act, and both actions expire on a time#287,
where the trade died precisely because the

Fix

Two pieces, mirroring v1's global `Navigatiism:

  • Rustemit_trade_update now fires rm
    that persists a status (escrow-locked, ade
    generic status-sync arm), not just canceler
    the order book and the trade DB are syncethe
    push reads consistent state. Take replieske
    waiter consumes them before the arms run ng
    local navigation with zero double-navigat
  • Dart — new TradeActionListener wrap
    tradeUpdatesProvider: WaitingBuyerInvo add-invoice screen, WaitingPaymentpushice screen, from any screen in the app. It reso the counterparty's informational copy ofwaiting-seller-to-paypersistsWaitingo)
    never navigates. It also skips when the dn
    top, dedupes bursts of identical emission
    tradeRoleProvider before navigating, as

MyOrderScreen drops its two invoice-navigr is
the single source of that navigation; it stfrom
Active on. Existing consumers of the stredes
list already refetches on any emission (it , on
every daemon-driven transition), and the invoice screens only act on
cancellation statuses.

Deliberate deviation from v1: no Lightning-ation —
with NWC connected the add-invoice screen amits
the invoice, and LN-address pre-fill is tra

Changes

  • rust/src/api/orders.rs: emissions in the four dispatch arms; stream,
    buffer and TradeUpdate docs updated.
  • rust/src/api/types.rs: TradeUpdate doc updated.
  • `lib/shared/widgets/trade_action_listenerener.
  • lib/core/app.dart: listener mounted at
  • `lib/features/order/screens/my_order_scre
    removed, now global.
  • `specs/004-mostro-p2p-client/contracts/or
    documented.

Summary by CodeRabbit

  • New Features
    • Trade updates now automatically open the relevant invoice or payment screen when action is required.
    • Trade status changes are synchronized across the order book and trade history.
  • Bug Fixes
    • Prevented duplicate, outdated, and unnecessary navigation.
    • Improved handling of waiting-invoice and waiting-payment orders.
    • Updates from counterparty actions no longer open inappropriate screens.
  • Documentation
    • Clarified which trade status changes trigger updates and user interface notifications.

Catrya added 4 commits August 6, 2026 22:58
- emit_trade_update now fires from every dispatch arm that persists a
  status: escrow-locked, add-invoice, pay-invoice and the generic
  status-sync arm, not just cancellations.
- Emission happens after book and DB are synced, so push listeners
  read consistent state.
- Take replies are untouched: the take waiter consumes them before the
  arms, so takers produce no emission.
- Stream, buffer and TradeUpdate docs updated to the new semantics.
- New TradeActionListener wraps the app root and listens to trade
  updates pushed by the Rust ingest.
- WaitingBuyerInvoice sends the buyer to add-invoice; WaitingPayment
  sends the seller to pay-invoice, from any screen in the app.
- Role check keeps informational syncs (the counterparty's copy of the
  same status) from navigating.
- Skips when already on the destination route; in-flight dedupe
  collapses bursts of identical emissions.
- Populates tradeRoleProvider before navigating, as the screens expect.
- WaitingBuyerInvoice and WaitingPayment no longer navigate from the
  maker's waiting screen; TradeActionListener pushes the invoice screen
  for the actionable role from anywhere, this screen included.
- The counterparty's informational copy of those statuses is tracked
  but never navigated, same as before.
- Post-frame navigation collapses to the trade detail route.
- on_trade_updated now covers every daemon-driven status sync, not just
  cancellations; consumers and the no-emission take-reply case listed.
- Inbound actions table notes the emission after both stores are synced.
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Catrya, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 40 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3be26839-a70e-4201-8a7b-8871abea587e

📥 Commits

Reviewing files that changed from the base of the PR and between eb2feb3 and 248ebd7.

📒 Files selected for processing (1)
  • test/shared/widgets/trade_action_listener_test.dart

Walkthrough

The app now emits trade updates after daemon status synchronization. A root listener opens role-specific invoice or payment routes globally. MyOrderScreen removes duplicate action navigation and routes remaining actionable statuses to trade details.

Changes

Trade-action navigation

Layer / File(s) Summary
Synchronized trade-update emission
rust/src/api/orders.rs, rust/src/api/types.rs, specs/004-mostro-p2p-client/contracts.md
Daemon status handlers emit TradeUpdate after order-book updates and database persistence attempts. API and contract documentation cover lifecycle, cancellation, and persistence behavior.
Global action navigation
lib/shared/widgets/trade_action_listener.dart, lib/core/app.dart, test/shared/widgets/trade_action_listener_test.dart
TradeActionListener consumes updates, validates roles and statuses, suppresses duplicate and stale navigation, initializes trade-role state, and opens action routes. Tests cover navigation, filtering, and stale updates.
Order-screen status routing
lib/features/order/screens/my_order_screen.dart
Invoice-related waiting statuses no longer navigate locally. Other actionable non-pending statuses navigate to trade details.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Daemon
  participant OrdersApi
  participant TradeDatabase
  participant tradeUpdatesProvider
  participant TradeActionListener
  participant NavigationRouter
  Daemon->>OrdersApi: dispatch trade status action
  OrdersApi->>TradeDatabase: attempt status persistence
  OrdersApi->>tradeUpdatesProvider: emit TradeUpdate
  tradeUpdatesProvider->>TradeActionListener: deliver update
  TradeActionListener->>NavigationRouter: open role-specific action route
Loading

Possibly related PRs

  • MostroP2P/app#274 — Modified the trade-update stream and invoice-related navigation flow.
  • MostroP2P/app#288 — Modified add-invoice status synchronization in the orders API.
  • MostroP2P/app#213 — Modified trade-status handling and invoice-payment routing.

Suggested reviewers: ermeme

Poem

I’m a rabbit watching trades in flight,
I hop to invoices at daemon’s light.
Stale hops fade from view,
Role checks guide each route true.
Synchronized updates make actions appear—
The right screen is here!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements global add-invoice and pay-invoice navigation but does not implement the linked issue's Lightning-address pre-fill requirement [#283]. Implement configured Lightning-address pre-fill for add-invoice, while skipping pre-fill after payment-failed as required by issue #283.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: automatic navigation to invoice screens when the daemon requests action.
Out of Scope Changes check ✅ Passed The Rust synchronization, listener, screen changes, documentation, and tests directly support the global daemon-triggered invoice navigation objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch auto-navigate-invoice-screens

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.

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/shared/widgets/trade_action_listener.dart`:
- Around line 36-68: Update _handle to track the latest status per orderId
before awaiting getTradeRole, then recheck that stored status still matches
update.status after the await and return when it has changed. Add a regression
test covering WaitingPayment followed by Active to ensure no stale pay-invoice
navigation occurs.

In `@rust/src/api/orders.rs`:
- Around line 2005-2013: Move each emit_trade_update call in the Kind 14
dispatch arms of rust/src/api/orders.rs (lines 2005-2013, 2056-2067, 2134,
2181-2189, and 3629-3636) into the successful update_trade_fields path, or
defer/retry it until synchronization succeeds; failed writes must not broadcast
TradeUpdate events. Update the corresponding contract at
specs/004-mostro-p2p-client/contracts/orders.md:264-266 to reflect that
TradeUpdate is emitted only after both book and persisted trade state are
consistent.
🪄 Autofix

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 Plus

Run ID: 79bcb13f-8c2d-4a78-828b-009cbe5001c2

📥 Commits

Reviewing files that changed from the base of the PR and between 526f277 and 274889a.

📒 Files selected for processing (6)
  • lib/core/app.dart
  • lib/features/order/screens/my_order_screen.dart
  • lib/shared/widgets/trade_action_listener.dart
  • rust/src/api/orders.rs
  • rust/src/api/types.rs
  • specs/004-mostro-p2p-client/contracts/orders.md

Comment thread lib/shared/widgets/trade_action_listener.dart Outdated
Comment thread rust/src/api/orders.rs
- Latest status per order is recorded synchronously on emission; a
  handler that finishes its role lookup after a newer status landed
  (startup replay delivers them milliseconds apart) no longer navigates.
- resolveRole and navigate are injectable test seams.
- Widget tests: actionable navigation, informational-copy skip, and the
  WaitingPayment-superseded-by-Active regression.

@ermeme ermeme Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review summary

Thanks for the update — the stale WaitingPaymentActive navigation race is fixed on the current head, and the Rust/Flutter CI checks are green. I found one remaining blocker: the updated stream contract still says TradeUpdate is emitted after both stores are consistent, but the implementation intentionally emits after the DB write is only attempted (or when there is no DB). That mismatch is now the public contract for this stream, so it should be corrected before merge.

Validated locally:

  • cargo check
  • cargo test (249 passed, 8 ignored)

GitHub checks on c9ea11df2c12b60d21eddf3f3f84730ee3ea4688 are green: Flutter analyze/test, Rust build/test/clippy/wasm, and Web wasm smoke test.

Comment thread specs/004-mostro-p2p-client/contracts/orders.md
- Emission happens after the in-memory book sync and the DB persistence
  attempt; DB failures or a memory-only session are logged and never
  suppress the notification.
- Listeners must tolerate a trade row that is missing or behind the
  book; the role lookup in TradeActionListener already does.
- Spec, on_trade_updated rustdoc and the listener doc now say so.

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/shared/widgets/trade_action_listener_test.dart`:
- Around line 45-59: Add a targeted widget test alongside “actionable status
navigates and records the role” for OrderStatus.waitingBuyerInvoice, configuring
pumpListener to resolve TradeRole.buyer and asserting navigation to
AppRoute.addInvoicePath('o1') and tradeRoleProvider contains {'o1': true}.
🪄 Autofix

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 Plus

Run ID: 899db27e-fa26-4ca2-b7d1-ebe56a48ae89

📥 Commits

Reviewing files that changed from the base of the PR and between 274889a and eb2feb3.

📒 Files selected for processing (4)
  • lib/shared/widgets/trade_action_listener.dart
  • rust/src/api/orders.rs
  • specs/004-mostro-p2p-client/contracts/orders.md
  • test/shared/widgets/trade_action_listener_test.dart
🚧 Files skipped from review as they are similar to previous changes (2)
  • rust/src/api/orders.rs
  • specs/004-mostro-p2p-client/contracts/orders.md

Comment thread test/shared/widgets/trade_action_listener_test.dart
- WaitingBuyerInvoice with a buyer role navigates to add-invoice and
  records the role, mirroring the existing seller pay-invoice test.

@ermeme ermeme Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review summary

Approved. The previous blocker is resolved on the current head: the TradeUpdate contract now describes the real semantics — emitted after the in-memory book update and DB persistence attempt, with DB failures logged and not suppressing the lifecycle notification.

I also re-checked the role-gated global navigation path and the new widget coverage for both WaitingPayment and WaitingBuyerInvoice, including the stale WaitingPaymentActive race.

Validated locally:

  • cargo check
  • cargo test (249 passed, 8 ignored)

GitHub checks on 248ebd7d523cd019fbf78a831564bf356d4a2443 are green: Flutter analyze/test, Rust build/test/clippy/wasm, and Web wasm smoke test.

@Catrya
Catrya merged commit ea8dd1e into main Aug 7, 2026
4 checks passed
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.

Auto-navigate to add-invoice / pay-invoice screens when the daemon requests action

1 participant