fix: handle pending payment response from server correctly in ui
This commit is contained in:
@@ -20,6 +20,7 @@ import com.bitcointxoko.gudariwallet.util.SendInputType
|
||||
import com.bitcointxoko.gudariwallet.util.WalletConstants
|
||||
import com.bitcointxoko.gudariwallet.util.lnurlProtocolError
|
||||
import com.bitcointxoko.gudariwallet.util.parseApiError
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -87,26 +88,18 @@ class SendViewModel(
|
||||
val decoded = _sendState.value as? SendState.Bolt11Decoded
|
||||
val amountSats = decoded?.amountSats ?: 0L
|
||||
_sendState.value = SendState.Paying
|
||||
Log.d(TAG, "SEND [PAY BOLT11 START] Sending invoice to server")
|
||||
runCatching { repo.payBolt11(bolt11) }
|
||||
.onSuccess { response ->
|
||||
val feeSats = runCatching {
|
||||
repo.getPaymentDetail(response.paymentHash).details?.feeSat
|
||||
}.getOrNull()
|
||||
_sendState.value = SendState.PaymentSent(
|
||||
amountSats = amountSats,
|
||||
feeSats = feeSats,
|
||||
handlePaymentResult(
|
||||
paymentHash = response.paymentHash,
|
||||
pendingRecord = buildPendingRecord(
|
||||
paymentHash = response.paymentHash,
|
||||
amountSats = amountSats,
|
||||
feeSats = feeSats,
|
||||
amountSats,
|
||||
bolt11 = decoded?.bolt11,
|
||||
memo = decoded?.memo,
|
||||
pubkey = decoded?.payee,
|
||||
alias = decoded?.nodeAlias
|
||||
alias = decoded?.nodeAlias,
|
||||
strings
|
||||
)
|
||||
)
|
||||
balanceVm.refreshBalance()
|
||||
}
|
||||
.onFailure { e ->
|
||||
Log.e(TAG, "SEND [PAY BOLT11 ERROR] ${e.message}")
|
||||
@@ -117,6 +110,97 @@ class SendViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handlePaymentResult(
|
||||
paymentHash : String,
|
||||
amountSats : Long,
|
||||
bolt11 : String?,
|
||||
memo : String?,
|
||||
pubkey : String?,
|
||||
alias : String?,
|
||||
strings : SendStrings,
|
||||
) {
|
||||
val detail = runCatching {
|
||||
repo.getPaymentDetail(paymentHash)
|
||||
}.getOrNull()
|
||||
|
||||
when {
|
||||
// ── Settled ──────────────────────────────────────────────────────────
|
||||
detail?.paid == true -> {
|
||||
val feeSats = detail.details?.feeSat
|
||||
_sendState.value = SendState.PaymentSent(
|
||||
amountSats = amountSats,
|
||||
feeSats = feeSats,
|
||||
paymentHash = paymentHash,
|
||||
pendingRecord = buildPendingRecord(paymentHash, amountSats, feeSats, bolt11, memo, pubkey, alias)
|
||||
)
|
||||
balanceVm.refreshBalance()
|
||||
}
|
||||
|
||||
// ── Hold invoice — still pending ──────────────────────────────────
|
||||
detail?.details?.status == "pending" || detail?.details?.pending == true -> {
|
||||
// Stay in SendState.Paying and start polling (see Part 2)
|
||||
pollUntilSettled(paymentHash, amountSats, bolt11, memo, pubkey, alias, strings)
|
||||
}
|
||||
|
||||
// ── Failed or unknown ─────────────────────────────────────────────
|
||||
else -> {
|
||||
_sendState.value = SendState.Error(strings.paymentFailed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun pollUntilSettled(
|
||||
paymentHash : String,
|
||||
amountSats : Long,
|
||||
bolt11 : String?,
|
||||
memo : String?,
|
||||
pubkey : String?,
|
||||
alias : String?,
|
||||
strings : SendStrings,
|
||||
) {
|
||||
// SendState.Paying is already set — the UI already shows the
|
||||
// hourglass/slow-payment message after 10 s, so no UI change needed here.
|
||||
val pollIntervalMs = 5_000L
|
||||
val maxAttempts = 120 // 10 minutes total
|
||||
|
||||
repeat(maxAttempts) { attempt ->
|
||||
delay(pollIntervalMs)
|
||||
|
||||
val detail = runCatching { repo.getPaymentDetail(paymentHash) }.getOrNull()
|
||||
|
||||
when {
|
||||
detail?.paid == true -> {
|
||||
val feeSats = detail.details?.feeSat
|
||||
_sendState.value = SendState.PaymentSent(
|
||||
amountSats = amountSats,
|
||||
feeSats = feeSats,
|
||||
paymentHash = paymentHash,
|
||||
pendingRecord = buildPendingRecord(paymentHash, amountSats, feeSats, bolt11, memo, pubkey, alias)
|
||||
)
|
||||
balanceVm.refreshBalance()
|
||||
return // done
|
||||
}
|
||||
|
||||
// Still pending — keep polling
|
||||
detail?.details?.status == "pending" || detail?.details?.pending == true -> {
|
||||
Log.d(TAG, "HOLD INVOICE [POLL $attempt] still pending — $paymentHash")
|
||||
}
|
||||
|
||||
// Failed (status changed to "failed" or detail is gone)
|
||||
else -> {
|
||||
Log.w(TAG, "HOLD INVOICE [POLL $attempt] payment failed — $paymentHash")
|
||||
_sendState.value = SendState.Error(strings.paymentFailed)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Timed out — leave in Paying so the user can dismiss manually
|
||||
// (the existing 10-second slow-payment UI already handles this gracefully)
|
||||
Log.w(TAG, "HOLD INVOICE [POLL TIMEOUT] $paymentHash — leaving in Paying state")
|
||||
}
|
||||
|
||||
|
||||
fun payLnurl(
|
||||
rawRes : LnurlScanResponse,
|
||||
lnurl : String,
|
||||
|
||||
Reference in New Issue
Block a user