DonauComposables.kt (6200B)
1 /* 2 * This file is part of GNU Taler 3 * (C) 2025 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.donau 18 19 import androidx.compose.foundation.clickable 20 import androidx.compose.foundation.layout.Column 21 import androidx.compose.foundation.layout.Row 22 import androidx.compose.foundation.layout.fillMaxSize 23 import androidx.compose.foundation.layout.fillMaxWidth 24 import androidx.compose.foundation.layout.padding 25 import androidx.compose.foundation.lazy.LazyColumn 26 import androidx.compose.foundation.lazy.itemsIndexed 27 import androidx.compose.material3.AlertDialog 28 import androidx.compose.material3.Button 29 import androidx.compose.material3.RadioButton 30 import androidx.compose.material3.Switch 31 import androidx.compose.material3.Text 32 import androidx.compose.material3.TextButton 33 import androidx.compose.runtime.Composable 34 import androidx.compose.runtime.getValue 35 import androidx.compose.runtime.mutableIntStateOf 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.res.stringResource 42 import androidx.compose.ui.tooling.preview.Preview 43 import androidx.compose.ui.unit.dp 44 import net.taler.wallet.R 45 import net.taler.wallet.cleanExchange 46 import net.taler.wallet.compose.TalerSurface 47 import net.taler.wallet.compose.WarningLabel 48 import net.taler.wallet.payment.DonauStatus 49 50 @Composable 51 fun DonauToggle( 52 donauStatus: DonauStatus, 53 useDonau: Boolean = false, 54 onToggleDonau: (Boolean) -> Unit, 55 ) { 56 if (donauStatus !is DonauStatus.Unavailable) { 57 Column { 58 Row( 59 Modifier 60 .fillMaxWidth() 61 .padding(9.dp), 62 ) { 63 Text( 64 modifier = Modifier.weight(1f), 65 text = stringResource(R.string.donau_toggle_label), 66 ) 67 68 Switch( 69 checked = useDonau, 70 onCheckedChange = onToggleDonau, 71 ) 72 } 73 74 if (useDonau) when (donauStatus) { 75 is DonauStatus.Mismatch -> { 76 WarningLabel(stringResource( 77 R.string.donau_warning_mismatch, 78 cleanExchange(donauStatus.donauInfo.donauBaseUrl))) 79 } 80 81 is DonauStatus.Unset -> { 82 WarningLabel(stringResource(R.string.donau_warning_unset)) 83 } 84 85 // no need to show anything 86 else -> {} 87 } 88 } 89 } 90 } 91 92 @Composable 93 fun DonauSelector( 94 donauStatus: DonauStatus, 95 showDialog: Boolean, 96 onDismiss: () -> Unit, 97 onSetup: (donauBaseUrl: String) -> Unit, 98 ) { 99 var selectedDonauIndex by remember { mutableIntStateOf(0) } 100 101 val donauUrls = when(donauStatus) { 102 is DonauStatus.Mismatch -> donauStatus.donauUrls 103 is DonauStatus.Unset -> donauStatus.donauUrls 104 else -> return 105 } 106 107 if (showDialog) AlertDialog( 108 title = { Text(stringResource(R.string.donau_selector_title)) }, 109 text = { 110 LazyColumn(modifier = Modifier.fillMaxWidth()) { 111 itemsIndexed(donauUrls) { i, url -> 112 DonauSelectorItem( 113 donauBaseUrl = url, 114 selected = i == selectedDonauIndex, 115 onSelected = { selectedDonauIndex = i }, 116 ) 117 } 118 } 119 }, 120 confirmButton = { 121 Button(onClick = { 122 onSetup(donauUrls[selectedDonauIndex]) 123 onDismiss() 124 }) { 125 Text(stringResource(R.string.donau_selector_confirm)) 126 } 127 }, 128 dismissButton = { 129 TextButton (onClick = { onDismiss() }) { 130 Text(stringResource(R.string.cancel)) 131 } 132 }, 133 onDismissRequest = { 134 onDismiss() 135 }, 136 ) 137 } 138 139 @Composable 140 fun DonauSelectorItem( 141 donauBaseUrl: String, 142 selected: Boolean, 143 onSelected: () -> Unit, 144 ) { 145 Row(Modifier 146 .padding(bottom = 5.dp) 147 .fillMaxWidth() 148 .clickable { onSelected() }, 149 verticalAlignment = Alignment.CenterVertically) { 150 RadioButton( 151 selected = selected, 152 onClick = onSelected, 153 ) 154 155 Text( 156 modifier = Modifier.weight(1f), 157 text = cleanExchange(donauBaseUrl) 158 ) 159 } 160 } 161 162 @Preview 163 @Composable 164 fun DonauSelectorPreview() { 165 TalerSurface { 166 val donauInfo = DonauInfo(donauBaseUrl = "https://donau.test.taler.net/", taxPayerId = "1234") 167 val donauUrls = listOf( 168 "https://donau.head.taler.net/", 169 "https://donau.test.taler.net/", 170 "https://donau.demo.taler.net/", 171 ) 172 173 var donauStatus: DonauStatus by remember { mutableStateOf(DonauStatus.Unset(donauUrls)) } 174 175 Column(Modifier.fillMaxSize()) { 176 Button(onClick = { donauStatus = DonauStatus.Unset(donauUrls) }) { 177 Text("DonauStatus.Unset") 178 } 179 180 Button(onClick = { donauStatus = DonauStatus.Mismatch(donauInfo, donauUrls) }) { 181 Text("DonauStatus.Mismatch") 182 } 183 } 184 185 DonauSelector(donauStatus, 186 showDialog = donauStatus !is DonauStatus.Unavailable, 187 onDismiss = { donauStatus = DonauStatus.Unavailable }, 188 onSetup = { donauStatus = DonauStatus.Unavailable } 189 ) 190 } 191 }