commit a7950cb0f51f2b9b34c38bd1bfa14ee4391ab37d
parent ddf18ca8b1fa64bc439b5fa39a78b751f7ba5281
Author: Iván Ávalos <avalos@disroot.org>
Date: Wed, 24 Jul 2024 09:30:20 -0600
[wallet] Show maximum effective amount in send screen when exceeded
Diffstat:
4 files changed, 40 insertions(+), 11 deletions(-)
diff --git a/taler-kotlin-android/src/test/java/net/taler/common/AmountTest.kt b/taler-kotlin-android/src/test/java/net/taler/common/AmountTest.kt
@@ -22,7 +22,6 @@ import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import java.text.DecimalFormatSymbols
-import kotlin.random.Random
class AmountTest {
diff --git a/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt b/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt
@@ -133,13 +133,19 @@ private fun SendFundsIntro(
horizontalAlignment = Alignment.CenterHorizontally,
) {
var text by rememberSaveable { mutableStateOf("0") }
+ val amount: Amount? = remember(currency, text) {
+ getAmount(currency, text)
+ }
var fees by remember { mutableStateOf<CheckFeeResult>(CheckFeeResult.None) }
-
val insufficientBalance: Boolean = remember(fees) {
fees is CheckFeeResult.InsufficientBalance
}
+ val maxAmount = remember(amount, fees) {
+ (fees as? CheckFeeResult.InsufficientBalance)?.maxAmountEffective
+ }
+
val calculateFees = { input: String ->
fees = CheckFeeResult.None
getAmount(currency, input)?.let { amount ->
@@ -162,6 +168,7 @@ private fun SendFundsIntro(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 8.dp),
) {
+
AmountInputField(
modifier = Modifier
.weight(1f)
@@ -173,7 +180,14 @@ private fun SendFundsIntro(
label = { Text(stringResource(R.string.amount_send)) },
supportingText = {
if (insufficientBalance) {
- Text(stringResource(R.string.payment_balance_insufficient))
+ if (maxAmount != null) {
+ Text(stringResource(
+ R.string.payment_balance_insufficient_max,
+ maxAmount.withSpec(spec).toString(),
+ ))
+ } else {
+ Text(stringResource(R.string.payment_balance_insufficient))
+ }
}
},
isError = insufficientBalance,
@@ -211,9 +225,6 @@ private fun SendFundsIntro(
)
Column(modifier = Modifier.padding(16.dp)) {
- val amount: Amount? = remember(currency, text) {
- getAmount(currency, text)
- }
Button(
modifier = Modifier.fillMaxWidth(),
@@ -288,9 +299,9 @@ fun PreviewSendFundsIntro() {
currency = "TESTKUDOS",
spec = null,
checkFees = {
- CheckFeeResult.Success(
- amountRaw = Amount.fromJSONString("TESTKUDOS:10"),
- amountEffective = Amount.fromJSONString("TESTKUDOS:10.2"),
+ CheckFeeResult.InsufficientBalance(
+ maxAmountRaw = Amount.fromJSONString("TESTKUDOS:10"),
+ maxAmountEffective = Amount.fromJSONString("TESTKUDOS:10.2"),
)
},
onDeposit = {},
diff --git a/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt b/wallet/src/main/java/net/taler/wallet/peer/PeerManager.kt
@@ -24,6 +24,8 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.jsonObject
+import kotlinx.serialization.json.jsonPrimitive
import net.taler.common.Amount
import net.taler.common.Timestamp
import net.taler.wallet.TAG
@@ -42,7 +44,10 @@ val DEFAULT_EXPIRY = ExpirationOption.DAYS_1
sealed class CheckFeeResult {
data object None: CheckFeeResult()
- data object InsufficientBalance: CheckFeeResult()
+ data class InsufficientBalance(
+ val maxAmountEffective: Amount?,
+ val maxAmountRaw: Amount?,
+ ): CheckFeeResult()
data class Success(
val amountRaw: Amount,
@@ -150,7 +155,20 @@ class PeerManager(
}.onError { error ->
Log.e(TAG, "got checkPeerPushDebit error result $error")
if (error.code == WALLET_PEER_PUSH_PAYMENT_INSUFFICIENT_BALANCE) {
- response = CheckFeeResult.InsufficientBalance
+ error.extra["insufficientBalanceDetails"]?.let { details ->
+ val maxAmountRaw = details.jsonObject["balanceAvailable"]?.let { amount ->
+ Amount.fromJSONString(amount.jsonPrimitive.content)
+ }
+
+ val maxAmountEffective = details.jsonObject["maxEffectiveSpendAmount"]?.let { amount ->
+ Amount.fromJSONString(amount.jsonPrimitive.content)
+ } ?: maxAmountRaw
+
+ response = CheckFeeResult.InsufficientBalance(
+ maxAmountEffective = maxAmountEffective,
+ maxAmountRaw = maxAmountRaw,
+ )
+ }
}
}
diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml
@@ -172,6 +172,7 @@ GNU Taler is immune against many types of fraud, such as phishing of credit card
<string name="payment_aborting">Aborting</string>
<string name="payment_already_paid">You\'ve already paid for this purchase.</string>
<string name="payment_balance_insufficient">Balance insufficient!</string>
+ <string name="payment_balance_insufficient_max">Balance insufficient! Maximum is %1$s</string>
<string name="payment_button_confirm">Confirm Payment</string>
<string name="payment_confirmation_code">Confirmation code</string>
<string name="payment_create_order">Create order</string>