taler-android

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

commit 552c95a8d6f561e0d87b0b4d9edd1d913d3956d7
parent 2ee27388aa2520c1625df3f20e2aecc0bad680b4
Author: Iván Ávalos <avalos@disroot.org>
Date:   Fri, 31 Jul 2026 15:28:25 +0200

[wallet] fix #11696 and #11695

Diffstat:
Mwallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt | 43+++++++++++++++++++++++++++++++++++++++----
Mwallet/src/main/java/net/taler/wallet/transactions/TransactionActionsComposable.kt | 41++++++++++++++++++++++++++---------------
Mwallet/src/main/java/net/taler/wallet/transactions/TransactionDetailScreen.kt | 4++++
Mwallet/src/main/java/net/taler/wallet/transactions/Transactions.kt | 2+-
Mwallet/src/main/java/net/taler/wallet/transfer/WireTransferDetailsScreen.kt | 35++++++++++-------------------------
5 files changed, 80 insertions(+), 45 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt b/wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt @@ -17,7 +17,9 @@ package net.taler.wallet.deposit import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -25,6 +27,11 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -50,17 +57,22 @@ import net.taler.wallet.transactions.TransactionAction.Suspend import net.taler.wallet.transactions.TransactionAmountComposable import net.taler.wallet.transactions.TransactionDeposit import net.taler.wallet.transactions.TransactionMajorState.Pending +import net.taler.wallet.transactions.TransactionMinorState import net.taler.wallet.transactions.TransactionState import net.taler.wallet.transactions.TransactionStateComposable +import net.taler.wallet.transactions.TransferOption import net.taler.wallet.transactions.TransitionsComposable +import net.taler.wallet.withdraw.TransferOptionChooser @Composable fun TransactionDepositComposable( t: TransactionDeposit, devMode: Boolean, spec: CurrencySpecification?, + onSelectOption: (option: TransferOption?) -> Unit, onWireTransfer: () -> Unit, onShowQrCodes: () -> Unit, + onConfirmKyc: (url: String) -> Unit, onTransition: (t: TransactionAction) -> Unit, modifier: Modifier = Modifier, ) { @@ -71,6 +83,27 @@ fun TransactionDepositComposable( .verticalScroll(scrollState), horizontalAlignment = Alignment.CenterHorizontally, ) { + val defaultOptionIndex = 0 + var selectedOptionIndex by remember { mutableIntStateOf(defaultOptionIndex) } + val selectedOption = t.kycAuthTransferInfo?.transferOptions[selectedOptionIndex] + + LaunchedEffect(selectedOption) { + selectedOption?.let { onSelectOption(it) } + } + + val showOptionChooser = t.kycAuthTransferInfo != null + && t.kycAuthTransferInfo.transferOptions.size > 1 + && t.txState.minor == TransactionMinorState.KycAuthRequired + + if (showOptionChooser) { + TransferOptionChooser( + options = t.kycAuthTransferInfo.transferOptions, + selectedIndex = selectedOptionIndex, + onSelectOption = { selectedOptionIndex = it }, + ) + Spacer(Modifier.height(16.dp)) + } + TransactionStateComposable(state = t.txState) Text( @@ -79,12 +112,12 @@ fun TransactionDepositComposable( style = MaterialTheme.typography.bodyLarge, ) - val qrCodes = t.kycAuthTransferInfo?.transferOptions - ?.firstOrNull()?.qrCodes ?: emptyList() + val qrCodes = selectedOption?.qrCodes ?: emptyList() DepositActions(t, qrCodes = qrCodes, onWireTransfer = onWireTransfer, - onShowQrCodes = onShowQrCodes) + onShowQrCodes = onShowQrCodes, + onConfirmKyc = onConfirmKyc) TransactionAmountComposable( label = stringResource(id = R.string.amount_chosen), @@ -121,7 +154,7 @@ fun TransactionDepositComposable( fun TransactionDepositComposablePreview() { val t = TransactionDeposit( transactionId = "transactionId", - timestamp = Timestamp.fromMillis(System.currentTimeMillis() - 360 * 60 * 1000), + timestamp = Timestamp.fromMillis(System.currentTimeMillis() - 360 * 60 * 1000), txState = TransactionState(Pending), txActions = listOf(Retry, Suspend, Abort), depositGroupId = "fooBar", @@ -139,6 +172,8 @@ fun TransactionDepositComposablePreview() { t = t, devMode = true, spec = null, + onSelectOption = {}, + onConfirmKyc = {}, onWireTransfer = {}, onShowQrCodes = {}, onTransition = {}, diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionActionsComposable.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionActionsComposable.kt @@ -108,23 +108,34 @@ fun ColumnScope.DepositActions( qrCodes: List<QrCodeSpec>, onWireTransfer: () -> Unit, onShowQrCodes: () -> Unit, + onConfirmKyc: (url: String) -> Unit, ) { - if (tx.txState.minor == KycAuthRequired) { - WireTransferStepsButton(onWireTransfer) - if (qrCodes.size == 1) { - Text( - text = stringResource(R.string.withdraw_manual_instruction_qr), - modifier = Modifier.padding(16.dp), - textAlign = TextAlign.Center, - style = MaterialTheme.typography.bodyLarge, - ) - PaytoQrCode( - modifier = Modifier.padding(horizontal = 16.dp), - qrCode = qrCodes[0], - ) - } else if (qrCodes.size > 1) { - ShowQrCodesButton(onShowQrCodes) + when (tx.txState.minor) { + KycAuthRequired -> { + WireTransferStepsButton(onWireTransfer) + if (qrCodes.size == 1) { + Text( + text = stringResource(R.string.withdraw_manual_instruction_qr), + modifier = Modifier.padding(16.dp), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyLarge, + ) + PaytoQrCode( + modifier = Modifier.padding(horizontal = 16.dp), + qrCode = qrCodes[0], + ) + } else if (qrCodes.size > 1) { + ShowQrCodesButton(onShowQrCodes) + } } + + KycRequired -> if (tx.kycUrl != null) { + ConfirmKycButton { + onConfirmKyc(tx.kycUrl) + } + } + + else -> {} } } diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailScreen.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionDetailScreen.kt @@ -210,6 +210,10 @@ fun TransactionDetailScreen( t = tx, devMode = devMode, spec = exchangeManager.getSpecForCurrency(tx.amountRaw.currency, tx.scopes), + onSelectOption = { it?.let { transactionManager.selectTransferOption(it) } }, + onConfirmKyc = { url -> + launchInAppBrowser(context, url) + }, onWireTransfer = { keepSelectedTx = true onNavigate( diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt @@ -553,7 +553,7 @@ class TransactionDeposit( override val amountType = AmountType.Negative @Composable override fun getTitle(): String { - val uri = Uri.parse(targetPaytoUri) + val uri = targetPaytoUri.toUri() return uri.getQueryParameter("receiver-name")?.let { receiverName -> stringResource(R.string.transaction_deposit_to, receiverName) } ?: stringResource(R.string.transaction_deposit) diff --git a/wallet/src/main/java/net/taler/wallet/transfer/WireTransferDetailsScreen.kt b/wallet/src/main/java/net/taler/wallet/transfer/WireTransferDetailsScreen.kt @@ -82,16 +82,16 @@ fun WireTransferDetailsScreen( context.shareText(text = transfer.withdrawalAccount.paytoUri) } + val option = selectedOption + val paytoUri = when (option) { + is TransferOption.Payto -> option.paytoUri + is TransferOption.SwissQrBill -> option.paytoUri + else -> null + } + if (paytoUri == null || option == null) return@GlobalScaffold + when (tx) { is TransactionWithdrawal -> { - val option = selectedOption - val paytoUri = when (option) { - is TransferOption.Payto -> option.paytoUri - is TransferOption.SwissQrBill -> option.paytoUri - else -> null - } - if (paytoUri == null || option == null) return@GlobalScaffold - val transferData = remember(option, tx) { WithdrawalExchangeAccountDetails( paytoUri = paytoUri, @@ -120,29 +120,14 @@ fun WireTransferDetailsScreen( } is TransactionDeposit -> { - val opt = tx.kycAuthTransferInfo?.transferOptions?.firstOrNull() - if (opt == null) { - EmptyComposable(modifier = Modifier.padding(paddingValues)) - return@GlobalScaffold - } - - val paytoUri = when (opt) { - is TransferOption.Payto -> opt.paytoUri - is TransferOption.SwissQrBill -> opt.paytoUri - is TransferOption.Uri -> { - EmptyComposable(modifier = Modifier.padding(paddingValues)) - return@GlobalScaffold - } - } - - val transferData = remember(opt, tx) { + val transferData = remember(option, tx) { WithdrawalExchangeAccountDetails( paytoUri = paytoUri, status = WithdrawalExchangeAccountDetails.Status.Ok, ).getTransferDetails( amountRaw = tx.amountRaw, amountEffective = tx.amountEffective, - transferOption = opt, + transferOption = option, ) }