Skip to content

feat: add send payment pending UI#825

Merged
ovitrif merged 37 commits intomasterfrom
feat/send-pending-ui
Mar 9, 2026
Merged

feat: add send payment pending UI#825
ovitrif merged 37 commits intomasterfrom
feat/send-pending-ui

Conversation

@ovitrif
Copy link
Collaborator

@ovitrif ovitrif commented Mar 5, 2026

This PR adds a pending payment UI for Lightning sends that take longer than expected (e.g. hold invoices).

Description

  1. Adds a SendPendingScreen with an hourglass animation, shown when a Lightning payment exceeds the 10-second timeout without resolving
  2. Adds PendingPaymentResolution tracking in LightningRepo so payment success/failure events are routed back to the pending screen
  3. Handles both resolution paths: navigates to success sheet on completion, or error sheet on failure
  4. Handles invoices in background if sheet was dismissed with toast for success or error
  5. Adds a "View Details" button that links to the activity detail once the payment activity is synced
  6. Toasts for the pending payment handled by the sheet only fire when the user has closed the sheet, if pending sheet is visible, rely on sheets UI.
  7. Adds mechanism to ensure older pending payments still show toast on settled/canceled, even if UI shows sheet for new pending payment.

Preview

Recording

  • Note: Video speed is at 1.75x playback speed.
  • Script
    1. Pending UI > Details > List > Settle > Error Toast
    2. Pending UI > Cancel > Error Sheet
    3. Pending UI > Settle > Success Sheet
    4. Pending UI > Details > List > Cancel Toast
Recording Edge Cases
tests_1.75x.mp4
edges_1.75x.mp4

QA Notes

Setup

  1. Startup bitkit-docker: docker compose up -d
  2. Start emulator via Android Studio
  3. Run this first:
    adb reverse tcp:9735 tcp:9735 && \
    adb reverse tcp:3000 tcp:3000 && \
    adb reverse tcp:60001 tcp:60001 && adb reverse --list
  4. Apply local-electrum.patch to connect to local Electrum, then build and run on emulator:
    curl -sL https://gist.githubusercontent.com/ovitrif/ac13a7ba09efd4c12bee0a1b4cc27f4a/raw/local-electrum.patch | git apply
  5. Open a channel, skip first 4 steps

Use ./bitcoin-cli in bitkit-docker for hold invoices ops:

./bitcoin-cli holdinvoice 42 -m 'test' # create
./bitcoin-cli settleinvoice __preimage__ # settle
./bitcoin-cli cancelinvoice __hash__ # cancel

Tests

  • Pending screen should show on hold invoices
  • Payment resolves to success sheet when on sheet
  • Payment resolves to error sheet when on sheet
  • View Details button opens pending activity detail
  • Close button + settle/cancel -> resolves to toast
  • UI should match FIGMA / iOS
  • QuickPay for cancelled/settled pending payment
  • Tests from stacked PR feat: add pending payment notifications #828
    • App in BG + settle/cancel → success/error notification

Edge Cases

No need for reviewer(s) to test edge cases, they're listed here for transparency into what was dev-tested.

  • Back nav from success/error sheet should dismiss it
  • Pending screen visible + settle → no toast, success screen shown
  • Pending screen visible + cancel → no toast, error screen shown
  • Sheet closed + settle → toast shown
  • Sheet closed + cancel → toast shown
  • Multi pending payment resolution
    • Pay hold invoice1 (old) + dismiss sheet
    • Pay hold invoice2 (new) + settle/cancel old invoice while on pending sheet → toast shown
    • Settle/cancel new invoice → no toast, success/error screen shown
  • Scanner (QuickPay on/off), paste, cancel invoice, tap 'Try Again' → Send Recipient shown
  • Paste 0-amount hold invoice via send + cancel + try again → Send Recipient

🤖 Generated with Claude Code

@ovitrif ovitrif self-assigned this Mar 5, 2026
@ovitrif

This comment was marked as resolved.

@claude

This comment has been minimized.

claude[bot]

This comment was marked as outdated.

@ovitrif ovitrif marked this pull request as ready for review March 6, 2026 13:51
@ovitrif ovitrif requested review from jvsena42, piotr-iohk and pwltr March 6, 2026 13:51
@pwltr

This comment was marked as resolved.

@piotr-iohk
Copy link
Collaborator

Note / observation. There is a little discrepancy in behavior between Android and iOS:

In those cases iOS shows both toast and success / error screen:

  • Pending screen visible + settle → no toast, success screen shown
  • Pending screen visible + cancel → no toast, error screen shown

This edge case is not handled in iOS

Multi pending payment resolution

  • Pay hold invoice1 (old) + dismiss sheet
  • Pay hold invoice2 (new) + settle/cancel old invoice while on pending sheet → toast shown [on iOS toast + success screen for old tx is shown and pending screen is dismissed]
  • Settle/cancel new invoice → no toast, success/error screen shown

Probably should be reported in iOS.

@pwltr

This comment was marked as resolved.

@ovitrif

This comment was marked as resolved.

@piotr-iohk

This comment was marked as resolved.

ovitrif and others added 2 commits March 6, 2026 18:18
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ovitrif
Copy link
Collaborator Author

ovitrif commented Mar 6, 2026

@pwltr fixes:

Error Try Again
fixTryAgain.mp4

🆕 Dev tests

New dev tests, also added to PR description.

  • Scanner (QuickPay on/off), paste, cancel invoice, tap 'Try Again' → Send Recipient shown
  • QuickPay for cancelled/settled pending payment
  • Paste 0-amount hold invoice via send + cancel + try again → Send Recipient

@piotr-iohk
Copy link
Collaborator

piotr-iohk commented Mar 9, 2026

I tested the QuickPay flow against an external channel using docker backend and hit inconsistent behavior.

Repro steps

  1. Fund the wallet.

  2. Open an external Lightning channel.

  3. Get the external node URI:

    ./bitcoin-cli getinfo | jq .uris

    Example:

    [
      "027729b90799a8ed1d6f511afd6651378361a5b86e453149cd9e8bb3e92e3659fc@127.0.0.1:9735"
    ]
  4. In the app, go to Settings > Advanced > Lightning Connections > Add Connection > Advanced > Manual Setup.

  5. Paste the node URI and connect.

  6. Open the channel using about 25k sats.

  7. Confirm the channel with:

    ./bitcoin-cli mine 6
  8. Verify the channel works normally:

    • create a hold invoice and send to it
    • create a hold invoice and cancel it

    Both of these worked for me before enabling QuickPay.

  9. Turn on QuickPay.

  10. Create a new hold invoice for a small amount, around 677 sats. > ./bitcoin-cli holdinvoice 677

  11. Paste invoice with QuickPay enabled.

Actual result

  • On the first QuickPay attempt, the app appeared to restart automatically.
  • On the following attempts, the app showed Transaction failed immediately.
  • This happened even though I did not manually cancel the payment using ./bitcoin-cli cancelinvoice....

From the latest logs, it looks like the same invoice may be processed twice in QuickPay: the first send is initiated and the second one fails as a duplicate payment.

logs.zip

Screen.Recording.2026-03-09.at.10.05.59.mov

@ovitrif
Copy link
Collaborator Author

ovitrif commented Mar 9, 2026

I fixed the toast message in this PR but the error sheet message is also misleading, I will remove in next PR, then on this error screen we'll have parity with iOS:

That screen needs work on both platforms. Design has some improvements to status quo but needs to be adjusted somewhat. For LN payments "Transaction" is not accurate, should be "Payment". And we should try to show a user actionable error description as well as we can.

Extracted this to new issue(s) for next milestone:

@jvsena42
Copy link
Member

jvsena42 commented Mar 9, 2026

Starting review

Copy link
Member

@jvsena42 jvsena42 left a comment

Choose a reason for hiding this comment

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

Code looks good overall, will test in #828

feat: add pending payment notifications
@ovitrif
Copy link
Collaborator Author

ovitrif commented Mar 9, 2026

I tested the QuickPay flow against an external channel using docker backend and hit inconsistent behavior.

As discussed and figured out in private, this bug is not in the logic of the new PR.
The issue comes from DB click to paste invoice, and it repros in all the flows where we have an UI button for this.

The root cause is the unresolved issue we have with Material3's buttons not preventing unwanted DB click.

This issue must be fixed, but not in this PR as it's not a regression but rather an unfixed issue in PROD.

Copy link
Member

@jvsena42 jvsena42 left a comment

Choose a reason for hiding this comment

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

Tested:

  • ✅ Success and failure flows
  • ✅ Multiple pending invoices
  • ❌ Background notifications (missing set the brand color)
  • ✅ Quickpay
  • ✅ Finish / reopen app and update payment state

@ovitrif
Copy link
Collaborator Author

ovitrif commented Mar 9, 2026

Tested:

  • ❌ Background notifications (missing set the brand color)

Thanks, fixed in a03b4b0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ovitrif ovitrif enabled auto-merge March 9, 2026 13:01
@ovitrif ovitrif requested a review from jvsena42 March 9, 2026 13:02
@ovitrif ovitrif dismissed jvsena42’s stale review March 9, 2026 13:15

can't re-request properly. GH bug.

@ovitrif ovitrif merged commit a31c67e into master Mar 9, 2026
19 checks passed
@ovitrif ovitrif deleted the feat/send-pending-ui branch March 9, 2026 13:30
@ovitrif ovitrif linked an issue Mar 9, 2026 that may be closed by this pull request
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.

[Feat]: Send: add pending payment UI

4 participants