diff --git a/app/src/main/java/to/bitkit/services/LightningService.kt b/app/src/main/java/to/bitkit/services/LightningService.kt index 0c5bd44c0..479534c32 100644 --- a/app/src/main/java/to/bitkit/services/LightningService.kt +++ b/app/src/main/java/to/bitkit/services/LightningService.kt @@ -311,10 +311,10 @@ class LightningService @Inject constructor( return ServiceQueue.LDK.background { if (sat != null) { Logger.debug("Creating bolt11 for $sat sats") - node.bolt11Payment().receive(sat.millis, description, expirySecs) + node.bolt11Payment().receive(sat.millis, description.ifBlank { "Bitkit" }, expirySecs) } else { Logger.debug("Creating bolt11 for variable amount") - node.bolt11Payment().receiveVariableAmount(description, expirySecs) + node.bolt11Payment().receiveVariableAmount(description.ifBlank { "Bitkit" }, expirySecs) } } } 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 af8883386..679ad84ac 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 @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults @@ -395,7 +396,14 @@ private fun CopyAddressCard( .fillMaxWidth() .padding(24.dp) ) { - Caption13Up(text = title, color = Colors.White64) + Row { + Caption13Up(text = title, color = Colors.White64) + + Spacer(modifier = Modifier.width(3.dp)) + + val iconRes = if (type == CopyAddressType.ONCHAIN) R.drawable.ic_bitcoin else R.drawable.ic_lightning_alt + Icon(painter = painterResource(iconRes), contentDescription = null, tint = Colors.White64) + } Spacer(modifier = Modifier.height(16.dp)) BodyS(text = address.truncate(32).uppercase()) Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/to/bitkit/utils/Bip21Utils.kt b/app/src/main/java/to/bitkit/utils/Bip21Utils.kt index 06fb2cdeb..0aa0370ac 100644 --- a/app/src/main/java/to/bitkit/utils/Bip21Utils.kt +++ b/app/src/main/java/to/bitkit/utils/Bip21Utils.kt @@ -6,7 +6,7 @@ object Bip21Utils { bitcoinAddress: String, amountSats: ULong? = null, label: String? = null, - message: String? = null, + message: String? = "Bitkit", lightningInvoice: String? = null ): String { val builder = StringBuilder("bitcoin:$bitcoinAddress") diff --git a/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt b/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt index 4fbeebdee..e1a23971b 100644 --- a/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt +++ b/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt @@ -278,7 +278,7 @@ class WalletViewModel @Inject constructor( } } - updateBip21Invoice(description = "Bitkit") + updateBip21Invoice() } fun disconnectPeer(peer: LnPeer) { @@ -307,7 +307,7 @@ class WalletViewModel @Inject constructor( fun updateBip21Invoice( amountSats: ULong? = null, - description: String + description: String = "" ) { viewModelScope.launch(Dispatchers.IO) { val hasChannels = lightningService.channels.hasChannels() @@ -321,7 +321,7 @@ class WalletViewModel @Inject constructor( val newBip21 = Bip21Utils.buildBip21Url( bitcoinAddress = _onchainAddress, amountSats = amountSats, - message = description.ifBlank { "Bitkit" }, + message = description.ifBlank { DEFAULT_INVOICE_MESSAGE }, lightningInvoice = _bolt11 ) _bip21 = newBip21 @@ -336,7 +336,7 @@ class WalletViewModel @Inject constructor( description: String, expirySeconds: UInt = 86_400u, // 1 day ): String { - return lightningService.receive(amountSats, description, expirySeconds) + return lightningService.receive(amountSats, description.ifBlank { DEFAULT_INVOICE_MESSAGE }, expirySeconds) } fun openChannel() { @@ -517,6 +517,10 @@ class WalletViewModel @Inject constructor( } private fun List?.hasChannels() = this?.isNotEmpty() == true + + private companion object { + const val DEFAULT_INVOICE_MESSAGE = "Bitkit" + } } // region state diff --git a/app/src/main/res/drawable/ic_bitcoin.xml b/app/src/main/res/drawable/ic_bitcoin.xml new file mode 100644 index 000000000..ded7b3642 --- /dev/null +++ b/app/src/main/res/drawable/ic_bitcoin.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_lightning_alt.xml b/app/src/main/res/drawable/ic_lightning_alt.xml new file mode 100644 index 000000000..0ab6f0338 --- /dev/null +++ b/app/src/main/res/drawable/ic_lightning_alt.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/test/java/to/bitkit/utils/Bip21UrlBuilderTest.kt b/app/src/test/java/to/bitkit/utils/Bip21UrlBuilderTest.kt index 2e136f0c0..54ea1ab3a 100644 --- a/app/src/test/java/to/bitkit/utils/Bip21UrlBuilderTest.kt +++ b/app/src/test/java/to/bitkit/utils/Bip21UrlBuilderTest.kt @@ -18,7 +18,7 @@ class Bip21UrlBuilderTest { @Test fun `basic address without parameters`() { val address = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" - val expected = "bitcoin:$address" + val expected = "bitcoin:$address?message=Bitkit" Assert.assertEquals(expected, buildBip21Url(address)) } @@ -26,7 +26,7 @@ class Bip21UrlBuilderTest { fun `address with amount in sats`() { val address = "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa" val amount = 100000uL // 0.001 BTC - val expected = "bitcoin:$address?amount=0.001" + val expected = "bitcoin:$address?amount=0.001&message=Bitkit" Assert.assertEquals(expected, buildBip21Url(address, amount)) } @@ -34,7 +34,7 @@ class Bip21UrlBuilderTest { fun `amount with exact 1 BTC`() { val address = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" val amount = 100000000uL - val expected = "bitcoin:$address?amount=1" + val expected = "bitcoin:$address?amount=1&message=Bitkit" Assert.assertEquals(expected, buildBip21Url(address, amount)) } @@ -42,7 +42,7 @@ class Bip21UrlBuilderTest { fun `amount with fractional sats rounds correctly`() { val address = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" val amount = 12345678uL - val expected = "bitcoin:$address?amount=0.12345678" + val expected = "bitcoin:$address?amount=0.12345678&message=Bitkit" Assert.assertEquals(expected, buildBip21Url(address, amount)) } @@ -64,7 +64,7 @@ class Bip21UrlBuilderTest { fun `address with lightning parameter`() { val address = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" val invoice = "lnbc500n1p3k9v3pp5kzmj..." - val expected = "bitcoin:$address?lightning=${invoice.encodeToUrl()}" + val expected = "bitcoin:$address?message=Bitkit&lightning=${invoice.encodeToUrl()}" Assert.assertEquals(expected, buildBip21Url(address, lightningInvoice = invoice)) } @@ -105,7 +105,7 @@ class Bip21UrlBuilderTest { fun `zero sats is handled correctly`() { val address = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" val amount = 0uL - val expected = "bitcoin:$address?amount=0" + val expected = "bitcoin:$address?amount=0&message=Bitkit" Assert.assertEquals(expected, buildBip21Url(address, amount)) } @@ -113,7 +113,7 @@ class Bip21UrlBuilderTest { fun `maximum ULong value is handled correctly`() { val address = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" val amount = ULong.MAX_VALUE - val expected = "bitcoin:$address?amount=184467440737.09551615" + val expected = "bitcoin:$address?amount=184467440737.09551615&message=Bitkit" Assert.assertEquals(expected, buildBip21Url(address, amount)) } @@ -121,7 +121,7 @@ class Bip21UrlBuilderTest { fun `lightning parameter without other parameters`() { val address = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" val invoice = "lnbc100n1p3k9v3pp5kzmj..." - val expected = "bitcoin:$address?lightning=${invoice.encodeToUrl()}" + val expected = "bitcoin:$address?message=Bitkit&lightning=${invoice.encodeToUrl()}" Assert.assertEquals(expected, buildBip21Url(address, lightningInvoice = invoice)) } @@ -130,7 +130,7 @@ class Bip21UrlBuilderTest { val address = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" val amount = 10000uL val invoice = "lnbc100n1p3k9v3pp5kzmj..." - val expected = "bitcoin:$address?amount=0.0001&lightning=${invoice.encodeToUrl()}" + val expected = "bitcoin:$address?amount=0.0001&message=Bitkit&lightning=${invoice.encodeToUrl()}" Assert.assertEquals(expected, buildBip21Url(address, amount, lightningInvoice = invoice)) } }