taler-android

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

TransactionPeerPushDebit.kt (6731B)


      1 /*
      2  * This file is part of GNU Taler
      3  * (C) 2022 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.peer
     18 
     19 import androidx.compose.foundation.layout.ColumnScope
     20 import androidx.compose.foundation.layout.Spacer
     21 import androidx.compose.foundation.layout.aspectRatio
     22 import androidx.compose.foundation.layout.fillMaxWidth
     23 import androidx.compose.foundation.layout.height
     24 import androidx.compose.foundation.layout.padding
     25 import androidx.compose.material3.CircularProgressIndicator
     26 import androidx.compose.material3.MaterialTheme
     27 import androidx.compose.material3.Text
     28 import androidx.compose.runtime.Composable
     29 import androidx.compose.ui.Alignment.Companion.CenterHorizontally
     30 import androidx.compose.ui.Modifier
     31 import androidx.compose.ui.res.stringResource
     32 import androidx.compose.ui.text.style.TextAlign
     33 import androidx.compose.ui.tooling.preview.Preview
     34 import androidx.compose.ui.unit.dp
     35 import net.taler.common.Amount
     36 import net.taler.common.CurrencySpecification
     37 import net.taler.common.Timestamp
     38 import net.taler.wallet.R
     39 import net.taler.wallet.balances.ScopeInfo
     40 import net.taler.wallet.compose.QrCodeParams
     41 import net.taler.wallet.compose.QrCodeUriComposable
     42 import net.taler.wallet.compose.TalerSurface
     43 import net.taler.wallet.transactions.AmountType
     44 import net.taler.wallet.transactions.PeerInfoShort
     45 import net.taler.wallet.transactions.TransactionAction.Abort
     46 import net.taler.wallet.transactions.TransactionAction.Retry
     47 import net.taler.wallet.transactions.TransactionAction.Suspend
     48 import net.taler.wallet.transactions.TransactionAmountComposable
     49 import net.taler.wallet.transactions.TransactionInfoComposable
     50 import net.taler.wallet.transactions.TransactionMajorState.Done
     51 import net.taler.wallet.transactions.TransactionMajorState.Pending
     52 import net.taler.wallet.transactions.TransactionMinorState.CreatePurse
     53 import net.taler.wallet.transactions.TransactionMinorState.KycRequired
     54 import net.taler.wallet.transactions.TransactionMinorState.Ready
     55 import net.taler.wallet.transactions.TransactionPeerComposable
     56 import net.taler.wallet.transactions.TransactionPeerPushDebit
     57 import net.taler.wallet.transactions.TransactionState
     58 
     59 @Composable
     60 fun ColumnScope.TransactionPeerPushDebitComposable(t: TransactionPeerPushDebit, spec: CurrencySpecification?) {
     61     if (t.error == null) PeerQrCode(
     62         state = t.txState,
     63         amount = t.amountRaw.withSpec(spec),
     64         talerUri = t.talerUri,
     65         instructionResId = R.string.send_peer_payment_instruction,
     66     )
     67 
     68     TransactionAmountComposable(
     69         label = stringResource(id = R.string.transaction_order_total),
     70         amount = t.amountRaw.withSpec(spec),
     71         amountType = AmountType.Neutral,
     72     )
     73 
     74     if (t.amountEffective > t.amountRaw) {
     75         val fee = t.amountEffective - t.amountRaw
     76         TransactionAmountComposable(
     77             label = stringResource(id = R.string.amount_fee),
     78             amount = fee.withSpec(spec),
     79             amountType = AmountType.Negative,
     80         )
     81     }
     82 
     83     TransactionAmountComposable(
     84         label = if (t.txState.major == Done) {
     85             stringResource(id = R.string.amount_sent)
     86         } else {
     87             stringResource(R.string.amount_send)
     88         },
     89         amount = t.amountEffective.withSpec(spec),
     90         amountType = AmountType.Negative,
     91     )
     92 
     93     TransactionInfoComposable(
     94         label = stringResource(id = R.string.send_peer_purpose),
     95         info = t.info.summary ?: "",
     96     )
     97 }
     98 
     99 @Composable
    100 fun ColumnScope.PeerQrCode(
    101     state: TransactionState,
    102     amount: Amount,
    103     talerUri: String?,
    104     instructionResId: Int,
    105 ) {
    106     if (state == TransactionState(Pending) && state.minor != KycRequired) {
    107         Text(
    108             modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 8.dp),
    109             style = MaterialTheme.typography.bodyLarge,
    110             text = stringResource(id = instructionResId, amount.toString()),
    111             textAlign = TextAlign.Center,
    112         )
    113 
    114         if (state.minor == Ready && talerUri != null) {
    115             Spacer(Modifier.height(8.dp))
    116             QrCodeUriComposable(
    117                 modifier = Modifier.padding(horizontal = 16.dp),
    118                 qrData = talerUri,
    119                 clipboardLabel = "Push payment",
    120                 params = QrCodeParams.Taler,
    121                 buttonText = stringResource(id = R.string.copy),
    122             ) {
    123                 Text(
    124                     modifier = Modifier
    125                         .padding(top = 12.dp)
    126                         .padding(horizontal = 16.dp),
    127                     style = MaterialTheme.typography.bodyLarge,
    128                     text = stringResource(id = R.string.receive_peer_invoice_uri),
    129                 )
    130             }
    131         } else CircularProgressIndicator(
    132             modifier = Modifier
    133                 .padding(45.dp)
    134                 .fillMaxWidth()
    135                 .aspectRatio(1f)
    136                 .align(CenterHorizontally),
    137         )
    138     }
    139 }
    140 
    141 @Preview
    142 @Composable
    143 fun TransactionPeerPushDebitPreview(loading: Boolean = false) {
    144     val t = TransactionPeerPushDebit(
    145         transactionId = "transactionId",
    146         timestamp = Timestamp.fromMillis(System.currentTimeMillis() - 360 * 60 * 1000),
    147         txState = TransactionState(Pending, if (loading) CreatePurse else Ready),
    148         txActions = listOf(Retry, Suspend, Abort),
    149         exchangeBaseUrl = "https://exchange.example.org/",
    150         amountRaw = Amount.fromString("TESTKUDOS", "42.1337"),
    151         amountEffective = Amount.fromString("TESTKUDOS", "42.23"),
    152         info = PeerInfoShort(
    153             expiration = Timestamp.fromMillis(System.currentTimeMillis() + 60 * 60 * 1000),
    154             summary = "test invoice",
    155         ),
    156         talerUri = "https://exchange.example.org/peer/pull/credit",
    157         scopes = listOf(ScopeInfo.Exchange(
    158             currency = "TESTKUDOS",
    159             url = "exchange.test.taler.net",
    160         ))
    161     )
    162 
    163     TalerSurface {
    164         TransactionPeerComposable(t, true, null, Modifier, {}) {}
    165     }
    166 }
    167 
    168 @Preview
    169 @Composable
    170 fun TransactionPeerPushDebitLoadingPreview() {
    171     TransactionPeerPushDebitPreview(loading = true)
    172 }