taler-android

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

commit 39e27b5a32ff76940245db714437531bd7b11878
parent 1d7a64cfab8f7474933f0b8a8695a105a5194d1c
Author: Iván Ávalos <avalos@disroot.org>
Date:   Mon, 25 May 2026 15:37:08 +0200

[wallet] render token merchant name

Diffstat:
Awallet/src/main/java/net/taler/wallet/compose/MerchantAvatar.kt | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mwallet/src/main/java/net/taler/wallet/payment/PromptPaymentComposable.kt | 38++------------------------------------
Mwallet/src/main/java/net/taler/wallet/tokens/TokenListScreen.kt | 16+++++++++++-----
Mwallet/src/main/java/net/taler/wallet/tokens/TokenResponses.kt | 3+++
4 files changed, 100 insertions(+), 41 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/compose/MerchantAvatar.kt b/wallet/src/main/java/net/taler/wallet/compose/MerchantAvatar.kt @@ -0,0 +1,83 @@ +/* + * This file is part of GNU Taler + * (C) 2026 Taler Systems S.A. + * + * GNU Taler is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +package net.taler.wallet.compose + +import android.graphics.Bitmap +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Store +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import net.taler.common.Merchant +import net.taler.lib.android.base64Bitmap + +@Composable +fun MerchantAvatar( + merchantInfo: Merchant?, + modifier: Modifier = Modifier, + size: Dp = 60.dp, + onClickImage: ((Bitmap) -> Unit) = {}, +) { + val logo = remember(merchantInfo?.logo) { merchantInfo?.logo?.base64Bitmap } + + Box( + modifier + .size(size) + .background( + shape = CircleShape, + color = if (logo != null) { + Color.White + } else { + MaterialTheme.colorScheme.surfaceVariant + }, + ) + .clip(CircleShape) + .clickable { if (logo != null) onClickImage(logo) }, + contentAlignment = Alignment.Center, + ) { + if (logo != null) { + Image( + logo.asImageBitmap(), + modifier = Modifier.fillMaxSize(), + contentDescription = null, + ) + } else { + Icon( + Icons.Default.Store, + modifier = Modifier.fillMaxSize(0.54f), + tint = MaterialTheme.colorScheme.onSurfaceVariant, + contentDescription = null, + ) + } + } +} +\ No newline at end of file diff --git a/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentComposable.kt b/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentComposable.kt @@ -93,6 +93,7 @@ import net.taler.wallet.R import net.taler.wallet.cleanExchange import net.taler.wallet.compose.BottomButtonBox import net.taler.wallet.compose.ExpandableSection +import net.taler.wallet.compose.MerchantAvatar import net.taler.wallet.compose.TalerSurface import net.taler.wallet.compose.cardPaddings import net.taler.wallet.donau.DonauInfo @@ -265,42 +266,7 @@ fun MerchantSection( horizontalAlignment = CenterHorizontally, ) { // MERCHANT LOGO - val logo = remember(merchant.logo) { - merchant.logo?.base64Bitmap - } - - Box( - Modifier - .size(60.dp) - .background( - shape = CircleShape, - color = if (logo != null) { - Color.White - } else { - MaterialTheme.colorScheme.surfaceVariant - }, - ) - .clip(CircleShape) - .clickable { if (logo != null) onClickImage(logo) }, - contentAlignment = Alignment.Center, - ) { - if (logo != null) { - Image( - logo.asImageBitmap(), - modifier = Modifier.fillMaxSize(), - contentDescription = null, - ) - } else { - Icon( - Icons.Default.Store, - modifier = Modifier - .padding(16.dp) - .fillMaxSize(), - tint = MaterialTheme.colorScheme.onSurfaceVariant, - contentDescription = null, - ) - } - } + MerchantAvatar(contractTerms.merchant, onClickImage = onClickImage) // MERCHANT NAME Text( diff --git a/wallet/src/main/java/net/taler/wallet/tokens/TokenListScreen.kt b/wallet/src/main/java/net/taler/wallet/tokens/TokenListScreen.kt @@ -16,7 +16,6 @@ package net.taler.wallet.tokens -import androidx.compose.animation.animateContentSize import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -50,9 +49,11 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch +import net.taler.common.Merchant import net.taler.common.RelativeTime import net.taler.common.TalerUtils import net.taler.common.Timestamp +import net.taler.lib.android.base64Bitmap import net.taler.lib.android.toAbsoluteTime import net.taler.wallet.NavigateCallback import net.taler.wallet.R @@ -60,6 +61,7 @@ import net.taler.wallet.cleanExchange import net.taler.wallet.compose.EmptyComposable import net.taler.wallet.compose.ErrorComposable import net.taler.wallet.compose.GlobalScaffold +import net.taler.wallet.compose.MerchantAvatar import net.taler.wallet.compose.TalerSurface import net.taler.wallet.compose.cardPaddings import net.taler.wallet.compose.collectAsStateLifecycleAware @@ -195,6 +197,7 @@ fun DiscountCard(pass: DiscountListDetail) { OutlinedCard(Modifier.cardPaddings()) { Column { ListItem( + // leadingContent = { MerchantAvatar(pass.merchantInfo, size = 40.dp) }, headlineContent = { Text(pass.name, style = MaterialTheme.typography.headlineMedium .copy(fontWeight = FontWeight.Medium)) @@ -210,10 +213,10 @@ fun DiscountCard(pass: DiscountListDetail) { ) Text( - // TODO: expose merchantName in wallet-core stringResource( R.string.pass_issuer, - cleanExchange(pass.merchantBaseUrl) + pass.merchantInfo?.name + ?: cleanExchange(pass.merchantBaseUrl), ), modifier = Modifier.padding(top = 5.dp), style = MaterialTheme.typography.bodySmall, @@ -255,6 +258,7 @@ fun PassCard(pass: SubscriptionListDetail) { OutlinedCard(Modifier.cardPaddings()) { Column { ListItem( + // leadingContent = { MerchantAvatar(pass.merchantInfo, size = 40.dp) }, headlineContent = { Text(pass.name, style = MaterialTheme.typography.headlineMedium .copy(fontWeight = FontWeight.Medium)) @@ -270,10 +274,10 @@ fun PassCard(pass: SubscriptionListDetail) { ) Text( - // TODO: expose merchantName in wallet-core stringResource( R.string.pass_issuer, - cleanExchange(pass.merchantBaseUrl) + pass.merchantInfo?.name + ?: cleanExchange(pass.merchantBaseUrl), ), modifier = Modifier.padding(top = 5.dp), style = MaterialTheme.typography.bodySmall, @@ -361,6 +365,7 @@ fun DiscountListPreview() { tokenFamilyHash = "", tokenIssuePubHash = "", merchantBaseUrl = "https://backend.demo.taler.net/", + merchantInfo = Merchant(name = "Test Merchant"), name = "20% off", description = "valid for fruits", descriptionI18n = mapOf(), @@ -401,6 +406,7 @@ fun PassListPreview() { tokenFamilyHash = "", tokenIssuePubHash = "", merchantBaseUrl = "https://backend.demo.taler.net/", + merchantInfo = Merchant(name = "Test Merchant"), name = "Premium pass", description = "Provides you access to this mega description", descriptionI18n = mapOf(), diff --git a/wallet/src/main/java/net/taler/wallet/tokens/TokenResponses.kt b/wallet/src/main/java/net/taler/wallet/tokens/TokenResponses.kt @@ -17,6 +17,7 @@ package net.taler.wallet.tokens import kotlinx.serialization.Serializable +import net.taler.common.Merchant import net.taler.common.Timestamp @Serializable @@ -24,6 +25,7 @@ data class DiscountListDetail( val tokenFamilyHash: String, val tokenIssuePubHash: String, val merchantBaseUrl: String, + val merchantInfo: Merchant? = null, val name: String, val description: String, val descriptionI18n: Map<String, String>, @@ -52,6 +54,7 @@ data class SubscriptionListDetail( val tokenFamilyHash: String, val tokenIssuePubHash: String, val merchantBaseUrl: String, + val merchantInfo: Merchant? = null, val name: String, val description: String, val descriptionI18n: Map<String, String>,