taler-android

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

commit 6e7c17b810543725d5982228cb597c6b3ad06aa9
parent ec34c9ab65358840cad4e959dca9e6e2aa2b6352
Author: Iván Ávalos <avalos@disroot.org>
Date:   Wed, 14 Jan 2026 22:31:18 +0100

[wallet] fix withdrawal crash on empty wallet

Diffstat:
Mwallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt | 36+++++++++++++++++++++++-------------
Mwallet/src/main/java/net/taler/wallet/withdraw/WithdrawalShowInfo.kt | 7++++++-
2 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt @@ -24,12 +24,14 @@ import androidx.appcompat.app.AppCompatActivity import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.remember import androidx.compose.ui.platform.ComposeView import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.map import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController import com.google.android.material.snackbar.Snackbar @@ -40,10 +42,7 @@ import net.taler.common.EventObserver import net.taler.wallet.MainViewModel import net.taler.wallet.R import net.taler.wallet.main.ViewMode -import net.taler.wallet.backend.BackendManager -import net.taler.wallet.balances.ScopeInfo import net.taler.wallet.compose.AmountScope -import net.taler.wallet.compose.EmptyComposable import net.taler.wallet.compose.LoadingScreen import net.taler.wallet.compose.TalerSurface import net.taler.wallet.compose.collectAsStateLifecycleAware @@ -81,19 +80,30 @@ class PromptWithdrawFragment: Fragment() { val withdrawExchangeUri = arguments?.getString("withdrawExchangeUri") val exchangeBaseUrl = arguments?.getString("exchangeBaseUrl") val amount = arguments?.getString("amount")?.let { Amount.fromJSONString(it) } - val scope: ScopeInfo? = arguments?.getString("scopeInfo")?.let { - BackendManager.json.decodeFromString(it) - } ?: (model.viewMode.value as? ViewMode.Transactions)?.selectedScope editableCurrency = arguments?.getBoolean("editableCurrency") ?: true - val scopes = balanceManager.getScopes() setContent { val status by withdrawManager.withdrawStatus.collectAsStateLifecycleAware() + val viewMode by model.viewMode.collectAsStateLifecycleAware() val devMode by model.devMode.observeAsState() + val selectedScope = remember (viewMode) { + (viewMode as? ViewMode.Transactions)?.selectedScope + } + + val scopes by balanceManager.balances + .map { bl -> bl.map { it.scopeInfo } } + .map { bl -> + val scope = status.amountInfo?.scopeInfo + if (scope != null && !bl.contains(scope)) { bl + scope } else bl + }.observeAsState(emptyList()) + + val initialAmount = status.selectedAmount + ?: selectedScope?.let { Amount.zero(it.currency) } + ?: scopes.firstOrNull()?.let { Amount.zero(it.currency) } - if (scopes.isEmpty()) EmptyComposable() - val initialScope = status.selectedScope ?: scope ?: scopes.first() - val initialAmount = status.selectedAmount ?: Amount.zero(initialScope.currency) + val initialScope = status.selectedScope + ?: selectedScope + ?: scopes.firstOrNull() LaunchedEffect(status.status) { if (status.status == None) { @@ -105,7 +115,7 @@ class PromptWithdrawFragment: Fragment() { withdrawManager.prepareManualWithdrawal(withdrawExchangeUri) } else if (exchangeBaseUrl != null) { withdrawManager.getWithdrawalDetailsForExchange(exchangeBaseUrl, loading = true) - } else { + } else if (initialAmount != null) { withdrawManager.getWithdrawalDetailsForAmount( amount = initialAmount, scopeInfo = initialScope, @@ -133,8 +143,8 @@ class PromptWithdrawFragment: Fragment() { WithdrawalShowInfo( status = s, devMode = devMode ?: false, - initialAmountScope = status.selectedAmount?.let { amount -> - status.selectedScope?.let { scope -> + initialAmountScope = initialAmount?.let { amount -> + initialScope?.let { scope -> AmountScope(amount, scope) } }, diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawalShowInfo.kt b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawalShowInfo.kt @@ -92,6 +92,11 @@ fun WithdrawalShowInfo( val possibleExchanges = status.uriInfo?.possibleExchanges ?: emptyList() val ageRestrictionOptions = status.amountInfo?.ageRestrictionOptions ?: emptyList() + if (scopes.isEmpty()) { + LoadingScreen() + return + } + val keyboardController = LocalSoftwareKeyboardController.current var selectedAmount by remember(initialAmountScope != null) { mutableStateOf(initialAmountScope @@ -330,7 +335,7 @@ fun WithdrawalShowInfo( enabled = status.status != Updating && (status.isCashAcceptor || status.status == TosReviewRequired - || !selectedAmount.amount.isZero()), + || status.selectedAmount?.isZero() == false), onClick = { keyboardController?.hide() if (status.status == TosReviewRequired) {