taler-android

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

ExchangeShoppingScreen.kt (5725B)


      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.exchanges
     18 
     19 import androidx.compose.foundation.basicMarquee
     20 import androidx.compose.foundation.layout.Box
     21 import androidx.compose.foundation.layout.fillMaxSize
     22 import androidx.compose.foundation.layout.Column
     23 import androidx.compose.foundation.layout.fillMaxWidth
     24 import androidx.compose.foundation.layout.padding
     25 import androidx.compose.foundation.rememberScrollState
     26 import androidx.compose.foundation.verticalScroll
     27 import androidx.compose.material.icons.Icons
     28 import androidx.compose.material.icons.filled.Link
     29 import androidx.compose.material3.Icon
     30 import androidx.compose.material3.Text
     31 import androidx.compose.runtime.Composable
     32 import androidx.compose.runtime.getValue
     33 import androidx.compose.runtime.livedata.observeAsState
     34 import androidx.compose.runtime.remember
     35 import androidx.compose.ui.Alignment
     36 import androidx.compose.ui.Modifier
     37 import androidx.compose.ui.graphics.Color
     38 import androidx.compose.ui.platform.LocalContext
     39 import androidx.compose.ui.res.stringResource
     40 import androidx.compose.ui.tooling.preview.Preview
     41 import androidx.compose.ui.unit.dp
     42 import net.taler.wallet.BottomInsetsSpacer
     43 import net.taler.wallet.R
     44 import net.taler.wallet.balances.BalanceState
     45 import net.taler.wallet.compose.EmptyComposable
     46 import net.taler.wallet.compose.GlobalScaffold
     47 import net.taler.wallet.compose.LoadingScreen
     48 import net.taler.wallet.compose.Material3MenuGroup
     49 import net.taler.wallet.compose.Material3MenuItemData
     50 import net.taler.wallet.compose.TalerSurface
     51 import net.taler.wallet.compose.collectAsStateLifecycleAware
     52 import net.taler.wallet.getAttrColor
     53 import net.taler.wallet.launchInAppBrowser
     54 import net.taler.wallet.main.MainViewModel
     55 import net.taler.wallet.main.ViewMode
     56 
     57 @Composable
     58 fun ExchangeShoppingScreen(
     59     model: MainViewModel,
     60     onNavigateBack: () -> Unit,
     61 ) {
     62     val viewMode by model.viewMode.collectAsStateLifecycleAware()
     63     val selectedScope = (viewMode as? ViewMode.Transactions)?.selectedScope
     64     val balanceState by model.balanceManager.state.observeAsState(BalanceState.None)
     65 
     66     val selectedBalance = remember(balanceState, selectedScope) {
     67         val balances = (balanceState as? BalanceState.Success)?.balances
     68         selectedScope?.let {
     69             balances?.find { it.scopeInfo == selectedScope }
     70         }
     71     }
     72 
     73     TalerSurface {
     74         GlobalScaffold(
     75             model = model,
     76             modifier = Modifier.fillMaxSize(),
     77             onNavigateBack = onNavigateBack,
     78         ) { paddingValues ->
     79             Box(Modifier.padding(paddingValues)) {
     80                 if (selectedScope == null) {
     81                     EmptyComposable(message = stringResource(R.string.exchange_unselected))
     82                 } else if (selectedBalance == null) {
     83                     LoadingScreen()
     84                 } else {
     85                     ExchangeShoppingComposable(
     86                         currency = selectedBalance.currency,
     87                         shoppingUrls = selectedBalance.shoppingUrls,
     88                     )
     89                 }
     90             }
     91         }
     92     }
     93 }
     94 
     95 @Composable
     96 fun ExchangeShoppingComposable(
     97     currency: String,
     98     shoppingUrls: List<String>,
     99 ) {
    100     val context = LocalContext.current
    101     val linkColor = Color(context.getAttrColor(android.R.attr.textColorLink))
    102 
    103     Column (
    104         modifier = Modifier
    105             .fillMaxWidth()
    106             .verticalScroll(rememberScrollState()),
    107         horizontalAlignment = Alignment.CenterHorizontally,
    108     ) {
    109         Text(
    110             modifier = Modifier.padding(16.dp),
    111             text = stringResource(
    112                 R.string.exchange_shopping_message,
    113                 currency,
    114             ),
    115         )
    116 
    117         Box(Modifier.padding(horizontal = 16.dp)) {
    118             Material3MenuGroup(items = buildList {
    119                 shoppingUrls.forEach { url ->
    120                     add(
    121                         Material3MenuItemData(
    122                             icon = {
    123                                 Icon(
    124                                     Icons.Default.Link,
    125                                     contentDescription = null
    126                                 )
    127                             },
    128                             title = {
    129                                 Text(
    130                                     modifier = Modifier.basicMarquee(),
    131                                     text = url,
    132                                     color = linkColor,
    133                                 )
    134                             },
    135                             onClick = { launchInAppBrowser(context, url) },
    136                         )
    137                     )
    138                 }
    139             })
    140         }
    141 
    142         BottomInsetsSpacer()
    143     }
    144 }
    145 
    146 @Preview
    147 @Composable
    148 fun ExchangeShoppingComposablePreview() {
    149     TalerSurface {
    150         ExchangeShoppingComposable(
    151             currency = "CHF",
    152             shoppingUrls = listOf(
    153                 "https://shopping.taler.net/",
    154                 "https://shopping.taler.ar/",
    155                 "https://shopping.taler-ops.ch/",
    156             )
    157         )
    158     }
    159 }