View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0012084 | Taler | wallet (iOS App) | public | 2026-11-11 01:40 | 2026-11-11 01:40 |
| Reporter | bot-cg [agent] | Assigned To | Resolution deadline | ||
| Implementer | Reviewer | ||||
| Release signed by | Deployed by | ||||
| Verifier | Communicator | CM_7 | |||
| Data protection authority notification required | No | ||||
| CSIRT notification required | No | ||||
| Estimated effort (hours) | Actual effort (hours) | 0 | |||
| Fast-track | No | ||||
| Work package | none | ||||
| Priority | normal | Severity | minor | Reproducibility | have not tried |
| Status | new | Resolution | open | ||
| Summary | 0012084: iOS: the payment screen never shows product images, which Android and the WebExtension display (patch attached) | ||||
| Description | The iOS payment screen lists the order's products (name, description, quantity, price) but never shows the product images that merchants put into the contract (ProductSold.image, a data: URL). Android and the WebExtension show them. What the user sees (origin/master builds of 2026-11-11; an order with two products, each with a 128x128 PNG image): - iOS: "Coffee / Large cappuccino / 2 / 2.00" and "Croissant / Butter croissant / 1 / 1.00", text only (before-ios-1.png). - Android: each product with its thumbnail (tap enlarges it) (before-android-1.png). - WebExtension: each product with a round thumbnail (before-web-1.png). Code (origin/master 674b7915): - TalerWallet1/Views/Sheets/Payment/ChoicesView.swift:178-220: ProductsView never reads product.image. - TalerWallet1/Backend/WalletBackendRequest.swift:154: image is decoded ("product image 128x128 encoded"). - TalerCommon/Helper/Image+fallback.swift:41: Image(imageBase64:) already decodes product.image safely (its comment names product.image); PaymentTransactionView.swift:52-58,79-83 uses it for the merchant logo. References: Android PromptPaymentComposable.kt:354-409; web routes/order-model.ts:10-14,66 and ui/OrderSummary.tsx:17-35. Patch (ios-product-images.patch): a small ProductImageView (decodes once in .task with Image(imageBase64:), 44x44, rounded, hidden from VoiceOver) in front of each product that has an image. No new strings. (The name ProductImage is taken by an unused model struct in ThreeAmountsSection.swift:73.) Verified: GNU_Taler Release builds for the simulator; after-ios-1.png is the same order with the patch. Assisted by LLM | ||||
| Steps To Reproduce | 1. Create an order with products[] that carry "image": "data:image/png;base64,...". 2. Open its taler://pay/ link on iOS: no images. Same order on Android or in the WebExtension: thumbnails. (Automated: wc-stack pay-uri --order-json <order with products and images>.) | ||||
| Tags | No tags attached. | ||||
| Attached Files | ios-product-images.patch (1,692 bytes)
diff --git a/TalerWallet1/Views/Sheets/Payment/ChoicesView.swift b/TalerWallet1/Views/Sheets/Payment/ChoicesView.swift
index dbeb0dca..680ee72c 100644
--- a/TalerWallet1/Views/Sheets/Payment/ChoicesView.swift
+++ b/TalerWallet1/Views/Sheets/Payment/ChoicesView.swift
@@ -175,6 +175,31 @@ struct ChoicesView: View, Sendable {
}
}
// MARK: -
+/// The merchant-supplied product image (a data URL), decoded once
+struct ProductImageView: View {
+ let imageBase64: String
+
+ @State private var image: Image? = nil
+
+ var body: some View {
+ Group {
+ if let image {
+ image
+ .resizable()
+ .aspectRatio(contentMode: .fit)
+ .clipShape(RoundedRectangle(cornerRadius: 6))
+ } else {
+ Color.clear // keeps the view (and its .task) alive until decoded
+ }
+ }
+ .frame(width: 44, height: 44)
+ .accessibilityHidden(true)
+ .task(id: imageBase64) {
+ image = Image(imageBase64: imageBase64)
+ }
+ }
+}
+// MARK: -
struct ProductsView: View, Sendable {
let stack: CallStack
let scope: ScopeInfo?
@@ -188,6 +213,9 @@ struct ProductsView: View, Sendable {
Section {
ForEach(products, id: \.self) { product in
HStack {
+ if let imageBase64 = product.image {
+ ProductImageView(imageBase64: imageBase64)
+ }
VStack(alignment: .leading) {
if let name = product.productName {
Text(name)
| ||||
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-11-11 01:40 | bot-cg | New Issue | |
| 2026-11-11 01:40 | bot-cg | File Added: before-ios-1.png | |
| 2026-11-11 01:40 | bot-cg | File Added: before-android-1.png | |
| 2026-11-11 01:40 | bot-cg | File Added: before-web-1.png | |
| 2026-11-11 01:40 | bot-cg | File Added: after-ios-1.png | |
| 2026-11-11 01:40 | bot-cg | File Added: ios-product-images.patch |