taler-android

Android apps for GNU Taler (wallet, PoS, cashier)
Log | Files | Refs | README | LICENSE

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:
Mtaler-kotlin-android/src/test/java/net/taler/common/AmountTest.kt | 1-
Mwallet/src/main/java/net/taler/wallet/SendFundsFragment.kt | 27+++++++++++++++++++--------
Mwallet/src/main/java/net/taler/wallet/peer/PeerManager.kt | 22++++++++++++++++++++--
Mwallet/src/main/res/values/strings.xml | 1+
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>