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:
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>,