taler-android

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

commit 97f8c41c87f07dcbf418f81060cc8e8842938201
parent 72d0f8816eb4eba03ea7e8474642b6c503ca5cc1
Author: Iván Ávalos <avalos@disroot.org>
Date:   Thu, 26 Sep 2024 15:19:29 +0200

[cashier] allow withdrawing under debit threshold

Diffstat:
Mcashier/src/main/java/net/taler/cashier/BalanceFragment.kt | 23++++++++++++++++++++---
Mcashier/src/main/java/net/taler/cashier/MainViewModel.kt | 12++++++++++--
Mcashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt | 4+++-
Mcashier/src/main/res/layout-w550dp/fragment_balance.xml | 16++++++++++++++++
Mcashier/src/main/res/layout/fragment_balance.xml | 18+++++++++++++++++-
Mcashier/src/main/res/values/strings.xml | 4+++-
6 files changed, 69 insertions(+), 8 deletions(-)

diff --git a/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt b/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt @@ -38,9 +38,13 @@ import net.taler.common.fadeIn import net.taler.common.fadeOut sealed class BalanceResult { - class Error(val msg: String) : BalanceResult() - object Offline : BalanceResult() - class Success(val amount: SignedAmount) : BalanceResult() + data class Error(val msg: String) : BalanceResult() + data object Offline : BalanceResult() + data class Success( + val amount: SignedAmount, + val debitThreshold: Amount, + val minCashout: Amount? = null, + ) : BalanceResult() } class BalanceFragment : Fragment() { @@ -137,14 +141,23 @@ class BalanceFragment : Fragment() { when (result) { is BalanceResult.Success -> { ui.balanceView.text = result.amount.toString() + if (!result.debitThreshold.isZero()) { + ui.debitView.text = getString( + R.string.balance_debit_threshold, + result.debitThreshold.toString(), + ) + ui.debitView.fadeIn() + } uiList.forEach { it.fadeIn() } } is BalanceResult.Error -> { ui.balanceView.text = getString(R.string.balance_error, result.msg) + ui.debitView.fadeOut() uiList.forEach { it.fadeOut() } } BalanceResult.Offline -> { ui.balanceView.text = getString(R.string.balance_offline) + ui.debitView.fadeOut() uiList.forEach { it.fadeOut() } } }.exhaustive @@ -164,8 +177,12 @@ class BalanceFragment : Fragment() { } private fun onAmountConfirmed(amount: Amount) { + val balance = viewModel.balance.value as? BalanceResult.Success + val minCashout = balance?.minCashout if (amount.isZero()) { ui.amountView.error = getString(R.string.withdraw_error_zero) + } else if (minCashout != null && amount < minCashout) { + ui.amountView.error = getString(R.string.withdraw_error_under_min_cashout, minCashout.toString()) } else when (withdrawManager.hasSufficientBalance(amount)) { true -> { ui.amountView.error = null diff --git a/cashier/src/main/java/net/taler/cashier/MainViewModel.kt b/cashier/src/main/java/net/taler/cashier/MainViewModel.kt @@ -71,14 +71,22 @@ class MainViewModel(private val app: Application) : AndroidViewModel(app) { try { val balanceObj = response.json.getJSONObject("balance") val balanceAmount = balanceObj.getString("amount") + val debitThreshold = response.json.getString("debit_threshold") + val minCashout = if (response.json.has("min_cashout")) { + response.json.getString("min_cashout") + } else null val positive = when (val creditDebitIndicator = balanceObj.getString("credit_debit_indicator")) { "credit" -> true "debit" -> false else -> throw AmountParserException("Unexpected credit_debit_indicator: $creditDebitIndicator") } - BalanceResult.Success(SignedAmount(positive, - Amount.fromJSONString(balanceAmount))) + BalanceResult.Success( + amount = SignedAmount(positive, Amount.fromJSONString(balanceAmount)), + debitThreshold = Amount.fromJSONString(debitThreshold), + minCashout = minCashout?.let { Amount.fromJSONString(it) } + + ) } catch (e: Exception) { Log.e(TAG, "Error parsing balance", e) BalanceResult.Error("Invalid amount:\n${response.json.toString(2)}") diff --git a/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt b/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt @@ -80,7 +80,9 @@ class WithdrawManager( val balanceResult = viewModel.balance.value if (balanceResult !is BalanceResult.Success) return false return try { - balanceResult.amount.positive && amount <= balanceResult.amount.amount + (balanceResult.amount.positive && amount <= (balanceResult.debitThreshold + balanceResult.amount.amount)) || + (!balanceResult.amount.positive && amount <= (balanceResult.debitThreshold - balanceResult.amount.amount)) + } catch (e: IllegalStateException) { Log.e(TAG, "Error comparing amounts", e) null diff --git a/cashier/src/main/res/layout-w550dp/fragment_balance.xml b/cashier/src/main/res/layout-w550dp/fragment_balance.xml @@ -79,6 +79,22 @@ app:layout_constraintTop_toBottomOf="@+id/balanceLabel" tools:text="100 KUDOS" /> + <TextView + android:id="@+id/debitView" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:gravity="center" + android:paddingStart="@dimen/default_margin" + android:paddingTop="8dp" + android:paddingEnd="@dimen/default_margin" + android:paddingBottom="@dimen/default_margin" + app:layout_constraintEnd_toStartOf="@id/guideline" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/balanceView" + android:visibility="gone" + tools:visibility="visible" + tools:text="@string/balance_debit_threshold" /> + <ProgressBar android:id="@+id/progressBar" style="?android:attr/progressBarStyle" diff --git a/cashier/src/main/res/layout/fragment_balance.xml b/cashier/src/main/res/layout/fragment_balance.xml @@ -45,7 +45,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:background="@color/background" - app:layout_constraintBottom_toBottomOf="@+id/balanceView" + app:layout_constraintBottom_toBottomOf="@+id/debitView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/lastTransactionView" /> @@ -76,6 +76,22 @@ app:layout_constraintTop_toBottomOf="@+id/balanceLabel" tools:text="100 KUDOS" /> + <TextView + android:id="@+id/debitView" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:gravity="center" + android:paddingStart="@dimen/default_margin" + android:paddingTop="8dp" + android:paddingEnd="@dimen/default_margin" + android:paddingBottom="@dimen/default_margin" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/balanceView" + android:visibility="gone" + tools:visibility="visible" + tools:text="@string/balance_debit_threshold" /> + <ProgressBar android:id="@+id/progressBar" style="?android:attr/progressBarStyle" diff --git a/cashier/src/main/res/values/strings.xml b/cashier/src/main/res/values/strings.xml @@ -14,7 +14,8 @@ <string name="balance_current_label">Current balance</string> <string name="balance_error">ERROR: %s</string> - <string name="balance_offline">Offline. Please connect to the Internet.</string> + <string name="balance_offline">Offline. Please connect to the Internet.</string>\ + <string name="balance_debit_threshold">Maximum debt: %1$s</string> <string name="ok">OK</string> @@ -26,6 +27,7 @@ <string name="withdraw_into">How much e-cash should be withdrawn?</string> <string name="withdraw_error_zero">Enter positive amount!</string> <string name="withdraw_error_insufficient_balance">Insufficient balance</string> + <string name="withdraw_error_under_min_cashout">Amount below minimum cash-out of %1$s</string> <string name="withdraw_error_currency_mismatch">Error: Bank reported a different currency</string> <string name="withdraw_error_fetch">Error communicating with bank: %s</string> <string name="withdraw_error_timeout">No wallet tried to withdraw. Please try again.</string>