diff options
author | Iván Ávalos <avalos@disroot.org> | 2024-04-02 11:35:07 -0600 |
---|---|---|
committer | Torsten Grote <t@grobox.de> | 2024-04-15 15:51:12 -0300 |
commit | 89e1051a022afd57bc901e02cf2ca3dce6998b6a (patch) | |
tree | fb59fed181dd2bcad06c0e5947303bb139817137 /wallet/src/main/java/net | |
parent | 7ac241fd58a17e552101e602d1451f6f65e74c8b (diff) | |
download | taler-android-89e1051a022afd57bc901e02cf2ca3dce6998b6a.tar.gz taler-android-89e1051a022afd57bc901e02cf2ca3dce6998b6a.tar.bz2 taler-android-89e1051a022afd57bc901e02cf2ca3dce6998b6a.zip |
[wallet] Implement financial loss transactions
bug 0008694
Diffstat (limited to 'wallet/src/main/java/net')
-rw-r--r-- | wallet/src/main/java/net/taler/wallet/transactions/TransactionLossFragment.kt | 163 | ||||
-rw-r--r-- | wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt | 41 |
2 files changed, 204 insertions, 0 deletions
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionLossFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionLossFragment.kt new file mode 100644 index 0000000..9138345 --- /dev/null +++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionLossFragment.kt @@ -0,0 +1,163 @@ +/* + * 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.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalContext +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.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.compose.TalerSurface +import net.taler.wallet.transactions.LossEventType.DenomExpired +import net.taler.wallet.transactions.LossEventType.DenomUnoffered +import net.taler.wallet.transactions.LossEventType.DenomVanished +import net.taler.wallet.transactions.TransactionAction.Abort +import net.taler.wallet.transactions.TransactionAction.Retry +import net.taler.wallet.transactions.TransactionAction.Suspend +import net.taler.wallet.transactions.TransactionMajorState.Pending + +class TransactionLossFragment: TransactionDetailFragment() { + val scope get() = transactionManager.selectedScope + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View = ComposeView(requireContext()).apply { + setContent { + val t = transactionManager.selectedTransaction.observeAsState().value + val spec = scope?.let { balanceManager.getSpecForScopeInfo(it) } + + TalerSurface { + if (t is TransactionDenomLoss) { + TransitionLossComposable(t, devMode, spec) { + onTransitionButtonClicked(t, it) + } + } + } + } + } +} + +@Composable +fun TransitionLossComposable( + t: TransactionDenomLoss, + devMode: Boolean, + spec: CurrencySpecification?, + onTransition: (t: TransactionAction) -> Unit, +) { + val scrollState = rememberScrollState() + val context = LocalContext.current + + Column( + modifier = Modifier + .fillMaxWidth() + .verticalScroll(scrollState), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + modifier = Modifier.padding(16.dp), + text = t.timestamp.ms.toAbsoluteTime(context).toString(), + style = MaterialTheme.typography.bodyLarge, + ) + + TransactionAmountComposable( + label = stringResource(id = R.string.loss_amount), + amount = t.amountEffective.withSpec(spec), + amountType = AmountType.Negative, + ) + + TransactionInfoComposable( + label = stringResource(id = R.string.loss_reason), + info = stringResource( + when(t.lossEventType) { + DenomExpired -> R.string.loss_reason_expired + DenomVanished -> R.string.loss_reason_vanished + DenomUnoffered -> R.string.loss_reason_unoffered + } + ) + ) + + TransitionsComposable(t, devMode, onTransition) + + if (devMode && t.error != null) { + ErrorTransactionButton(error = t.error) + } + } +} + +fun previewLossTransaction(lossEventType: LossEventType) = + TransactionDenomLoss( + transactionId = "transactionId", + timestamp = Timestamp.fromMillis(System.currentTimeMillis() - 360 * 60 * 1000), + txState = TransactionState(Pending), + txActions = listOf(Retry, Suspend, Abort), + amountRaw = Amount.fromString("TESTKUDOS", "0.3"), + amountEffective = Amount.fromString("TESTKUDOS", "0.3"), + error = TalerErrorInfo(code = TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED), + lossEventType = lossEventType, + ) + +@Composable +@Preview +fun TransitionLossComposableExpiredPreview() { + val t = previewLossTransaction(DenomExpired) + Surface { + TransitionLossComposable(t, true, null) {} + } +} + +@Composable +@Preview +fun TransitionLossComposableVanishedPreview() { + val t = previewLossTransaction(DenomVanished) + Surface { + TransitionLossComposable(t, true, null) {} + } +} + +@Composable +@Preview +fun TransactionLossComposableUnofferedPreview() { + val t = previewLossTransaction(DenomUnoffered) + Surface { + TransitionLossComposable(t, true, null) {} + } +} diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt index be36a13..f43db5f 100644 --- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt +++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt @@ -506,6 +506,47 @@ class TransactionPeerPushCredit( } /** + * A transaction to indicate financial loss due to denominations + * that became unusable for deposits. + */ +@Serializable +@SerialName("denom-loss") +class TransactionDenomLoss( + override val transactionId: String, + override val timestamp: Timestamp, + override val txState: TransactionState, + override val txActions: List<TransactionAction>, + override val error: TalerErrorInfo? = null, + override val amountRaw: Amount, + override val amountEffective: Amount, + val lossEventType: LossEventType, +): Transaction() { + override val icon: Int = R.drawable.transaction_loss + override val detailPageNav = R.id.nav_transactions_detail_loss + + @Transient + override val amountType: AmountType = AmountType.Negative + + override fun getTitle(context: Context): String { + return context.getString(R.string.transaction_denom_loss) + } + + override val generalTitleRes: Int = R.string.transaction_denom_loss +} + +@Serializable +enum class LossEventType { + @SerialName("denom-expired") + DenomExpired, + + @SerialName("denom-vanished") + DenomVanished, + + @SerialName("denom-unoffered") + DenomUnoffered +} + +/** * This represents a transaction that we can not parse for some reason. */ class DummyTransaction( |