taler-android

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

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 }