taler-android

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

commit c7f9effe3cc6027d5660335d4f321422552e4d58
parent a766783513fe9ca673a8a2b98fb7e5a07f62a578
Author: Iván Ávalos <avalos@disroot.org>
Date:   Fri,  2 Aug 2024 14:33:00 -0600

[wallet] Render reserveClosingDelay in aborted manual withdrawals

bug 0009035

Diffstat:
Mtaler-kotlin-android/src/main/java/net/taler/common/Time.kt | 10++++++++--
Mwallet/src/main/java/net/taler/wallet/transactions/TransactionStateComposable.kt | 29++++++++++++++++++++++++++++-
Mwallet/src/main/java/net/taler/wallet/transactions/Transactions.kt | 2++
Mwallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt | 6++++--
Mwallet/src/main/res/values/strings.xml | 1+
5 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/taler-kotlin-android/src/main/java/net/taler/common/Time.kt b/taler-kotlin-android/src/main/java/net/taler/common/Time.kt @@ -50,6 +50,12 @@ data class Timestamp( else -> RelativeTime.fromMillis(ms - other.ms) } + operator fun plus(other: RelativeTime): Timestamp = when { + ms == NEVER -> this + other.ms == RelativeTime.FOREVER -> never() + else -> fromMillis(ms + other.ms) + } + operator fun minus(other: RelativeTime): Timestamp = when { ms == NEVER -> this other.ms == RelativeTime.FOREVER -> fromMillis(0) @@ -76,9 +82,9 @@ data class RelativeTime( */ @SerialName("d_us") @Serializable(ForeverSerializer::class) - private val s: Long, + private val us: Long, ) { - val ms: Long = s * 1000L + val ms: Long = us / 1000L companion object { internal const val FOREVER: Long = -1 diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionStateComposable.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionStateComposable.kt @@ -27,10 +27,15 @@ import androidx.compose.material3.ShapeDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext 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.common.Amount +import net.taler.common.RelativeTime +import net.taler.common.Timestamp +import net.taler.common.toAbsoluteTime import net.taler.wallet.R import net.taler.wallet.compose.TalerSurface import net.taler.wallet.transactions.TransactionMajorState.Aborted @@ -41,16 +46,24 @@ import net.taler.wallet.transactions.TransactionMajorState.Failed import net.taler.wallet.transactions.TransactionMajorState.Pending import net.taler.wallet.transactions.TransactionMajorState.Suspended import net.taler.wallet.transactions.TransactionMinorState.BankConfirmTransfer +import net.taler.wallet.transactions.WithdrawalDetails.ManualTransfer @Composable fun TransactionStateComposable( modifier: Modifier = Modifier, state: TransactionState, + tx: Transaction? = null, ) { + val context = LocalContext.current val message = when (state) { TransactionState(Pending, BankConfirmTransfer) -> stringResource(R.string.transaction_state_pending_bank) TransactionState(Pending) -> stringResource(R.string.transaction_state_pending) - TransactionState(Aborted) -> stringResource(R.string.transaction_state_aborted) + TransactionState(Aborted) -> if (tx is TransactionWithdrawal && tx.withdrawalDetails is ManualTransfer) { + stringResource( + R.string.transaction_state_aborted_manual, + (tx.timestamp + tx.withdrawalDetails.reserveClosingDelay).ms.toAbsoluteTime(context).toString(), + ) + } else stringResource(R.string.transaction_state_aborted) TransactionState(Aborting) -> stringResource(R.string.transaction_state_aborting) TransactionState(Suspended) -> stringResource(R.string.transaction_state_suspended) TransactionState(Failed) -> stringResource(R.string.transaction_state_failed) @@ -106,6 +119,20 @@ fun TransactionStateComposablePreview() { TransactionStateComposable(modifier, state = TransactionState(Failed)) TransactionStateComposable(modifier, state = TransactionState(Expired)) TransactionStateComposable(modifier, state = TransactionState(Done)) + + TransactionStateComposable(modifier, state = TransactionState(Aborted), tx = TransactionWithdrawal( + transactionId = "1234", + timestamp = Timestamp.fromMillis(1722629432000L), + txState = TransactionState(Aborted), + txActions = emptyList(), + exchangeBaseUrl = "exchange.demo.taler.net", + withdrawalDetails = ManualTransfer( + exchangeCreditAccountDetails = emptyList(), + reserveClosingDelay = RelativeTime(10_000_000_000_000), + ), + amountRaw = Amount.zero("KUDOS"), + amountEffective = Amount.zero("KUDOS"), + )) } } } diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt @@ -43,6 +43,7 @@ import net.taler.wallet.TAG import net.taler.wallet.backend.TalerErrorCode import net.taler.wallet.backend.TalerErrorInfo import net.taler.common.CurrencySpecification +import net.taler.common.RelativeTime import net.taler.wallet.refund.RefundPaymentInfo import net.taler.wallet.transactions.TransactionMajorState.None import net.taler.wallet.transactions.TransactionMajorState.Pending @@ -184,6 +185,7 @@ sealed class WithdrawalDetails { @SerialName("manual-transfer") class ManualTransfer( val exchangeCreditAccountDetails: List<WithdrawalExchangeAccountDetails>? = null, + val reserveClosingDelay: RelativeTime, ) : WithdrawalDetails() @Serializable diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt b/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt @@ -32,13 +32,14 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import net.taler.common.Amount +import net.taler.common.CurrencySpecification +import net.taler.common.RelativeTime import net.taler.common.Timestamp import net.taler.common.toAbsoluteTime import net.taler.wallet.R import net.taler.wallet.backend.TalerErrorCode import net.taler.wallet.backend.TalerErrorInfo import net.taler.wallet.cleanExchange -import net.taler.common.CurrencySpecification import net.taler.wallet.transactions.ActionButton import net.taler.wallet.transactions.ActionListener import net.taler.wallet.transactions.AmountType @@ -75,7 +76,7 @@ fun TransactionWithdrawalComposable( ) { val context = LocalContext.current - TransactionStateComposable(state = t.txState) + TransactionStateComposable(state = t.txState, tx = t) Text( modifier = Modifier.padding(16.dp), @@ -145,6 +146,7 @@ fun TransactionWithdrawalComposablePreview() { ), ), ), + reserveClosingDelay = RelativeTime.fromMillis(1000), ), amountRaw = Amount.fromString("TESTKUDOS", "42.23"), amountEffective = Amount.fromString("TESTKUDOS", "42.1337"), diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml @@ -135,6 +135,7 @@ GNU Taler is immune against many types of fraud, such as phishing of credit card <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_aborted_manual">This transaction was aborted. If you have already sent money to this exchange, it will be transferred back to you in %1$s</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>