refactor: move biometric prompt trigger to UI
This commit is contained in:
@@ -10,7 +10,6 @@ import com.bitcointxoko.gudariwallet.data.WalletRepository
|
|||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import com.bitcointxoko.gudariwallet.data.BalancePrefsStore
|
import com.bitcointxoko.gudariwallet.data.BalancePrefsStore
|
||||||
import com.bitcointxoko.gudariwallet.data.LightningAddressStore
|
import com.bitcointxoko.gudariwallet.data.LightningAddressStore
|
||||||
import com.bitcointxoko.gudariwallet.ui.balance.BalanceViewModel
|
import com.bitcointxoko.gudariwallet.ui.balance.BalanceViewModel
|
||||||
@@ -103,12 +102,9 @@ class WalletViewModel(
|
|||||||
fun payLnurlInvoice(state: SendState.LnurlInvoiceReady, strings: SendStrings) =
|
fun payLnurlInvoice(state: SendState.LnurlInvoiceReady, strings: SendStrings) =
|
||||||
sendVm.payLnurlInvoice(state, strings)
|
sendVm.payLnurlInvoice(state, strings)
|
||||||
|
|
||||||
fun requestPayment(
|
fun onAuthFailed(message: String, strings: SendStrings) {
|
||||||
activity : FragmentActivity,
|
sendVm.onAuthFailed(message, strings)
|
||||||
subtitle : String,
|
}
|
||||||
strings : SendStrings,
|
|
||||||
pay : () -> Unit,
|
|
||||||
) = sendVm.requestPayment(activity, subtitle, strings, pay)
|
|
||||||
fun resetSendState() = sendVm.resetSendState()
|
fun resetSendState() = sendVm.resetSendState()
|
||||||
|
|
||||||
val sendEvents: SharedFlow<SendEvent> = sendVm.events
|
val sendEvents: SharedFlow<SendEvent> = sendVm.events
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import com.bitcointxoko.gudariwallet.ui.SendState
|
|||||||
import com.bitcointxoko.gudariwallet.ui.WalletViewModel
|
import com.bitcointxoko.gudariwallet.ui.WalletViewModel
|
||||||
import com.bitcointxoko.gudariwallet.ui.components.CopyIconButton
|
import com.bitcointxoko.gudariwallet.ui.components.CopyIconButton
|
||||||
import com.bitcointxoko.gudariwallet.ui.components.DetailRow
|
import com.bitcointxoko.gudariwallet.ui.components.DetailRow
|
||||||
|
import com.bitcointxoko.gudariwallet.util.BiometricHelper
|
||||||
import com.bitcointxoko.gudariwallet.util.fiatLabel
|
import com.bitcointxoko.gudariwallet.util.fiatLabel
|
||||||
import com.bitcointxoko.gudariwallet.util.payingToLabel
|
import com.bitcointxoko.gudariwallet.util.payingToLabel
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@@ -52,13 +53,13 @@ internal fun Bolt11ConfirmCard(
|
|||||||
title = strings.invoiceDetails, // ← "Invoice Details"
|
title = strings.invoiceDetails, // ← "Invoice Details"
|
||||||
invoice = state,
|
invoice = state,
|
||||||
fiatLabel = fiatLbl,
|
fiatLabel = fiatLbl,
|
||||||
onPay = {
|
onPay = rememberBiometricPay(
|
||||||
vm.requestPayment(
|
activity = activity,
|
||||||
activity,
|
subtitle = strings.sendBiometricPrompt(state.amountSats),
|
||||||
strings.sendBiometricPrompt(state.amountSats),
|
strings = sendStrings,
|
||||||
strings = sendStrings, // ← "Send X sats"
|
vm = vm,
|
||||||
) { vm.payBolt11(state.bolt11, sendStrings) }
|
pay = { vm.payBolt11(state.bolt11, sendStrings) }
|
||||||
},
|
),
|
||||||
onCancel = { vm.resetSendState() }
|
onCancel = { vm.resetSendState() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -79,13 +80,13 @@ internal fun LnurlInvoiceConfirmCard(
|
|||||||
title = strings.payingTo(label), // ← "Paying to X"
|
title = strings.payingTo(label), // ← "Paying to X"
|
||||||
invoice = state,
|
invoice = state,
|
||||||
fiatLabel = fiatLbl,
|
fiatLabel = fiatLbl,
|
||||||
onPay = {
|
onPay = rememberBiometricPay(
|
||||||
vm.requestPayment(
|
activity = activity,
|
||||||
activity,
|
subtitle = strings.sendBiometricPromptTo(state.amountSats, label),
|
||||||
strings.sendBiometricPromptTo(state.amountSats, label),
|
strings = sendStrings,
|
||||||
strings = sendStrings, // ← "Send X sats to Y"
|
vm = vm,
|
||||||
) { vm.payLnurlInvoice(state, sendStrings) }
|
pay = { vm.payLnurlInvoice(state, sendStrings) }
|
||||||
},
|
),
|
||||||
onCancel = { vm.resetSendState() }
|
onCancel = { vm.resetSendState() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -270,3 +271,25 @@ private fun PayCancelButton(onCancel: () -> Unit) {
|
|||||||
Text(strings.cancel) // ← "Cancel"
|
Text(strings.cancel) // ← "Cancel"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun rememberBiometricPay(
|
||||||
|
activity : FragmentActivity,
|
||||||
|
subtitle : String,
|
||||||
|
strings : SendStrings,
|
||||||
|
vm : WalletViewModel,
|
||||||
|
pay : () -> Unit,
|
||||||
|
): () -> Unit = remember(subtitle) {
|
||||||
|
{
|
||||||
|
if (BiometricHelper.canAuthenticate(activity)) {
|
||||||
|
BiometricHelper.prompt(
|
||||||
|
activity = activity,
|
||||||
|
subtitle = subtitle,
|
||||||
|
onSuccess = pay,
|
||||||
|
onError = { _, msg -> vm.onAuthFailed(msg.toString(), strings) }
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
pay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,6 +71,10 @@ class SendViewModel(
|
|||||||
private val _sendState = MutableStateFlow<SendState>(SendState.Idle)
|
private val _sendState = MutableStateFlow<SendState>(SendState.Idle)
|
||||||
val sendState: StateFlow<SendState> = _sendState
|
val sendState: StateFlow<SendState> = _sendState
|
||||||
|
|
||||||
|
fun onAuthFailed(message: String, strings: SendStrings) {
|
||||||
|
_sendState.value = SendState.Error(strings.authFailed(message))
|
||||||
|
}
|
||||||
|
|
||||||
// ── Entry point ──────────────────────────────────────────────────────────
|
// ── Entry point ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
fun scan(rawInput: String, strings: SendStrings) {
|
fun scan(rawInput: String, strings: SendStrings) {
|
||||||
@@ -321,31 +325,6 @@ class SendViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Biometric gate. Shows prompt if device supports it; calls [pay] directly if not.
|
|
||||||
*/
|
|
||||||
fun requestPayment(
|
|
||||||
activity : FragmentActivity,
|
|
||||||
subtitle : String,
|
|
||||||
strings : SendStrings,
|
|
||||||
pay : () -> Unit
|
|
||||||
) {
|
|
||||||
if (!BiometricHelper.canAuthenticate(activity)) {
|
|
||||||
pay()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
BiometricHelper.prompt(
|
|
||||||
activity = activity,
|
|
||||||
subtitle = subtitle,
|
|
||||||
onSuccess = pay,
|
|
||||||
onError = { _, msg ->
|
|
||||||
_sendState.value = SendState.Error(
|
|
||||||
strings.authFailed(msg.toString()) // ← "Authentication failed: $msg"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun resetSendState() { _sendState.value = SendState.Idle }
|
fun resetSendState() { _sendState.value = SendState.Idle }
|
||||||
|
|
||||||
// ── Scan handlers ────────────────────────────────────────────────────────
|
// ── Scan handlers ────────────────────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user