taler-android

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

SetDonauScreen.kt (7360B)


      1 /*
      2  * This file is part of GNU Taler
      3  * (C) 2026 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.layout.Column
     20 import androidx.compose.foundation.layout.fillMaxSize
     21 import androidx.compose.foundation.layout.fillMaxWidth
     22 import androidx.compose.foundation.layout.padding
     23 import androidx.compose.foundation.rememberScrollState
     24 import androidx.compose.foundation.text.KeyboardActions
     25 import androidx.compose.foundation.text.KeyboardOptions
     26 import androidx.compose.foundation.verticalScroll
     27 import androidx.compose.material3.Button
     28 import androidx.compose.material3.OutlinedTextField
     29 import androidx.compose.material3.Text
     30 import androidx.compose.runtime.Composable
     31 import androidx.compose.runtime.LaunchedEffect
     32 import androidx.compose.runtime.getValue
     33 import androidx.compose.runtime.livedata.observeAsState
     34 import androidx.compose.runtime.mutableStateOf
     35 import androidx.compose.runtime.remember
     36 import androidx.compose.runtime.setValue
     37 import androidx.compose.ui.Alignment
     38 import androidx.compose.ui.Modifier
     39 import androidx.compose.ui.focus.FocusDirection
     40 import androidx.compose.ui.platform.LocalFocusManager
     41 import androidx.compose.ui.platform.LocalSoftwareKeyboardController
     42 import androidx.compose.ui.res.stringResource
     43 import androidx.compose.ui.text.TextStyle
     44 import androidx.compose.ui.text.font.FontFamily.Companion.Monospace
     45 import androidx.compose.ui.text.input.ImeAction
     46 import androidx.compose.ui.tooling.preview.Preview
     47 import androidx.compose.ui.unit.dp
     48 import net.taler.wallet.BottomInsetsSpacer
     49 import net.taler.wallet.R
     50 import net.taler.wallet.backend.TalerErrorInfo
     51 import net.taler.wallet.compose.ErrorComposable
     52 import net.taler.wallet.compose.GlobalScaffold
     53 import net.taler.wallet.compose.LoadingScreen
     54 import net.taler.wallet.compose.TalerSurface
     55 import net.taler.wallet.compose.collectAsStateLifecycleAware
     56 import net.taler.wallet.donau.GetDonauStatus.Error
     57 import net.taler.wallet.donau.GetDonauStatus.Loading
     58 import net.taler.wallet.donau.GetDonauStatus.None
     59 import net.taler.wallet.donau.GetDonauStatus.Success
     60 import net.taler.wallet.main.MainViewModel
     61 
     62 @Composable
     63 fun SetDonauScreen(
     64     model: MainViewModel,
     65     donauBaseUrl: String?,
     66     onShowMessage: (String) -> Unit,
     67     onShowError: (TalerErrorInfo) -> Unit,
     68     onNavigateBack: () -> Unit,
     69 ) {
     70     val donauManager = model.donauManager
     71     val donauStatus by donauManager.donauStatus.collectAsStateLifecycleAware()
     72     val devMode by model.devMode.observeAsState(false)
     73 
     74     LaunchedEffect(Unit) {
     75         donauManager.getDonau()
     76     }
     77 
     78     val readyMessage = stringResource(id = R.string.donau_ready)
     79 
     80     TalerSurface {
     81         GlobalScaffold(
     82             model = model,
     83             modifier = Modifier.fillMaxSize(),
     84             onNavigateBack = onNavigateBack,
     85             title = { Text(stringResource(R.string.donau_title)) },
     86         ) { paddingValues ->
     87             when (val status = donauStatus) {
     88                 Loading, None -> LoadingScreen(Modifier.padding(paddingValues))
     89                 is Success -> SetDonauComposable(
     90                     modifier = Modifier.padding(paddingValues),
     91                     donauInfo = status.donauInfo,
     92                     initialUrl = donauBaseUrl,
     93                     onSetDonauInfo = { info ->
     94                         donauManager.setDonau(
     95                             info,
     96                             {
     97                                 onShowMessage(readyMessage)
     98                                 onNavigateBack()
     99                             },
    100                             { error -> onShowError(error) }
    101                         )
    102                     },
    103                 )
    104 
    105                 is Error -> ErrorComposable(
    106                     error = status.error,
    107                     modifier = Modifier
    108                         .fillMaxSize()
    109                         .padding(paddingValues)
    110                         .verticalScroll(rememberScrollState()),
    111                     devMode = devMode,
    112                 )
    113             }
    114         }
    115     }
    116 }
    117 
    118 @Composable
    119 fun SetDonauComposable(
    120     donauInfo: DonauInfo?,
    121     onSetDonauInfo: (info: DonauInfo) -> Unit,
    122     modifier: Modifier = Modifier,
    123     initialUrl: String? = null,
    124 ) {
    125     val focusManager = LocalFocusManager.current
    126     val keyboardController = LocalSoftwareKeyboardController.current
    127     var donauBaseUrl by remember { mutableStateOf(initialUrl ?: donauInfo?.donauBaseUrl ?: "") }
    128     var taxPayerId by remember { mutableStateOf(donauInfo?.taxPayerId ?: "") }
    129 
    130     Column(modifier.fillMaxSize()) {
    131         OutlinedTextField(
    132             modifier = Modifier.padding(
    133                 bottom = 16.dp,
    134                 start = 16.dp,
    135                 end = 16.dp,
    136             ).fillMaxWidth(),
    137             value = donauBaseUrl,
    138             onValueChange = {
    139                 donauBaseUrl = it
    140             },
    141             singleLine = true,
    142             isError = donauBaseUrl.isBlank(),
    143             label = { Text(stringResource(R.string.donau_url)) },
    144             keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
    145             keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) }),
    146         )
    147 
    148         OutlinedTextField(
    149             modifier = Modifier.padding(
    150                 bottom = 16.dp,
    151                 start = 16.dp,
    152                 end = 16.dp,
    153             ).fillMaxWidth(),
    154             value = taxPayerId,
    155             onValueChange = {
    156                 taxPayerId = it
    157             },
    158             singleLine = true,
    159             textStyle = TextStyle(fontFamily = Monospace),
    160             isError = taxPayerId.isBlank(),
    161             label = { Text(stringResource(R.string.donau_id)) },
    162             keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
    163             keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Exit) }),
    164         )
    165 
    166         Button(
    167             modifier = Modifier
    168                 .padding(horizontal = 16.dp)
    169                 .align(Alignment.End),
    170             onClick = {
    171                 focusManager.clearFocus()
    172                 keyboardController?.hide()
    173                 onSetDonauInfo(DonauInfo(
    174                     donauBaseUrl = donauBaseUrl,
    175                     taxPayerId = taxPayerId,
    176                 ))
    177             },
    178             enabled = donauBaseUrl.isNotBlank() &&
    179                     taxPayerId.isNotBlank()
    180         ) {
    181             Text(stringResource(R.string.save))
    182         }
    183 
    184         BottomInsetsSpacer()
    185     }
    186 }
    187 
    188 @Preview
    189 @Composable
    190 fun SetDonauComposablePreview() {
    191     TalerSurface {
    192         SetDonauComposable(
    193             donauInfo = null,
    194             initialUrl = "https://donau.test.taler.net/",
    195             onSetDonauInfo = {},
    196         )
    197     }
    198 }