From 3064b10051239cde7dc79629f6adb225a1b86bba Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 24 Sep 2026 18:49:11 +0200 Subject: [PATCH 1/7] fix: surface payment request details in sheet --- .../screens/wallets/send/SendConfirmScreen.kt | 123 ++++++++++++++++++ .../java/to/bitkit/viewmodels/AppViewModel.kt | 4 + app/src/main/res/values/strings.xml | 1 + .../viewmodels/AppViewModelSendFlowTest.kt | 31 +++++ changelog.d/next/1336.changed.md | 1 + journeys/payment-requests/README.md | 3 + journeys/payment-requests/request-summary.xml | 15 +++ 7 files changed, 178 insertions(+) create mode 100644 changelog.d/next/1336.changed.md create mode 100644 journeys/payment-requests/request-summary.xml diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt index 42f259aa8e..a653b24326 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt @@ -1,5 +1,6 @@ package to.bitkit.ui.screens.wallets.send +import androidx.annotation.DrawableRes import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.tween import androidx.compose.foundation.Image @@ -35,6 +36,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.testTag @@ -69,6 +71,7 @@ import to.bitkit.ui.components.BottomSheetPreview import to.bitkit.ui.components.ButtonSize import to.bitkit.ui.components.Caption13Up import to.bitkit.ui.components.FillHeight +import to.bitkit.ui.components.FillWidth import to.bitkit.ui.components.GradientCircularProgressIndicator import to.bitkit.ui.components.NumberPadActionButton import to.bitkit.ui.components.PrimaryButton @@ -364,6 +367,10 @@ private fun ContentRunning( } } } else { + if (uiState.isPaymentRequest && !uiState.isSubscriptionPayment) { + PaymentRequestSummary(uiState = uiState, iconColor = accentColor) + VerticalSpacer(32.dp) + } Image( painter = painterResource(R.drawable.coin_stack_4), contentDescription = null, @@ -796,6 +803,76 @@ private fun ContactRecipient( } } +@Composable +private fun PaymentRequestSummary( + uiState: SendUiState, + iconColor: Color, + modifier: Modifier = Modifier, +) { + val profile = uiState.contactPaymentProfile ?: return + val note = uiState.paymentRequestNote?.takeIf { it.isNotBlank() } + + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + modifier = modifier.height(IntrinsicSize.Min) + ) { + SendCell( + caption = stringResource(R.string.wallet__send_from), + modifier = Modifier.weight(1f) + ) { + PaymentRequestSummaryValue( + text = profile.name, + icon = R.drawable.ic_user, + iconColor = iconColor, + testTag = "PaymentRequestFrom", + ) + } + if (note != null) { + SendCell( + caption = stringResource(R.string.wallet__payment_request_for), + modifier = Modifier.weight(1f) + ) { + PaymentRequestSummaryValue( + text = note, + icon = R.drawable.ic_note, + iconColor = iconColor, + testTag = "PaymentRequestFor", + ) + } + } else { + FillWidth() + } + } +} + +@Composable +private fun PaymentRequestSummaryValue( + text: String, + @DrawableRes icon: Int, + iconColor: Color, + testTag: String, + modifier: Modifier = Modifier, +) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp), + modifier = modifier + ) { + Icon( + painter = painterResource(icon), + contentDescription = null, + tint = iconColor, + modifier = Modifier.size(16.dp) + ) + BodySSB( + text = text, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.testTag(testTag) + ) + } +} + @Composable private fun LnurlPayDetails( uiState: SendUiState, @@ -1007,6 +1084,52 @@ private fun PreviewLightning() { } } +@Suppress("MagicNumber") +@Preview(showSystemUi = true, group = "payment request") +@Composable +private fun PreviewPaymentRequest() { + AppThemeSurface { + BottomSheetPreview { + SendConfirmContent( + uiState = sendUiState().copy( + amount = 21_000u, + payMethod = SendMethod.LIGHTNING, + isPaymentRequest = true, + contactPaymentProfile = PubkyProfile.placeholder("pk8e3xqyn5ha6swnhwp4bcw4dkj").copy( + name = "Anna Pleb", + ), + paymentRequestNote = "Lunch last week", + ), + isNodeRunning = true, + isLoading = false, + showBiometrics = false, + modifier = Modifier.sheetHeight(), + ) + } + } +} + +@Suppress("MagicNumber") +@Preview(showSystemUi = true, group = "payment request") +@Composable +private fun PreviewPaymentRequestWithoutNote() { + AppThemeSurface { + BottomSheetPreview { + SendConfirmContent( + uiState = sendUiState().copy( + amount = 21_000u, + isPaymentRequest = true, + contactPaymentProfile = PubkyProfile.placeholder("pk8e3xqyn5ha6swnhwp4bcw4dkj"), + ), + isNodeRunning = true, + isLoading = false, + showBiometrics = false, + modifier = Modifier.sheetHeight(), + ) + } + } +} + @Preview(showSystemUi = true) @Composable private fun PreviewLnurl() { diff --git a/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt b/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt index fed62b981f..d7a2adb25f 100644 --- a/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt +++ b/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt @@ -2875,6 +2875,7 @@ class AppViewModel @Inject constructor( resetSendState( contactPaymentProfile = contactPaymentProfile, isPaymentRequest = isPaymentRequest, + paymentRequestNote = incomingPaymentRequest?.note, isSubscriptionPayment = incomingPaymentRequest?.billingPeriod != null, isInitialSubscriptionPayment = synchronized(contactPaymentContextLock) { activeContactPaymentContext?.isInitialSubscriptionPayment == true @@ -4631,6 +4632,7 @@ class AppViewModel @Inject constructor( suspend fun resetSendState( contactPaymentProfile: PubkyProfile? = null, isPaymentRequest: Boolean = false, + paymentRequestNote: String? = null, hardwareWalletId: String? = activeHardwareWalletId, isSubscriptionPayment: Boolean = false, isInitialSubscriptionPayment: Boolean = false, @@ -4652,6 +4654,7 @@ class AppViewModel @Inject constructor( onchainFeeUi = OnchainFeeUi(rate = FeeRate.fromSpeed(speed)), contactPaymentProfile = contactPaymentProfile, isPaymentRequest = isPaymentRequest, + paymentRequestNote = paymentRequestNote, hardwareWalletId = hardwareWalletId, hardwareWalletName = hardwareWalletId?.let { walletId -> hwWalletRepo.wallets.value.find { it.id == walletId }?.name @@ -5817,6 +5820,7 @@ data class SendUiState( val lastLightningFee: Long = 0L, val contactPaymentProfile: PubkyProfile? = null, val isPaymentRequest: Boolean = false, + val paymentRequestNote: String? = null, val hardwareWalletId: String? = null, val hardwareWalletName: String? = null, val hardwareAvailableSats: ULong = 0uL, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4c570f91c9..042cc64d53 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1323,6 +1323,7 @@ 1 hour 1 month 1 week + For The payment details did not match the request. Payment cancelled. Note What is this payment for? diff --git a/app/src/test/java/to/bitkit/viewmodels/AppViewModelSendFlowTest.kt b/app/src/test/java/to/bitkit/viewmodels/AppViewModelSendFlowTest.kt index 5a2e521729..562ebf4ac2 100644 --- a/app/src/test/java/to/bitkit/viewmodels/AppViewModelSendFlowTest.kt +++ b/app/src/test/java/to/bitkit/viewmodels/AppViewModelSendFlowTest.kt @@ -869,6 +869,37 @@ class AppViewModelSendFlowTest : BaseUnitTest() { assertEquals(Sheet.Send(SendRoute.Confirm), sut.currentSheet.value) } + @Test + fun `opened request passes its note to the confirm sheet`() = test { + sut.setIsAuthenticated(true) + val request = paymentRequest().copy(note = "Lunch last week") + val bolt11 = "lnbcrt1requestwithnote" + whenever(privatePaykitRepo.beginPaymentRequest(request)).thenReturn( + Result.success( + PublicPaykitPaymentResult.Opened( + paymentRequest = bolt11, + privatePaymentContext = PrivatePaykitPaymentContext("bitkit/server", 8uL), + ), + ), + ) + stubLightningScan(bolt11 = bolt11, amountSats = 0u) + balanceState.value = BalanceState(maxSendLightningSats = 100_000u) + pendingPaykitPaymentRequests.value = listOf(request) + surfacedPaykitPaymentRequestIds += request.id + enablePaykitUi() + pubkyPublicKey.value = testPublicKey + runCurrent() + + sut.showPaymentRequests() + sut.openIncomingPaymentRequest(request.id) + advanceTimeBy(TRANSITION_SCREEN_MS) + runCurrent() + + assertEquals(Sheet.Send(SendRoute.Confirm), sut.currentSheet.value) + assertTrue(sut.sendUiState.value.isPaymentRequest) + assertEquals("Lunch last week", sut.sendUiState.value.paymentRequestNote) + } + @Test fun `manually reopened request preserves tags while waiting for a newer private list`() = test { sut.setIsAuthenticated(true) diff --git a/changelog.d/next/1336.changed.md b/changelog.d/next/1336.changed.md new file mode 100644 index 0000000000..e6bfef0a60 --- /dev/null +++ b/changelog.d/next/1336.changed.md @@ -0,0 +1 @@ +Incoming Payment Requests now show who the request is from and what it is for under the amount. diff --git a/journeys/payment-requests/README.md b/journeys/payment-requests/README.md index 750a7132a0..a7868c620a 100644 --- a/journeys/payment-requests/README.md +++ b/journeys/payment-requests/README.md @@ -18,6 +18,8 @@ The accepted journey uses: Rejected fixture shapes stay in unit tests because Bitkit intentionally does not present requests that fail the contract gate. +`request-summary.xml` uses a second Bitkit instance as the requester instead of the fixture issuer: both instances are authenticated Pubky identities, saved as each other's contacts and linked on receiver path `bitkit/wallet`, and the payer holds enough balance to pay 21,000 sats. + ## Reference evidence The source wallet-leg run completed this path on regtest on 2026-08-22: Bitkit presented the incoming request, opened the on-chain payment, broadcast it, and confirmed transaction @@ -33,6 +35,7 @@ That run established the issuer shapes captured by the fixture: lowercase `btc`, - Pay action: `PaymentRequestPay-` - Dismiss action: `PaymentRequestDismiss-` - Payment confirmation: `PaymentRequestConfirm` +- Confirmation summary: `PaymentRequestFrom`, `PaymentRequestFor` - Confirmation details: `SendConfirmToggleDetails` - Saved-contact recipient: `ReviewContactRecipient` diff --git a/journeys/payment-requests/request-summary.xml b/journeys/payment-requests/request-summary.xml new file mode 100644 index 0000000000..96c56a6ee7 --- /dev/null +++ b/journeys/payment-requests/request-summary.xml @@ -0,0 +1,15 @@ + + + Verifies that the collapsed Payment Request confirmation shows who the request is from and what it is for, without opening the details. Requires two Bitkit instances saved as each other's contacts and linked on receiver path "bitkit/wallet", with the payer funded to cover 21,000 sats; see README.md. + + + On the requester, open Payment Requests and tap Create (testTag "PaymentRequestCreate") + Enter 21,000 sats and continue (testTag "PaymentRequestAmountContinue") + Enter the note "Lunch last week" (testTag "PaymentRequestNote"), choose the payer contact and send the request (testTag "PaymentRequestSend") + On the payer, verify the Payment Request confirmation screen (testTag "PaymentRequestConfirm") appears with 21,000 sats + Verify From (testTag "PaymentRequestFrom") shows the requester's contact name + Verify For (testTag "PaymentRequestFor") shows "Lunch last week" + Tap Show details (testTag "SendConfirmToggleDetails") + Verify From (testTag "PaymentRequestFrom") and For (testTag "PaymentRequestFor") are no longer shown, and the recipient (testTag "ReviewContactRecipient") is the requester's contact + + From 0274b0e5902697bbe425dd591ba3f7979f7e1730 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 24 Sep 2026 18:51:33 +0200 Subject: [PATCH 2/7] fix: trim payment request note --- .../to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt | 2 +- journeys/payment-requests/request-summary.xml | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt index a653b24326..96e7a12ba3 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt @@ -810,7 +810,7 @@ private fun PaymentRequestSummary( modifier: Modifier = Modifier, ) { val profile = uiState.contactPaymentProfile ?: return - val note = uiState.paymentRequestNote?.takeIf { it.isNotBlank() } + val note = uiState.paymentRequestNote?.trim()?.takeIf { it.isNotEmpty() } Row( horizontalArrangement = Arrangement.spacedBy(16.dp), diff --git a/journeys/payment-requests/request-summary.xml b/journeys/payment-requests/request-summary.xml index 96c56a6ee7..db9aa8fc02 100644 --- a/journeys/payment-requests/request-summary.xml +++ b/journeys/payment-requests/request-summary.xml @@ -3,9 +3,7 @@ Verifies that the collapsed Payment Request confirmation shows who the request is from and what it is for, without opening the details. Requires two Bitkit instances saved as each other's contacts and linked on receiver path "bitkit/wallet", with the payer funded to cover 21,000 sats; see README.md. - On the requester, open Payment Requests and tap Create (testTag "PaymentRequestCreate") - Enter 21,000 sats and continue (testTag "PaymentRequestAmountContinue") - Enter the note "Lunch last week" (testTag "PaymentRequestNote"), choose the payer contact and send the request (testTag "PaymentRequestSend") + On the requester, send the payer contact a Payment Request for 21,000 sats with the note "Lunch last week" On the payer, verify the Payment Request confirmation screen (testTag "PaymentRequestConfirm") appears with 21,000 sats Verify From (testTag "PaymentRequestFrom") shows the requester's contact name Verify For (testTag "PaymentRequestFor") shows "Lunch last week" From b8c5773bd5c764732c46a63b372225c9cd6c1118 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 24 Sep 2026 19:23:05 +0200 Subject: [PATCH 3/7] test: cover a payment request without a note --- journeys/payment-requests/request-summary.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/journeys/payment-requests/request-summary.xml b/journeys/payment-requests/request-summary.xml index db9aa8fc02..c4bd618108 100644 --- a/journeys/payment-requests/request-summary.xml +++ b/journeys/payment-requests/request-summary.xml @@ -1,6 +1,6 @@ - Verifies that the collapsed Payment Request confirmation shows who the request is from and what it is for, without opening the details. Requires two Bitkit instances saved as each other's contacts and linked on receiver path "bitkit/wallet", with the payer funded to cover 21,000 sats; see README.md. + Verifies that the collapsed Payment Request confirmation shows who the request is from and what it is for, without opening the details, and leaves For out when the request has no note. Requires two Bitkit instances saved as each other's contacts and linked on receiver path "bitkit/wallet", with the payer funded to cover 21,000 sats; see README.md. On the requester, send the payer contact a Payment Request for 21,000 sats with the note "Lunch last week" @@ -9,5 +9,9 @@ Verify For (testTag "PaymentRequestFor") shows "Lunch last week" Tap Show details (testTag "SendConfirmToggleDetails") Verify From (testTag "PaymentRequestFrom") and For (testTag "PaymentRequestFor") are no longer shown, and the recipient (testTag "ReviewContactRecipient") is the requester's contact + Close the Payment Request confirmation screen without paying + On the requester, send the payer contact a Payment Request for 5,000 sats with no note + On the payer, verify the Payment Request confirmation screen (testTag "PaymentRequestConfirm") shows 5,000 sats, opening it from the pending Payment Requests bell (testTag "PaymentRequestsBell") if it does not open by itself + Verify From (testTag "PaymentRequestFrom") shows the requester's contact name and For (testTag "PaymentRequestFor") is not shown From d096500d37c239b3d7a3151d338dfb0cfb4c1329 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 24 Sep 2026 21:02:10 +0200 Subject: [PATCH 4/7] fix: show payment request note in details --- .../screens/wallets/send/SendConfirmScreen.kt | 92 +++++++++++++++++-- journeys/payment-requests/README.md | 1 + journeys/payment-requests/request-summary.xml | 5 +- 3 files changed, 89 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt index 96e7a12ba3..32e1d45e56 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt @@ -4,6 +4,7 @@ import androidx.annotation.DrawableRes import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.tween import androidx.compose.foundation.Image +import androidx.compose.foundation.background import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -81,7 +82,9 @@ import to.bitkit.ui.components.SwipeToConfirm import to.bitkit.ui.components.SyncNodeView import to.bitkit.ui.components.TagButton import to.bitkit.ui.components.TextInput +import to.bitkit.ui.components.Title import to.bitkit.ui.components.VerticalSpacer +import to.bitkit.ui.components.ZigzagDivider import to.bitkit.ui.components.rememberMoneyText import to.bitkit.ui.scaffold.AppAlertDialog import to.bitkit.ui.settingsViewModel @@ -341,7 +344,7 @@ private fun ContentRunning( .testTag("ReviewAmount") ) - VerticalSpacer(44.dp) + VerticalSpacer(if (uiState.isOneOffPaymentRequest && !isLnurlPay) 24.dp else 44.dp) if (isLnurlPay) { LnurlPayDetails(uiState = uiState, onEvent = onEvent) @@ -355,6 +358,10 @@ private fun ContentRunning( ) VerticalSpacer(16.dp) TagsSection(uiState, onClickTag, onClickAddTag) + uiState.oneOffPaymentRequestNote?.let { + VerticalSpacer(16.dp) + PaymentRequestInvoiceNote(note = it) + } } SendMethod.LIGHTNING -> { @@ -367,9 +374,9 @@ private fun ContentRunning( } } } else { - if (uiState.isPaymentRequest && !uiState.isSubscriptionPayment) { + if (uiState.isOneOffPaymentRequest) { PaymentRequestSummary(uiState = uiState, iconColor = accentColor) - VerticalSpacer(32.dp) + VerticalSpacer(16.dp) } Image( painter = painterResource(R.drawable.coin_stack_4), @@ -530,7 +537,13 @@ private fun OnChainDetails( ) } SendCell( - caption = stringResource(R.string.wallet__send_to), + caption = stringResource( + if (uiState.isOneOffPaymentRequest) { + R.string.wallet__payment_request_contact + } else { + R.string.wallet__send_to + } + ), modifier = Modifier.weight(1f) ) { if (uiState.contactPaymentProfile != null) { @@ -668,7 +681,13 @@ private fun LightningDetails( ) } SendCell( - caption = stringResource(R.string.wallet__send_to), + caption = stringResource( + if (uiState.isOneOffPaymentRequest) { + R.string.wallet__payment_request_contact + } else { + R.string.wallet__send_to + } + ), modifier = Modifier.weight(1f) ) { if (uiState.contactPaymentProfile != null) { @@ -764,7 +783,7 @@ private fun LightningDetails( } } - if (!isLnurlPay && !description.isNullOrEmpty()) { + if (!isLnurlPay && !description.isNullOrEmpty() && uiState.oneOffPaymentRequestNote == null) { SendCell(caption = stringResource(R.string.wallet__note)) { Row(modifier = Modifier.horizontalScroll(rememberScrollState())) { BodySSB(text = description, maxLines = 1) @@ -779,6 +798,10 @@ private fun LightningDetails( onClickAddTag = onClickAddTag, ) } + + uiState.oneOffPaymentRequestNote?.let { + PaymentRequestInvoiceNote(note = it) + } } } @@ -810,7 +833,7 @@ private fun PaymentRequestSummary( modifier: Modifier = Modifier, ) { val profile = uiState.contactPaymentProfile ?: return - val note = uiState.paymentRequestNote?.trim()?.takeIf { it.isNotEmpty() } + val note = uiState.oneOffPaymentRequestNote Row( horizontalArrangement = Arrangement.spacedBy(16.dp), @@ -873,6 +896,33 @@ private fun PaymentRequestSummaryValue( } } +@Composable +private fun PaymentRequestInvoiceNote( + note: String, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier.fillMaxWidth()) { + Caption13Up(text = stringResource(R.string.wallet__activity_invoice_note), color = Colors.White64) + VerticalSpacer(8.dp) + ZigzagDivider() + Title( + text = note, + color = Colors.White, + modifier = Modifier + .fillMaxWidth() + .background(Colors.White10) + .padding(24.dp) + .testTag("PaymentRequestInvoiceNote") + ) + } +} + +private val SendUiState.isOneOffPaymentRequest: Boolean + get() = isPaymentRequest && !isSubscriptionPayment + +private val SendUiState.oneOffPaymentRequestNote: String? + get() = paymentRequestNote?.trim()?.takeIf { isOneOffPaymentRequest && it.isNotEmpty() } + @Composable private fun LnurlPayDetails( uiState: SendUiState, @@ -1109,6 +1159,34 @@ private fun PreviewPaymentRequest() { } } +@Suppress("MagicNumber") +@Preview(showSystemUi = true, group = "payment request") +@Composable +private fun PreviewPaymentRequestDetails() { + AppThemeSurface { + BottomSheetPreview { + SendConfirmContent( + uiState = sendUiState().copy( + amount = 21_000u, + payMethod = SendMethod.LIGHTNING, + lightningFeeSats = 1, + isPaymentRequest = true, + contactPaymentProfile = PubkyProfile.placeholder("pk8e3xqyn5ha6swnhwp4bcw4dkj").copy( + name = "Areem Holden", + ), + paymentRequestNote = "Lunch last week", + selectedTags = persistentListOf("Lunch"), + ), + isNodeRunning = true, + isLoading = false, + showBiometrics = false, + initialShowDetails = true, + modifier = Modifier.sheetHeight(), + ) + } + } +} + @Suppress("MagicNumber") @Preview(showSystemUi = true, group = "payment request") @Composable diff --git a/journeys/payment-requests/README.md b/journeys/payment-requests/README.md index a7868c620a..a4f2c609b4 100644 --- a/journeys/payment-requests/README.md +++ b/journeys/payment-requests/README.md @@ -36,6 +36,7 @@ That run established the issuer shapes captured by the fixture: lowercase `btc`, - Dismiss action: `PaymentRequestDismiss-` - Payment confirmation: `PaymentRequestConfirm` - Confirmation summary: `PaymentRequestFrom`, `PaymentRequestFor` +- Confirmation invoice note: `PaymentRequestInvoiceNote` - Confirmation details: `SendConfirmToggleDetails` - Saved-contact recipient: `ReviewContactRecipient` diff --git a/journeys/payment-requests/request-summary.xml b/journeys/payment-requests/request-summary.xml index c4bd618108..fe8098e8d6 100644 --- a/journeys/payment-requests/request-summary.xml +++ b/journeys/payment-requests/request-summary.xml @@ -1,6 +1,6 @@ - Verifies that the collapsed Payment Request confirmation shows who the request is from and what it is for, without opening the details, and leaves For out when the request has no note. Requires two Bitkit instances saved as each other's contacts and linked on receiver path "bitkit/wallet", with the payer funded to cover 21,000 sats; see README.md. + Verifies that the collapsed Payment Request confirmation shows who the request is from and what it is for, keeps the note in the details, and leaves For out when the request has no note. Requires two Bitkit instances saved as each other's contacts and linked on receiver path "bitkit/wallet", with the payer funded to cover 21,000 sats; see README.md. On the requester, send the payer contact a Payment Request for 21,000 sats with the note "Lunch last week" @@ -8,7 +8,8 @@ Verify From (testTag "PaymentRequestFrom") shows the requester's contact name Verify For (testTag "PaymentRequestFor") shows "Lunch last week" Tap Show details (testTag "SendConfirmToggleDetails") - Verify From (testTag "PaymentRequestFrom") and For (testTag "PaymentRequestFor") are no longer shown, and the recipient (testTag "ReviewContactRecipient") is the requester's contact + Verify From (testTag "PaymentRequestFrom") and For (testTag "PaymentRequestFor") are no longer shown, and the recipient (testTag "ReviewContactRecipient") under Contact is the requester's contact + Verify the invoice note (testTag "PaymentRequestInvoiceNote") shows "Lunch last week" Close the Payment Request confirmation screen without paying On the requester, send the payer contact a Payment Request for 5,000 sats with no note On the payer, verify the Payment Request confirmation screen (testTag "PaymentRequestConfirm") shows 5,000 sats, opening it from the pending Payment Requests bell (testTag "PaymentRequestsBell") if it does not open by itself From 2f74260aa613428164f6dcd5d6407c3aa8a206c7 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 24 Sep 2026 23:06:11 +0200 Subject: [PATCH 5/7] fix: keep invoice description beside request note --- .../java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt index 32e1d45e56..bfdb65894d 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/send/SendConfirmScreen.kt @@ -783,7 +783,7 @@ private fun LightningDetails( } } - if (!isLnurlPay && !description.isNullOrEmpty() && uiState.oneOffPaymentRequestNote == null) { + if (!isLnurlPay && !description.isNullOrEmpty() && description.trim() != uiState.oneOffPaymentRequestNote) { SendCell(caption = stringResource(R.string.wallet__note)) { Row(modifier = Modifier.horizontalScroll(rememberScrollState())) { BodySSB(text = description, maxLines = 1) From 5fef1f267ed32bac511ecb2e5fdb9e69083d1a4a Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Fri, 25 Sep 2026 14:32:42 +0200 Subject: [PATCH 6/7] chore: describe payment request details in changelog --- changelog.d/next/1336.changed.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/next/1336.changed.md b/changelog.d/next/1336.changed.md index e6bfef0a60..903a133395 100644 --- a/changelog.d/next/1336.changed.md +++ b/changelog.d/next/1336.changed.md @@ -1 +1 @@ -Incoming Payment Requests now show who the request is from and what it is for under the amount. +Incoming Payment Requests now show who the request is from and what it is for under the amount, and keep the request note in the payment details. From 4b5e73f00c132ab89edbc05b701cbb3a9a1143e2 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Fri, 25 Sep 2026 15:24:24 +0200 Subject: [PATCH 7/7] chore: restore the payment request changelog entry --- changelog.d/next/1336.changed.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/next/1336.changed.md b/changelog.d/next/1336.changed.md index 903a133395..e6bfef0a60 100644 --- a/changelog.d/next/1336.changed.md +++ b/changelog.d/next/1336.changed.md @@ -1 +1 @@ -Incoming Payment Requests now show who the request is from and what it is for under the amount, and keep the request note in the payment details. +Incoming Payment Requests now show who the request is from and what it is for under the amount.