commit 864549b79b76aede5e82b6b2e1b3f7b6a4f1345f
parent 1f9f8ec3957a3a214593df7922a0da40657dbe2e
Author: Iván Ávalos <avalos@disroot.org>
Date: Thu, 24 Oct 2024 22:08:05 +0200
[pos] Render product images
Diffstat:
8 files changed, 85 insertions(+), 17 deletions(-)
diff --git a/merchant-terminal/src/main/java/net/taler/merchantpos/order/OrderAdapter.kt b/merchant-terminal/src/main/java/net/taler/merchantpos/order/OrderAdapter.kt
@@ -19,7 +19,10 @@ package net.taler.merchantpos.order
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.view.ViewGroup
+import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.selection.ItemDetailsLookup
import androidx.recyclerview.selection.ItemKeyProvider
@@ -79,12 +82,22 @@ internal class OrderAdapter : Adapter<OrderViewHolder>() {
private val quantity: TextView = v.findViewById(R.id.quantity)
private val name: TextView = v.findViewById(R.id.name)
private val price: TextView = v.findViewById(R.id.price)
+ private val image: ImageView = v.findViewById(R.id.image)
fun bind(product: ConfigProduct, selected: Boolean) {
v.isActivated = selected
quantity.text = product.quantity.toString()
name.text = product.localizedDescription
price.text = product.totalPrice.amountStr
+
+ // base64 encoded image
+ val bitmap = product.imageBitmap
+ if (bitmap == null) {
+ image.visibility = GONE
+ } else {
+ image.visibility = VISIBLE
+ image.setImageBitmap(bitmap)
+ }
}
}
diff --git a/merchant-terminal/src/main/java/net/taler/merchantpos/order/ProductsFragment.kt b/merchant-terminal/src/main/java/net/taler/merchantpos/order/ProductsFragment.kt
@@ -16,11 +16,16 @@
package net.taler.merchantpos.order
+import android.graphics.BitmapFactory.decodeByteArray
import android.os.Bundle
+import android.util.Base64
import android.view.LayoutInflater
import android.view.View
+import android.view.View.GONE
import android.view.View.INVISIBLE
+import android.view.View.VISIBLE
import android.view.ViewGroup
+import android.widget.ImageView
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
@@ -103,10 +108,21 @@ private class ProductAdapter(
inner class ProductViewHolder(private val v: View) : ViewHolder(v) {
private val name: TextView = v.findViewById(R.id.name)
private val price: TextView = v.findViewById(R.id.price)
+ private val image: ImageView = v.findViewById(R.id.image)
fun bind(product: ConfigProduct) {
name.text = product.localizedDescription
price.text = product.price.amountStr
+
+ // base64 encoded image
+ val bitmap = product.imageBitmap
+ if (bitmap == null) {
+ image.visibility = GONE
+ } else {
+ image.visibility = VISIBLE
+ image.setImageBitmap(bitmap)
+ }
+
v.setOnClickListener { listener.onProductSelected(product) }
}
}
diff --git a/merchant-terminal/src/main/res/layout/list_item_order.xml b/merchant-terminal/src/main/res/layout/list_item_order.xml
@@ -35,6 +35,20 @@
app:layout_constraintVertical_bias="0.0"
tools:text="31" />
+ <ImageView
+ android:id="@+id/image"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_marginHorizontal="10dp"
+ app:layout_constraintTop_toTopOf="@id/name"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/quantity"
+ android:visibility="gone"
+ android:contentDescription="@string/product_image"
+ app:layout_constraintVertical_bias="0.0"
+ tools:visibility="visible"
+ tools:src="@drawable/ic_launcher_background"/>
+
<TextView
android:id="@+id/name"
android:layout_width="0dp"
@@ -43,7 +57,7 @@
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/price"
- app:layout_constraintStart_toEndOf="@+id/quantity"
+ app:layout_constraintStart_toEndOf="@+id/image"
app:layout_constraintTop_toTopOf="parent"
tools:text="An order product item that in some cases could have a very long name" />
diff --git a/merchant-terminal/src/main/res/layout/list_item_product.xml b/merchant-terminal/src/main/res/layout/list_item_product.xml
@@ -29,6 +29,19 @@
android:layout_height="wrap_content"
android:padding="8dp">
+ <ImageView
+ android:id="@+id/image"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:padding="10dp"
+ android:contentDescription="@string/product_image"
+ android:visibility="gone"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ tools:visibility="visible"
+ tools:src="@drawable/ic_launcher_background"/>
+
<TextView
android:id="@+id/name"
android:layout_width="0dp"
@@ -37,7 +50,7 @@
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/image"
tools:text="Steak and two Eggs" />
<TextView
diff --git a/merchant-terminal/src/main/res/values/strings.xml b/merchant-terminal/src/main/res/values/strings.xml
@@ -8,6 +8,8 @@
<string name="menu_settings">Settings</string>
<string name="menu_reload">Reload</string>
+ <string name="product_image">Product image</string>
+
<string name="order_label_title">Order #%s</string>
<!-- The placeholder is the total order amount with currency -->
<string name="order_total">Total: %s</string>
diff --git a/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt b/taler-kotlin-android/src/main/java/net/taler/common/ContractTerms.kt
@@ -16,11 +16,16 @@
package net.taler.common
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory.decodeByteArray
import android.os.Build
+import android.util.Base64
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import net.taler.common.TalerUtils.getLocalizedString
+val REGEX_PRODUCT_IMAGE = Regex("^data:image/(jpeg|png);base64,([A-Za-z0-9+/=]+)$")
+
@Serializable
data class ContractTerms(
val summary: String,
@@ -52,6 +57,16 @@ abstract class Product {
} else {
description
}
+
+ val imageBitmap: Bitmap?
+ get() = image?.let {
+ REGEX_PRODUCT_IMAGE.matchEntire(it)?.let { match ->
+ match.groups[2]?.value?.let { group ->
+ val decodedString = Base64.decode(group, Base64.DEFAULT)
+ decodeByteArray(decodedString, 0, decodedString.size)
+ }
+ }
+ }
}
@Serializable
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
@@ -37,8 +37,6 @@ import net.taler.wallet.payment.PreparePayResponse.InsufficientBalanceResponse
import net.taler.wallet.payment.PreparePayResponse.PaymentPossibleResponse
import org.json.JSONObject
-val REGEX_PRODUCT_IMAGE = Regex("^data:image/(jpeg|png);base64,([A-Za-z0-9+/=]+)$")
-
sealed class PayStatus {
data object None : PayStatus()
data object Loading : PayStatus()
diff --git a/wallet/src/main/java/net/taler/wallet/payment/ProductAdapter.kt b/wallet/src/main/java/net/taler/wallet/payment/ProductAdapter.kt
@@ -18,8 +18,6 @@ package net.taler.wallet.payment
import android.content.Context
import android.graphics.Bitmap
-import android.graphics.BitmapFactory.decodeByteArray
-import android.util.Base64
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
@@ -76,20 +74,19 @@ internal class ProductAdapter(private val listener: ProductImageClickListener) :
fun bind(product: ContractProduct) {
quantity.text = product.quantity.toString()
- val productImage = product.image
- if (productImage == null) {
+
+ // base64 encoded image
+ val bitmap = product.imageBitmap
+ if (bitmap == null) {
image.visibility = GONE
- } else REGEX_PRODUCT_IMAGE.matchEntire(productImage)?.let { match ->
- match.groups[2]?.value?.let { group ->
- image.visibility = VISIBLE
- val decodedString = Base64.decode(group, Base64.DEFAULT)
- val bitmap = decodeByteArray(decodedString, 0, decodedString.size)
- image.setImageBitmap(bitmap)
- image.setOnClickListener {
- listener.onImageClick(bitmap)
- }
+ } else {
+ image.visibility = VISIBLE
+ image.setImageBitmap(bitmap)
+ image.setOnClickListener {
+ listener.onImageClick(bitmap)
}
}
+
name.text = product.description
if (product.totalPrice != null) {