TransactionWithdrawalComposable.kt (7672B)
1 /* 2 * This file is part of GNU Taler 3 * (C) 2023 Taler Systems S.A. 4 * 5 * GNU Taler is free software; you can redistribute it and/or modify it under the 6 * terms of the GNU General Public License as published by the Free Software 7 * Foundation; either version 3, or (at your option) any later version. 8 * 9 * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY 10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 package net.taler.wallet.withdraw 18 19 import androidx.compose.foundation.layout.Column 20 import androidx.compose.foundation.layout.fillMaxWidth 21 import androidx.compose.foundation.layout.padding 22 import androidx.compose.foundation.rememberScrollState 23 import androidx.compose.foundation.verticalScroll 24 import androidx.compose.material3.MaterialTheme 25 import androidx.compose.material3.Surface 26 import androidx.compose.material3.Text 27 import androidx.compose.runtime.Composable 28 import androidx.compose.ui.Alignment 29 import androidx.compose.ui.Modifier 30 import androidx.compose.ui.platform.LocalContext 31 import androidx.compose.ui.res.stringResource 32 import androidx.compose.ui.tooling.preview.Preview 33 import androidx.compose.ui.unit.dp 34 import net.taler.common.Amount 35 import net.taler.common.CurrencySpecification 36 import net.taler.common.RelativeTime 37 import net.taler.common.Timestamp 38 import net.taler.lib.android.toAbsoluteTime 39 import net.taler.wallet.BottomInsetsSpacer 40 import net.taler.wallet.R 41 import net.taler.wallet.backend.TalerErrorCode 42 import net.taler.wallet.backend.TalerErrorInfo 43 import net.taler.wallet.balances.ScopeInfo 44 import net.taler.wallet.cleanExchange 45 import net.taler.wallet.transactions.AmountType 46 import net.taler.wallet.transactions.ErrorTransactionButton 47 import net.taler.wallet.transactions.TransactionAction 48 import net.taler.wallet.transactions.TransactionAction.Abort 49 import net.taler.wallet.transactions.TransactionAction.Retry 50 import net.taler.wallet.transactions.TransactionAction.Suspend 51 import net.taler.wallet.transactions.TransactionAmountComposable 52 import net.taler.wallet.transactions.TransactionInfoComposable 53 import net.taler.wallet.transactions.TransactionMajorState.Pending 54 import net.taler.wallet.transactions.TransactionMinorState 55 import net.taler.wallet.transactions.TransactionState 56 import net.taler.wallet.transactions.TransactionStateComposable 57 import net.taler.wallet.transactions.TransactionWithdrawal 58 import net.taler.wallet.transactions.TransitionsComposable 59 import net.taler.wallet.transactions.WithdrawalActions 60 import net.taler.wallet.transactions.WithdrawalDetails.ManualTransfer 61 import net.taler.wallet.transactions.WithdrawalExchangeAccountDetails 62 63 @Composable 64 fun TransactionWithdrawalComposable( 65 t: TransactionWithdrawal, 66 devMode: Boolean, 67 qrCode: QrCodeSpec?, 68 spec: CurrencySpecification?, 69 onConfirmKyc: (url: String) -> Unit, 70 onConfirmBank: () -> Unit, 71 onConfirmManual: () -> Unit, 72 onShowQrCodes: () -> Unit, 73 onTransition: (t: TransactionAction) -> Unit, 74 modifier: Modifier = Modifier, 75 ) { 76 val scrollState = rememberScrollState() 77 Column( 78 modifier = modifier 79 .fillMaxWidth() 80 .verticalScroll(scrollState), 81 horizontalAlignment = Alignment.CenterHorizontally, 82 ) { 83 TransactionStateComposable(state = t.txState, tx = t) 84 85 Text( 86 modifier = Modifier.padding(16.dp), 87 text = t.timestamp.ms.toAbsoluteTime(LocalContext.current).toString(), 88 style = MaterialTheme.typography.bodyLarge, 89 ) 90 91 if (t.amountRaw != t.amountEffective) { 92 TransactionAmountComposable( 93 label = stringResource(R.string.amount_chosen), 94 amount = t.amountRaw.withSpec(spec), 95 amountType = AmountType.Neutral, 96 ) 97 } 98 99 if (t.amountRaw > t.amountEffective) { 100 val fee = t.amountRaw - t.amountEffective 101 TransactionAmountComposable( 102 label = stringResource(id = R.string.amount_fee), 103 amount = fee.withSpec(spec), 104 amountType = AmountType.Negative, 105 ) 106 } 107 108 TransactionAmountComposable( 109 label = stringResource(id = R.string.amount_total), 110 amount = t.amountEffective.withSpec(spec), 111 amountType = AmountType.Positive, 112 ) 113 114 WithdrawalActions(t, 115 mainQrCode = qrCode, 116 onConfirmKyc = onConfirmKyc, 117 onConfirmBank = onConfirmBank, 118 onConfirmManual = onConfirmManual, 119 onShowQrCodes = onShowQrCodes, 120 ) 121 122 if (t.exchangeBaseUrl != null) { 123 TransactionInfoComposable( 124 label = stringResource(id = R.string.withdraw_exchange), 125 info = cleanExchange(t.exchangeBaseUrl), 126 marquee = true, 127 ) 128 } 129 130 TransitionsComposable(t, devMode, onTransition) 131 132 if (devMode && t.error != null) { 133 ErrorTransactionButton(error = t.error) 134 } 135 136 BottomInsetsSpacer() 137 } 138 } 139 140 private val previewWithdrawalTx = TransactionWithdrawal( 141 transactionId = "transactionId", 142 timestamp = Timestamp.fromMillis(System.currentTimeMillis() - 360 * 60 * 1000), 143 txState = TransactionState(Pending, TransactionMinorState.ExchangeWaitReserve), 144 txActions = listOf(Retry, Suspend, Abort), 145 exchangeBaseUrl = "https://exchange.demo.taler.net/", 146 withdrawalDetails = ManualTransfer( 147 exchangeCreditAccountDetails = listOf( 148 WithdrawalExchangeAccountDetails( 149 paytoUri = "payto://IBAN/1231231231", 150 transferAmount = Amount.fromJSONString("NETZBON:42.23"), 151 status = WithdrawalExchangeAccountDetails.Status.Ok, 152 currencySpecification = CurrencySpecification( 153 name = "NETZBON", 154 numFractionalInputDigits = 2, 155 numFractionalNormalDigits = 2, 156 numFractionalTrailingZeroDigits = 2, 157 altUnitNames = mapOf(0 to "NETZBON"), 158 ), 159 ), 160 ), 161 reserveClosingDelay = RelativeTime.fromMillis(1000), 162 ), 163 amountRaw = Amount.fromString("TESTKUDOS", "42.23"), 164 amountEffective = Amount.fromString("TESTKUDOS", "42.1337"), 165 error = TalerErrorInfo(code = TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED), 166 scopes = listOf(ScopeInfo.Exchange( 167 currency = "TESTKUDOS", 168 url = "exchange.test.taler.net", 169 )) 170 ) 171 172 @Preview 173 @Composable 174 fun TransactionWithdrawalComposableSingleQrPreview() { 175 Surface { 176 TransactionWithdrawalComposable( 177 t = previewWithdrawalTx, 178 devMode = true, 179 qrCode = QrCodeSpec(QrCodeSpec.Type.SPC, "something"), 180 spec = null, 181 onConfirmKyc = {}, 182 onConfirmBank = {}, 183 onConfirmManual = {}, 184 onShowQrCodes = {}, 185 onTransition = {}, 186 ) 187 } 188 } 189 190 @Preview 191 @Composable 192 fun TransactionWithdrawalComposableMultiQrPreview() { 193 Surface { 194 TransactionWithdrawalComposable( 195 t = previewWithdrawalTx, 196 devMode = true, 197 qrCode = null, 198 spec = null, 199 onConfirmKyc = {}, 200 onConfirmBank = {}, 201 onConfirmManual = {}, 202 onShowQrCodes = {}, 203 onTransition = {}, 204 ) 205 } 206 }