taler-android

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

commit a8ae6141e54e5b8ee49c50a35254ad436790a86c
parent e1a53420dbfc672a06d969d9b758e6bab1a607cd
Author: Iván Ávalos <avalos@disroot.org>
Date:   Wed, 19 Jun 2024 15:55:06 -0600

[wallet] Render an alert for some transaction states

bug 0008955

Diffstat:
Mwallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt | 4++++
Mwallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt | 4++++
Mwallet/src/main/java/net/taler/wallet/refund/TransactionRefundComposable.kt | 10++++++++++
Mwallet/src/main/java/net/taler/wallet/transactions/TransactionLossFragment.kt | 2++
Mwallet/src/main/java/net/taler/wallet/transactions/TransactionPeerFragment.kt | 6++++++
Mwallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt | 5+++++
Awallet/src/main/java/net/taler/wallet/transactions/TransactionStateComposable.kt | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mwallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt | 4++++
Mwallet/src/main/res/values/strings.xml | 6++++++
9 files changed, 155 insertions(+), 0 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 @@ -48,6 +48,7 @@ import net.taler.wallet.transactions.TransactionAmountComposable import net.taler.wallet.transactions.TransactionDeposit import net.taler.wallet.transactions.TransactionMajorState.Pending import net.taler.wallet.transactions.TransactionState +import net.taler.wallet.transactions.TransactionStateComposable import net.taler.wallet.transactions.TransitionsComposable @Composable @@ -65,6 +66,9 @@ fun TransactionDepositComposable( horizontalAlignment = Alignment.CenterHorizontally, ) { val context = LocalContext.current + + TransactionStateComposable(state = t.txState) + Text( modifier = Modifier.padding(16.dp), text = t.timestamp.ms.toAbsoluteTime(context).toString(), diff --git a/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt b/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt @@ -52,6 +52,7 @@ import net.taler.wallet.transactions.TransactionLinkComposable import net.taler.wallet.transactions.TransactionMajorState.Pending import net.taler.wallet.transactions.TransactionPayment import net.taler.wallet.transactions.TransactionState +import net.taler.wallet.transactions.TransactionStateComposable import net.taler.wallet.transactions.TransitionsComposable @Composable @@ -70,6 +71,9 @@ fun TransactionPaymentComposable( horizontalAlignment = CenterHorizontally, ) { val context = LocalContext.current + + TransactionStateComposable(state = t.txState) + Text( modifier = Modifier.padding(16.dp), text = t.timestamp.ms.toAbsoluteTime(context).toString(), diff --git a/wallet/src/main/java/net/taler/wallet/refund/TransactionRefundComposable.kt b/wallet/src/main/java/net/taler/wallet/refund/TransactionRefundComposable.kt @@ -49,6 +49,7 @@ import net.taler.wallet.transactions.TransactionInfoComposable import net.taler.wallet.transactions.TransactionMajorState.Pending import net.taler.wallet.transactions.TransactionRefund import net.taler.wallet.transactions.TransactionState +import net.taler.wallet.transactions.TransactionStateComposable import net.taler.wallet.transactions.TransitionsComposable @Composable @@ -66,21 +67,27 @@ fun TransactionRefundComposable( horizontalAlignment = CenterHorizontally, ) { val context = LocalContext.current + + TransactionStateComposable(state = t.txState) + Text( modifier = Modifier.padding(16.dp), text = t.timestamp.ms.toAbsoluteTime(context).toString(), style = MaterialTheme.typography.bodyLarge, ) + TransactionAmountComposable( label = stringResource(id = R.string.transaction_refund), amount = t.amountEffective.withSpec(spec), amountType = AmountType.Positive, ) + TransactionAmountComposable( label = stringResource(id = R.string.transaction_order_total), amount = t.amountRaw.withSpec(spec), amountType = AmountType.Neutral, ) + if (t.amountRaw > t.amountEffective) { val fee = t.amountRaw - t.amountEffective TransactionAmountComposable( @@ -89,11 +96,14 @@ fun TransactionRefundComposable( amountType = AmountType.Negative, ) } + TransactionInfoComposable( label = stringResource(id = R.string.transaction_order), info = t.paymentInfo?.summary ?: "", ) + TransitionsComposable(t, devMode, onTransition) + if (devMode && t.error != null) { ErrorTransactionButton(error = t.error) } diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionLossFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionLossFragment.kt @@ -92,6 +92,8 @@ fun TransitionLossComposable( .verticalScroll(scrollState), horizontalAlignment = Alignment.CenterHorizontally, ) { + TransactionStateComposable(state = t.txState) + Text( modifier = Modifier.padding(16.dp), text = t.timestamp.ms.toAbsoluteTime(context).toString(), diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionPeerFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionPeerFragment.kt @@ -82,11 +82,15 @@ fun TransactionPeerComposable( horizontalAlignment = CenterHorizontally, ) { val context = LocalContext.current + + TransactionStateComposable(state = t.txState) + Text( modifier = Modifier.padding(16.dp), text = t.timestamp.ms.toAbsoluteTime(context).toString(), style = MaterialTheme.typography.bodyLarge, ) + when (t) { is TransactionPeerPullCredit -> TransactionPeerPullCreditComposable(t, spec) is TransactionPeerPushCredit -> TransactionPeerPushCreditComposable(t, spec) @@ -94,7 +98,9 @@ fun TransactionPeerComposable( is TransactionPeerPushDebit -> TransactionPeerPushDebitComposable(t, spec) else -> error("unexpected transaction: ${t::class.simpleName}") } + TransitionsComposable(t, devMode, onTransition) + if (devMode && t.error != null) { ErrorTransactionButton(error = t.error!!) } diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt @@ -85,16 +85,21 @@ private fun TransactionRefreshComposable( horizontalAlignment = CenterHorizontally, ) { val context = LocalContext.current + + TransactionStateComposable(state = t.txState) + Text( modifier = Modifier.padding(16.dp), text = t.timestamp.ms.toAbsoluteTime(context).toString(), style = MaterialTheme.typography.bodyLarge, ) + TransactionAmountComposable( label = stringResource(id = R.string.amount_fee), amount = t.amountEffective.withSpec(spec), amountType = AmountType.Negative, ) + TransitionsComposable(t, devMode, onTransition) if (devMode && t.error != null) { ErrorTransactionButton(error = t.error) diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionStateComposable.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionStateComposable.kt @@ -0,0 +1,113 @@ +/* + * This file is part of GNU Taler + * (C) 2024 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +package net.taler.wallet.transactions + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ShapeDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import net.taler.wallet.R +import net.taler.wallet.compose.TalerSurface +import net.taler.wallet.transactions.TransactionMajorState.Aborted +import net.taler.wallet.transactions.TransactionMajorState.Aborting +import net.taler.wallet.transactions.TransactionMajorState.Done +import net.taler.wallet.transactions.TransactionMajorState.Expired +import net.taler.wallet.transactions.TransactionMajorState.Failed +import net.taler.wallet.transactions.TransactionMajorState.Suspended +import net.taler.wallet.transactions.TransactionMajorState.Pending + +@Composable +fun TransactionStateComposable( + modifier: Modifier = Modifier, + state: TransactionState, +) { + val message = when (state.major) { + Pending -> stringResource(R.string.transaction_state_pending) + Aborted -> stringResource(R.string.transaction_state_aborted) + Aborting -> stringResource(R.string.transaction_state_aborting) + Suspended -> stringResource(R.string.transaction_state_suspended) + Failed -> stringResource(R.string.transaction_state_failed) + Expired -> stringResource(R.string.transaction_state_expired) + else -> return + } + + val cardColor = when (state.major) { + Aborted, Aborting, Failed, Expired -> MaterialTheme.colorScheme.errorContainer + Pending, Suspended -> MaterialTheme.colorScheme.surfaceVariant + else -> return + } + + val textColor = when (state.major) { + Aborted, Aborting, Failed, Expired -> MaterialTheme.colorScheme.onErrorContainer + Pending, Suspended -> MaterialTheme.colorScheme.onSurfaceVariant + else -> return + } + + Card( + modifier = modifier + .padding(horizontal = 9.dp) + .fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = cardColor, + ), + shape = ShapeDefaults.ExtraSmall, + ) { + Text( + modifier = Modifier + .padding(10.dp) + .fillMaxWidth(), + text = message, + style = MaterialTheme.typography.labelLarge, + color = textColor, + textAlign = TextAlign.Center, + ) + } +} + +@Preview +@Composable +fun TransactionStateComposablePreview() { + TalerSurface { + Column { + val modifier = Modifier.padding(vertical = 6.dp) + TransactionStateComposable(modifier, state = TransactionState(Pending)) + TransactionStateComposable(modifier, state = TransactionState(Aborted)) + TransactionStateComposable(modifier, state = TransactionState(Aborting)) + TransactionStateComposable(modifier, state = TransactionState(Suspended)) + TransactionStateComposable(modifier, state = TransactionState(Failed)) + TransactionStateComposable(modifier, state = TransactionState(Expired)) + TransactionStateComposable(modifier, state = TransactionState(Done)) + } + } +} + +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +fun TransactionStateComposableNightPreview() { + TransactionStateComposablePreview() +} +\ No newline at end of file diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt b/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt @@ -52,6 +52,7 @@ import net.taler.wallet.transactions.TransactionAmountComposable import net.taler.wallet.transactions.TransactionInfoComposable import net.taler.wallet.transactions.TransactionMajorState.Pending import net.taler.wallet.transactions.TransactionState +import net.taler.wallet.transactions.TransactionStateComposable import net.taler.wallet.transactions.TransactionWithdrawal import net.taler.wallet.transactions.TransitionsComposable import net.taler.wallet.transactions.WithdrawalDetails.ManualTransfer @@ -73,6 +74,9 @@ fun TransactionWithdrawalComposable( horizontalAlignment = Alignment.CenterHorizontally, ) { val context = LocalContext.current + + TransactionStateComposable(state = t.txState) + Text( modifier = Modifier.padding(16.dp), text = t.timestamp.ms.toAbsoluteTime(context).toString(), diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml @@ -129,6 +129,12 @@ GNU Taler is immune against many types of fraud, such as phishing of credit card <string name="transaction_pending">PENDING</string> <string name="transaction_refresh">Coin expiry change fee</string> <string name="transaction_refund">Refund</string> + <string name="transaction_state_aborted">This transaction was aborted</string> + <string name="transaction_state_aborting">This transaction is aborting</string> + <string name="transaction_state_expired">This transaction has expired</string> + <string name="transaction_state_failed">This transaction has failed</string> + <string name="transaction_state_pending">This transaction is pending</string> + <string name="transaction_state_suspended">This transaction is suspended</string> <string name="transactions_abort">Abort</string> <string name="transactions_abort_dialog_message">Are you sure you want to abort this transaction? Funds still in transit might get lost.</string> <string name="transactions_abort_dialog_title">Abort Transaction</string>