taler-android

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

ExpandableCard.kt (5619B)


      1 /*
      2  * This file is part of GNU Taler
      3  * (C) 2024 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.compose
     18 
     19 import androidx.compose.animation.animateContentSize
     20 import androidx.compose.animation.core.animateFloatAsState
     21 import androidx.compose.foundation.clickable
     22 import androidx.compose.foundation.layout.Arrangement
     23 import androidx.compose.foundation.layout.Column
     24 import androidx.compose.foundation.layout.ColumnScope
     25 import androidx.compose.foundation.layout.Row
     26 import androidx.compose.foundation.layout.RowScope
     27 import androidx.compose.foundation.layout.fillMaxWidth
     28 import androidx.compose.foundation.layout.padding
     29 import androidx.compose.material.icons.Icons
     30 import androidx.compose.material.icons.filled.KeyboardArrowDown
     31 import androidx.compose.material3.HorizontalDivider
     32 import androidx.compose.material3.Icon
     33 import androidx.compose.material3.IconButton
     34 import androidx.compose.material3.MaterialTheme
     35 import androidx.compose.material3.OutlinedCard
     36 import androidx.compose.material3.ProvideTextStyle
     37 import androidx.compose.material3.Text
     38 import androidx.compose.runtime.Composable
     39 import androidx.compose.runtime.getValue
     40 import androidx.compose.runtime.mutableStateOf
     41 import androidx.compose.runtime.remember
     42 import androidx.compose.runtime.setValue
     43 import androidx.compose.ui.Alignment
     44 import androidx.compose.ui.Modifier
     45 import androidx.compose.ui.draw.rotate
     46 import androidx.compose.ui.platform.LocalContext
     47 import androidx.compose.ui.tooling.preview.Preview
     48 import androidx.compose.ui.unit.dp
     49 import androidx.core.content.ContextCompat
     50 import net.taler.wallet.R
     51 
     52 @Composable
     53 fun ExpandableCard(
     54     modifier: Modifier = Modifier,
     55     expanded: Boolean = false,
     56     section: Boolean = false, // card or section?
     57     setExpanded: (expanded: Boolean) -> Unit,
     58     header: @Composable RowScope.() -> Unit,
     59     content: @Composable ColumnScope.() -> Unit,
     60 ) {
     61     val rotationState by animateFloatAsState(
     62         targetValue = if (expanded) 180f else 0f,
     63         label = "Rotation state of expand icon button",
     64     )
     65 
     66     val body = @Composable {
     67         Column(
     68             modifier = Modifier
     69                 .fillMaxWidth()
     70                 .animateContentSize() // edit animation here
     71         ) {
     72             Row(
     73                 modifier = Modifier
     74                     .fillMaxWidth()
     75                     .clickable { setExpanded(!expanded) }
     76                     .padding(start = 16.dp, top = 4.dp, bottom = 4.dp, end  = 8.dp),
     77                 verticalAlignment = Alignment.CenterVertically,
     78                 horizontalArrangement = Arrangement.SpaceBetween,
     79             ) {
     80                 ProvideTextStyle(
     81                     if (section) {
     82                         MaterialTheme.typography.titleLarge
     83                     } else {
     84                         MaterialTheme.typography.titleMedium
     85                     },
     86                 ) {
     87                     header()
     88                 }
     89 
     90                 IconButton(
     91                     modifier = Modifier.rotate(rotationState),
     92                     onClick = { setExpanded(!expanded) }
     93                 ) {
     94                     Icon(
     95                         imageVector = Icons.Default.KeyboardArrowDown,
     96                         contentDescription = "Drop Down Arrow"
     97                     )
     98                 }
     99             }
    100 
    101             if (expanded) {
    102                 content()
    103             }
    104         }
    105     }
    106 
    107     if (section) {
    108         Column {
    109             body()
    110             HorizontalDivider()
    111         }
    112     } else {
    113         OutlinedCard(
    114             modifier = modifier.cardPaddings(),
    115             onClick = { setExpanded(!expanded) }
    116         ) {
    117             body()
    118         }
    119     }
    120 }
    121 
    122 @Composable
    123 fun ExpandableSection(
    124     modifier: Modifier = Modifier,
    125     expanded: Boolean = false,
    126     setExpanded: (expanded: Boolean) -> Unit,
    127     header: @Composable RowScope.() -> Unit,
    128     content: @Composable ColumnScope.() -> Unit,
    129 ) {
    130     ExpandableCard(
    131         modifier = modifier,
    132         expanded = expanded,
    133         section = true,
    134         setExpanded = setExpanded,
    135         header = header,
    136         content = content,
    137     )
    138 }
    139 
    140 @Preview
    141 @Composable
    142 fun ExpandableCardPreview(
    143     section: Boolean = false,
    144 ) {
    145     val context = LocalContext.current
    146 
    147     TalerSurface {
    148         var expanded by remember { mutableStateOf(true) }
    149         ExpandableCard(
    150             expanded = expanded,
    151             setExpanded = { expanded = it },
    152             section = section,
    153             header = { Text("Swiss QR") },
    154             content = {
    155                 QrCodeUriComposable(
    156                     qrData = "taler://withdraw-exchange",
    157                     clipboardLabel = "",
    158                     params = QrCodeParams.Custom(
    159                         centerLogo = ContextCompat.getDrawable(context, R.drawable.ic_swiss_qr),
    160                     ),
    161                     showContents = false,
    162                 )
    163             }
    164         )
    165     }
    166 }
    167 
    168 @Preview
    169 @Composable
    170 fun ExpandableSectionPreview() {
    171     ExpandableCardPreview(true)
    172 }