From 4bd2bfb80d6f1ef7cdb0ae9d269d33d9c7ecca1e Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Thu, 16 Jul 2026 12:58:55 -0300 Subject: [PATCH 1/5] fix: remove details button guard for running node --- .../wallets/receive/ReceiveQrScreen.kt | 109 +++++++++--------- changelog.d/next/1084.fixed.md | 1 + 2 files changed, 54 insertions(+), 56 deletions(-) create mode 100644 changelog.d/next/1084.fixed.md diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt index 6d660fea09..ecf3b4f381 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt @@ -1,7 +1,6 @@ package to.bitkit.ui.screens.wallets.receive import android.graphics.Bitmap -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.Crossfade import androidx.compose.foundation.background import androidx.compose.foundation.gestures.snapping.SnapPosition @@ -288,63 +287,61 @@ fun ReceiveQrScreen( VerticalSpacer(24.dp) - AnimatedVisibility(visible = lightningState.nodeLifecycleState.isRunning()) { - val showCjitButton = showingCjitOnboarding && selectedTab == ReceiveTab.SPENDING - val buttonVariant = when { - showCjitButton -> BottomButtonVariant.CJIT - showDetails -> BottomButtonVariant.SHOW_QR - else -> BottomButtonVariant.SHOW_DETAILS - } - Crossfade( - targetState = buttonVariant, - label = "ReceiveBottomButtonCrossfade", - ) { variant -> - when (variant) { - BottomButtonVariant.CJIT -> PrimaryButton( - text = stringResource(R.string.wallet__receive__cjit), - icon = { - Icon( - painter = painterResource(R.drawable.ic_lightning_alt), - tint = Colors.Purple, - contentDescription = null, - ) - }, - onClick = { - onClickReceiveCjit() - showDetails = false - }, - fullWidth = true, - modifier = Modifier - .padding(horizontal = 16.dp) - .testTag("ShowDetails") - ) + val showCjitButton = showingCjitOnboarding && selectedTab == ReceiveTab.SPENDING + val buttonVariant = when { + showCjitButton -> BottomButtonVariant.CJIT + showDetails -> BottomButtonVariant.SHOW_QR + else -> BottomButtonVariant.SHOW_DETAILS + } + Crossfade( + targetState = buttonVariant, + label = "ReceiveBottomButtonCrossfade", + ) { variant -> + when (variant) { + BottomButtonVariant.CJIT -> PrimaryButton( + text = stringResource(R.string.wallet__receive__cjit), + icon = { + Icon( + painter = painterResource(R.drawable.ic_lightning_alt), + tint = Colors.Purple, + contentDescription = null, + ) + }, + onClick = { + onClickReceiveCjit() + showDetails = false + }, + fullWidth = true, + modifier = Modifier + .padding(horizontal = 16.dp) + .testTag("ShowDetails") + ) - BottomButtonVariant.SHOW_QR -> PrimaryButton( - text = stringResource(R.string.wallet__receive_show_qr), - icon = { - Icon( - painter = painterResource(R.drawable.ic_qr_purple), - tint = Colors.White, - contentDescription = null, - modifier = Modifier.size(16.dp) - ) - }, - onClick = { showDetails = false }, - fullWidth = true, - modifier = Modifier - .padding(horizontal = 16.dp) - .testTag("QRCode") - ) + BottomButtonVariant.SHOW_QR -> PrimaryButton( + text = stringResource(R.string.wallet__receive_show_qr), + icon = { + Icon( + painter = painterResource(R.drawable.ic_qr_purple), + tint = Colors.White, + contentDescription = null, + modifier = Modifier.size(16.dp) + ) + }, + onClick = { showDetails = false }, + fullWidth = true, + modifier = Modifier + .padding(horizontal = 16.dp) + .testTag("QRCode") + ) - BottomButtonVariant.SHOW_DETAILS -> TertiaryButton( - text = stringResource(R.string.wallet__receive_show_details), - onClick = { showDetails = true }, - fullWidth = true, - modifier = Modifier - .padding(horizontal = 16.dp) - .testTag("ShowDetails") - ) - } + BottomButtonVariant.SHOW_DETAILS -> TertiaryButton( + text = stringResource(R.string.wallet__receive_show_details), + onClick = { showDetails = true }, + fullWidth = true, + modifier = Modifier + .padding(horizontal = 16.dp) + .testTag("ShowDetails") + ) } } diff --git a/changelog.d/next/1084.fixed.md b/changelog.d/next/1084.fixed.md new file mode 100644 index 0000000000..37f2133c38 --- /dev/null +++ b/changelog.d/next/1084.fixed.md @@ -0,0 +1 @@ +The Show Details button on the Receive screen is now available while the Lightning node is still starting up, so you can view and copy your on-chain address right away. From f856c59a011bac79614043f5e6c7d7169836ef51 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Thu, 16 Jul 2026 13:08:09 -0300 Subject: [PATCH 2/5] chore: rename changelog fragment --- changelog.d/next/{1084.fixed.md => 1090.fixed.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/next/{1084.fixed.md => 1090.fixed.md} (100%) diff --git a/changelog.d/next/1084.fixed.md b/changelog.d/next/1090.fixed.md similarity index 100% rename from changelog.d/next/1084.fixed.md rename to changelog.d/next/1090.fixed.md From c0a420a464376c0aabe70ecc1a079f5be4c6613d Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Thu, 16 Jul 2026 13:21:28 -0300 Subject: [PATCH 3/5] fix: show loading spinner on spending details --- .../wallets/receive/ReceiveQrScreen.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt index ecf3b4f381..c80a243188 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt @@ -64,6 +64,7 @@ import to.bitkit.ui.components.BottomSheetPreview import to.bitkit.ui.components.ButtonSize import to.bitkit.ui.components.Caption13Up import to.bitkit.ui.components.Display +import to.bitkit.ui.components.GradientCircularProgressIndicator import to.bitkit.ui.components.PrimaryButton import to.bitkit.ui.components.QrCodeImage import to.bitkit.ui.components.TertiaryButton @@ -251,6 +252,7 @@ fun ReceiveQrScreen( tab = tab, walletState = walletState, cjitInvoice = cjitInvoice, + isNodeRunning = lightningState.nodeLifecycleState.isRunning(), onClickEditInvoice = onClickEditInvoice, modifier = Modifier.weight(1f) ) @@ -499,6 +501,7 @@ private fun ReceiveDetailsView( tab: ReceiveTab, walletState: WalletState, cjitInvoice: String?, + isNodeRunning: Boolean, onClickEditInvoice: () -> Unit, modifier: Modifier = Modifier, ) { @@ -560,6 +563,15 @@ private fun ReceiveDetailsView( onClickEditInvoice = onClickEditInvoice, testTag = "ReceiveLightningAddress", ) + } else if (!isNodeRunning) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxSize() + .testTag("ReceiveLightningLoading") + ) { + GradientCircularProgressIndicator(modifier = Modifier.size(24.dp)) + } } } } @@ -883,6 +895,29 @@ private fun PreviewDetailsMode() { "djjqen0wgsyqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxq" ), cjitInvoice = null, + isNodeRunning = true, + onClickEditInvoice = {}, + modifier = Modifier.weight(1f) + ) + } + } +} + +@Preview(showSystemUi = true, name = "Spending Details Node Not Ready") +@Composable +private fun PreviewDetailsModeSpendingNodeNotReady() { + AppThemeSurface { + Column( + modifier = Modifier + .gradientBackground() + .fillMaxSize() + .padding(16.dp) + ) { + ReceiveDetailsView( + tab = ReceiveTab.SPENDING, + walletState = WalletState(), + cjitInvoice = null, + isNodeRunning = false, onClickEditInvoice = {}, modifier = Modifier.weight(1f) ) From 1396d16093e1188b64c5e6420926394a3512bc82 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Thu, 16 Jul 2026 13:41:38 -0300 Subject: [PATCH 4/5] fix: remove node running gate for display spinner --- .../ui/screens/wallets/receive/ReceiveQrScreen.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt index c80a243188..1fe7c994be 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt @@ -252,7 +252,6 @@ fun ReceiveQrScreen( tab = tab, walletState = walletState, cjitInvoice = cjitInvoice, - isNodeRunning = lightningState.nodeLifecycleState.isRunning(), onClickEditInvoice = onClickEditInvoice, modifier = Modifier.weight(1f) ) @@ -501,7 +500,6 @@ private fun ReceiveDetailsView( tab: ReceiveTab, walletState: WalletState, cjitInvoice: String?, - isNodeRunning: Boolean, onClickEditInvoice: () -> Unit, modifier: Modifier = Modifier, ) { @@ -563,7 +561,7 @@ private fun ReceiveDetailsView( onClickEditInvoice = onClickEditInvoice, testTag = "ReceiveLightningAddress", ) - } else if (!isNodeRunning) { + } else { Box( contentAlignment = Alignment.Center, modifier = Modifier @@ -895,7 +893,6 @@ private fun PreviewDetailsMode() { "djjqen0wgsyqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxq" ), cjitInvoice = null, - isNodeRunning = true, onClickEditInvoice = {}, modifier = Modifier.weight(1f) ) @@ -903,9 +900,9 @@ private fun PreviewDetailsMode() { } } -@Preview(showSystemUi = true, name = "Spending Details Node Not Ready") +@Preview(showSystemUi = true, name = "Spending Details Loading") @Composable -private fun PreviewDetailsModeSpendingNodeNotReady() { +private fun PreviewDetailsModeSpendingLoading() { AppThemeSurface { Column( modifier = Modifier @@ -917,7 +914,6 @@ private fun PreviewDetailsModeSpendingNodeNotReady() { tab = ReceiveTab.SPENDING, walletState = WalletState(), cjitInvoice = null, - isNodeRunning = false, onClickEditInvoice = {}, modifier = Modifier.weight(1f) ) From dc47b98e7242cd7dd95acfe862b3d1fab1ff5b7f Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Thu, 16 Jul 2026 14:20:58 -0300 Subject: [PATCH 5/5] fix: don't display cached invoice when node is down --- .../screens/wallets/receive/ReceiveQrScreen.kt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt index 1fe7c994be..289a6f2587 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt @@ -252,6 +252,7 @@ fun ReceiveQrScreen( tab = tab, walletState = walletState, cjitInvoice = cjitInvoice, + isNodeRunning = lightningState.nodeLifecycleState.isRunning(), onClickEditInvoice = onClickEditInvoice, modifier = Modifier.weight(1f) ) @@ -500,6 +501,7 @@ private fun ReceiveDetailsView( tab: ReceiveTab, walletState: WalletState, cjitInvoice: String?, + isNodeRunning: Boolean, onClickEditInvoice: () -> Unit, modifier: Modifier = Modifier, ) { @@ -553,10 +555,11 @@ private fun ReceiveDetailsView( } ReceiveTab.SPENDING -> { - if (cjitInvoice != null || walletState.bolt11.isNotEmpty()) { + val lightningInvoice = cjitInvoice ?: walletState.bolt11.takeIf { isNodeRunning } + if (!lightningInvoice.isNullOrEmpty()) { CopyAddressCard( title = stringResource(R.string.wallet__receive_lightning_invoice), - address = cjitInvoice ?: walletState.bolt11, + address = lightningInvoice, type = CopyAddressType.LIGHTNING, onClickEditInvoice = onClickEditInvoice, testTag = "ReceiveLightningAddress", @@ -893,6 +896,7 @@ private fun PreviewDetailsMode() { "djjqen0wgsyqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxq" ), cjitInvoice = null, + isNodeRunning = true, onClickEditInvoice = {}, modifier = Modifier.weight(1f) ) @@ -900,6 +904,7 @@ private fun PreviewDetailsMode() { } } +@Suppress("SpellCheckingInspection") @Preview(showSystemUi = true, name = "Spending Details Loading") @Composable private fun PreviewDetailsModeSpendingLoading() { @@ -910,10 +915,15 @@ private fun PreviewDetailsModeSpendingLoading() { .fillMaxSize() .padding(16.dp) ) { + // Cached bolt11 with a node that is not running: the stale invoice is withheld in favor of loading ReceiveDetailsView( tab = ReceiveTab.SPENDING, - walletState = WalletState(), + walletState = WalletState( + bolt11 = "lnbcrt500u1pn7umn7pp5x0s9lt9fwrff6rp70pz3guwnjgw97sjuv79vhx9n2ps8q6tcdehhxapqd9h8vmmfv" + + "djjqen0wgsyqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxq" + ), cjitInvoice = null, + isNodeRunning = false, onClickEditInvoice = {}, modifier = Modifier.weight(1f) )