taler-android

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

TransitionsComposable.kt (7994B)


      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.transactions
     18 
     19 import androidx.compose.foundation.layout.Arrangement.Center
     20 import androidx.compose.foundation.layout.Column
     21 import androidx.compose.foundation.layout.ExperimentalLayoutApi
     22 import androidx.compose.foundation.layout.FlowRow
     23 import androidx.compose.foundation.layout.Row
     24 import androidx.compose.foundation.layout.padding
     25 import androidx.compose.foundation.rememberScrollState
     26 import androidx.compose.foundation.verticalScroll
     27 import androidx.compose.material3.AlertDialog
     28 import androidx.compose.material3.Button
     29 import androidx.compose.material3.ButtonDefaults
     30 import androidx.compose.material3.Icon
     31 import androidx.compose.material3.MaterialTheme
     32 import androidx.compose.material3.Text
     33 import androidx.compose.material3.TextButton
     34 import androidx.compose.runtime.Composable
     35 import androidx.compose.runtime.getValue
     36 import androidx.compose.runtime.mutableStateOf
     37 import androidx.compose.runtime.remember
     38 import androidx.compose.runtime.setValue
     39 import androidx.compose.ui.Alignment
     40 import androidx.compose.ui.Modifier
     41 import androidx.compose.ui.platform.LocalContext
     42 import androidx.compose.ui.res.painterResource
     43 import androidx.compose.ui.res.stringResource
     44 import androidx.compose.ui.text.font.FontFamily
     45 import androidx.compose.ui.unit.dp
     46 import androidx.compose.ui.unit.sp
     47 import kotlinx.serialization.json.Json
     48 import net.taler.lib.android.copyToClipBoard
     49 import net.taler.wallet.R
     50 import net.taler.wallet.transactions.TransactionAction.*
     51 
     52 @OptIn(ExperimentalLayoutApi::class)
     53 @Composable
     54 fun TransitionsComposable(
     55     t: Transaction,
     56     devMode: Boolean,
     57     onTransition: (t: TransactionAction) -> Unit,
     58 ) {
     59     var showDialog by remember { mutableStateOf(false) }
     60 
     61     if (showDialog) {
     62         @Suppress("OPT_IN_USAGE")
     63         val json = Json {
     64             prettyPrint = true
     65             prettyPrintIndent = "  "
     66         }
     67         val message = json.encodeToString(t)
     68         AlertDialog(
     69             onDismissRequest = {
     70                 showDialog = false
     71             },
     72             text = {
     73                 val scrollState = rememberScrollState()
     74                 Column(
     75                     modifier = Modifier.verticalScroll(scrollState),
     76                 ) {
     77                     Text(
     78                         fontFamily = FontFamily.Monospace,
     79                         fontSize = 10.sp,
     80                         text = message,
     81                     )
     82                 }
     83             },
     84             dismissButton = {
     85                 TextButton(onClick = {
     86                     showDialog = false
     87                 }) {
     88                     Text(stringResource(R.string.close))
     89                 }
     90             },
     91             confirmButton = {
     92                 val context = LocalContext.current
     93                 val label = stringResource(R.string.nav_error)
     94                 TextButton(onClick = {
     95                     copyToClipBoard(context, label, message)
     96                 }) {
     97                     Text(stringResource(R.string.copy))
     98                 }
     99             })
    100     }
    101     
    102     FlowRow(horizontalArrangement = Center) {
    103         t.txActions.forEach {
    104             if (it in arrayOf(Resume, Suspend, Retry)) {
    105                 if (devMode) TransitionComposable(it, onTransition)
    106             } else {
    107                 TransitionComposable(it, onTransition)
    108             }
    109         }
    110 
    111         if (devMode) Button(
    112             modifier = Modifier.padding(16.dp),
    113             onClick = { showDialog = true },
    114         ) {
    115             Text(stringResource(R.string.observability_show_json))
    116         }
    117     }
    118 }
    119 
    120 @Composable
    121 fun TransitionComposable(t: TransactionAction, onClick: (t: TransactionAction) -> Unit) {
    122     var showConfirmDialog by remember { mutableStateOf(false) }
    123     if (showConfirmDialog) {
    124         AlertDialog(
    125             onDismissRequest = { showConfirmDialog = false },
    126             title = { Text(stringResource(R.string.transactions_delete_dialog_title)) },
    127             text = { Text(stringResource(R.string.transactions_delete_dialog_message)) },
    128             confirmButton = {
    129                 TextButton(onClick = {
    130                     showConfirmDialog = false
    131                     onClick(t)
    132                 }) {
    133                     Text(stringResource(R.string.transactions_delete))
    134                 }
    135             },
    136             dismissButton = {
    137                 TextButton(onClick = { showConfirmDialog = false }) {
    138                     Text(stringResource(R.string.cancel))
    139                 }
    140             }
    141         )
    142     }
    143 
    144     Button(
    145         modifier = Modifier.padding(16.dp),
    146         colors = ButtonDefaults.buttonColors(
    147             containerColor = when (t) {
    148                 Delete -> MaterialTheme.colorScheme.error
    149                 Retry -> MaterialTheme.colorScheme.primary
    150                 Abort -> MaterialTheme.colorScheme.error
    151                 Fail -> MaterialTheme.colorScheme.error
    152                 Resume -> MaterialTheme.colorScheme.primary
    153                 Suspend -> MaterialTheme.colorScheme.primary
    154             }
    155         ),
    156         onClick = {
    157             if (t == Delete) {
    158                 showConfirmDialog = true
    159             } else {
    160                 onClick(t)
    161             }
    162         },
    163     ) {
    164         Row(verticalAlignment = Alignment.CenterVertically) {
    165             Icon(
    166                 painter = when (t) {
    167                     Delete -> painterResource(id = R.drawable.ic_delete)
    168                     Retry -> painterResource(id = R.drawable.ic_retry)
    169                     Abort -> painterResource(id = R.drawable.ic_cancel)
    170                     Fail -> painterResource(id = R.drawable.ic_fail)
    171                     Resume -> painterResource(id = R.drawable.ic_resume)
    172                     Suspend -> painterResource(id = R.drawable.ic_suspend)
    173                 },
    174                 contentDescription = null,
    175                 tint = when (t) {
    176                     Delete -> MaterialTheme.colorScheme.onError
    177                     Retry -> MaterialTheme.colorScheme.onPrimary
    178                     Abort -> MaterialTheme.colorScheme.onError
    179                     Fail -> MaterialTheme.colorScheme.onError
    180                     Resume -> MaterialTheme.colorScheme.onPrimary
    181                     Suspend -> MaterialTheme.colorScheme.onPrimary
    182                 },
    183             )
    184             Text(
    185                 modifier = Modifier.padding(start = 8.dp),
    186                 text = when (t) {
    187                     Delete -> stringResource(R.string.transactions_delete)
    188                     Retry -> stringResource(R.string.transactions_retry)
    189                     Abort -> stringResource(R.string.transactions_abort)
    190                     Fail -> stringResource(R.string.transactions_fail)
    191                     Resume -> stringResource(R.string.transactions_resume)
    192                     Suspend -> stringResource(R.string.transactions_suspend)
    193                 },
    194                 color = when (t) {
    195                     Delete -> MaterialTheme.colorScheme.onError
    196                     Retry -> MaterialTheme.colorScheme.onPrimary
    197                     Abort -> MaterialTheme.colorScheme.onError
    198                     Fail -> MaterialTheme.colorScheme.onError
    199                     Resume -> MaterialTheme.colorScheme.onPrimary
    200                     Suspend -> MaterialTheme.colorScheme.onPrimary
    201                 },
    202             )
    203         }
    204     }
    205 }