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 }