diff --git a/app/src/main/java/com/bitcointxoko/gudariwallet/api/Models.kt b/app/src/main/java/com/bitcointxoko/gudariwallet/api/Models.kt index 09451b0..58d3d90 100644 --- a/app/src/main/java/com/bitcointxoko/gudariwallet/api/Models.kt +++ b/app/src/main/java/com/bitcointxoko/gudariwallet/api/Models.kt @@ -175,6 +175,32 @@ data class PaymentRecord( val amountSat: Long get() = kotlin.math.abs(amountMsat) / 1000L val feeSat: Long get() = kotlin.math.abs(feeMsat) / 1000L val isOutgoing: Boolean get() = amountMsat < 0 + + companion object { + fun fromPayment( + paymentHash : String, + amountSats : Long, + feeSats : Long?, + bolt11 : String?, + memo : String?, + pubkey : String?, + alias : String?, + ): PaymentRecord = PaymentRecord( + paymentHash = paymentHash, + checkingId = paymentHash, + amountMsat = -(amountSats * 1_000L), + feeMsat = (feeSats ?: 0L) * 1_000L, + memo = memo, + time = (System.currentTimeMillis() / 1_000L).toString(), + status = "complete", + bolt11 = bolt11, + pending = false, + preimage = null, + extra = null, + pubkey = pubkey, + alias = alias, + ) + } } data class PaymentExtra( diff --git a/app/src/main/java/com/bitcointxoko/gudariwallet/ui/send/SendViewModel.kt b/app/src/main/java/com/bitcointxoko/gudariwallet/ui/send/SendViewModel.kt index 985b655..1b8159f 100644 --- a/app/src/main/java/com/bitcointxoko/gudariwallet/ui/send/SendViewModel.kt +++ b/app/src/main/java/com/bitcointxoko/gudariwallet/ui/send/SendViewModel.kt @@ -13,6 +13,7 @@ import com.bitcointxoko.gudariwallet.data.WalletRepository import com.bitcointxoko.gudariwallet.ui.SendState import com.bitcointxoko.gudariwallet.ui.balance.BalanceViewModel import com.bitcointxoko.gudariwallet.util.BiometricHelper +import com.bitcointxoko.gudariwallet.util.Bip21Parser import com.bitcointxoko.gudariwallet.util.LnurlMetadataParser import com.bitcointxoko.gudariwallet.util.RouteHintAnalyzer import com.bitcointxoko.gudariwallet.util.SendInputDetector @@ -163,7 +164,7 @@ class SendViewModel( amountSats = amountSats, feeSats = feeSats, paymentHash = paymentHash, - pendingRecord = buildPendingRecord(paymentHash, amountSats, feeSats, bolt11, memo, pubkey, alias) + pendingRecord = PaymentRecord.fromPayment(paymentHash, amountSats, feeSats, bolt11, memo, pubkey, alias) ) balanceVm.refreshBalance() } @@ -333,7 +334,7 @@ class SendViewModel( // ── Scan handlers ──────────────────────────────────────────────────────── private fun handleBip21Scan(rawInput: String, strings: SendStrings) { - val params = parseBip21Params(rawInput) + val params = Bip21Parser.parseParams(rawInput) val bolt11 = params["lightning"] val lnurl = params["lnurl"] ?: params["lnurlp"] when { @@ -520,42 +521,4 @@ class SendViewModel( } } } - - private fun parseBip21Params(raw: String): Map { - val query = raw.trim().substringAfter("?", missingDelimiterValue = "") - if (query.isBlank()) return emptyMap() - return query.split("&").mapNotNull { pair -> - val key = pair.substringBefore("=").takeIf { it.isNotBlank() } ?: return@mapNotNull null - val value = runCatching { - java.net.URLDecoder.decode( - pair.substringAfter("=", "").replace("+", " "), "UTF-8" - ) - }.getOrDefault("") - key to value - }.toMap() - } - - private fun buildPendingRecord( - paymentHash : String, - amountSats : Long, - feeSats : Long?, - bolt11 : String?, - memo : String?, - pubkey : String?, - alias : String? - ): PaymentRecord = PaymentRecord( - paymentHash = paymentHash, - checkingId = paymentHash, - amountMsat = -(amountSats * 1_000L), - feeMsat = (feeSats ?: 0L) * 1_000L, - memo = memo, - time = (System.currentTimeMillis() / 1_000L).toString(), - status = "complete", - bolt11 = bolt11, - pending = false, - preimage = null, - extra = null, - pubkey = pubkey, - alias = alias - ) } \ No newline at end of file diff --git a/app/src/main/java/com/bitcointxoko/gudariwallet/util/Bip21Parser.kt b/app/src/main/java/com/bitcointxoko/gudariwallet/util/Bip21Parser.kt new file mode 100644 index 0000000..be325ef --- /dev/null +++ b/app/src/main/java/com/bitcointxoko/gudariwallet/util/Bip21Parser.kt @@ -0,0 +1,24 @@ +package com.bitcointxoko.gudariwallet.util + +import android.net.Uri + +object Bip21Parser { + /** + * Parses the query string from a BIP-21 URI. + * Input can be the full URI ("bitcoin:addr?amount=...") or just the query + * string ("amount=0.001&label=Foo"). Returns an empty map on malformed input. + */ + fun parseParams(raw: String): Map { + val query = if ('?' in raw) raw.substringAfter('?') else raw + if (query.isBlank()) return emptyMap() + + return query.split('&') + .mapNotNull { pair -> + val idx = pair.indexOf('=') + if (idx < 1) null + else pair.substring(0, idx) to + Uri.decode(pair.substring(idx + 1)) + } + .toMap() + } +}