gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-android] branch master updated (9a1f300 -> d3cc4bb)


From: gnunet
Subject: [taler-wallet-android] branch master updated (9a1f300 -> d3cc4bb)
Date: Wed, 11 Mar 2020 13:58:28 +0100

This is an automated email from the git hooks/post-receive script.

torsten-grote pushed a change to branch master
in repository wallet-android.

    from 9a1f300  Do not require telephony features aka run on tablet devices
     new 6b7b807  Support base64 encoded images in rfc2397 data URLs for 
product images
     new 88decdd  Show a different product layout when there's only one product
     new d3cc4bb  Show product images in full size if you click on them

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../java/net/taler/wallet/payment/ContractTerms.kt |  6 +-
 .../net/taler/wallet/payment/PaymentManager.kt     | 21 +++++-
 .../net/taler/wallet/payment/ProductAdapter.kt     | 35 +++++++++-
 ...ccessfulFragment.kt => ProductImageFragment.kt} | 31 +++++----
 .../taler/wallet/payment/PromptPaymentFragment.kt  | 10 ++-
 .../fragment_product_image.xml}                    | 16 ++---
 app/src/main/res/layout/list_item_product.xml      | 31 +++++++--
 ...ry_payment.xml => list_item_product_single.xml} | 77 ++++++++++------------
 8 files changed, 146 insertions(+), 81 deletions(-)
 copy app/src/main/java/net/taler/wallet/payment/{PaymentSuccessfulFragment.kt 
=> ProductImageFragment.kt} (63%)
 copy app/src/main/res/{menu/pending_operations.xml => 
layout/fragment_product_image.xml} (69%)
 copy app/src/main/res/layout/{history_payment.xml => 
list_item_product_single.xml} (59%)

diff --git a/app/src/main/java/net/taler/wallet/payment/ContractTerms.kt 
b/app/src/main/java/net/taler/wallet/payment/ContractTerms.kt
index a9f75ed..da91dea 100644
--- a/app/src/main/java/net/taler/wallet/payment/ContractTerms.kt
+++ b/app/src/main/java/net/taler/wallet/payment/ContractTerms.kt
@@ -29,20 +29,22 @@ data class ContractTerms(
 )
 
 interface Product {
-    val id: String
+    val id: String?
     val description: String
     val price: Amount
     val location: String?
+    val image: String?
 }
 
 @JsonIgnoreProperties("totalPrice")
 data class ContractProduct(
     @JsonProperty("product_id")
-    override val id: String,
+    override val id: String?,
     override val description: String,
     override val price: Amount,
     @JsonProperty("delivery_location")
     override val location: String?,
+    override val image: String?,
     val quantity: Int
 ) : Product {
 
diff --git a/app/src/main/java/net/taler/wallet/payment/PaymentManager.kt 
b/app/src/main/java/net/taler/wallet/payment/PaymentManager.kt
index a00a686..ee0edaf 100644
--- a/app/src/main/java/net/taler/wallet/payment/PaymentManager.kt
+++ b/app/src/main/java/net/taler/wallet/payment/PaymentManager.kt
@@ -26,6 +26,9 @@ import net.taler.wallet.Amount
 import net.taler.wallet.TAG
 import net.taler.wallet.backend.WalletBackendApi
 import org.json.JSONObject
+import java.net.MalformedURLException
+
+val REGEX_PRODUCT_IMAGE = 
Regex("^data:image/(jpeg|png);base64,([A-Za-z0-9+/=]+)$")
 
 class PaymentManager(
     private val walletBackendApi: WalletBackendApi,
@@ -61,7 +64,12 @@ class PaymentManager(
                 }
                 else -> {
                     val status = result.getString("status")
-                    mPayStatus.postValue(getPayStatusUpdate(status, result))
+                    try {
+                        mPayStatus.postValue(getPayStatusUpdate(status, 
result))
+                    } catch (e: Exception) {
+                        Log.e(TAG, "Error getting PayStatusUpdate", e)
+                        mPayStatus.postValue(PayStatus.Error(e.message ?: 
"unknown error"))
+                    }
                 }
             }
         }
@@ -80,7 +88,16 @@ class PaymentManager(
     }
 
     private fun getContractTerms(json: JSONObject): ContractTerms {
-        return mapper.readValue(json.getString("contractTermsRaw"))
+        val terms: ContractTerms = 
mapper.readValue(json.getString("contractTermsRaw"))
+        // validate product images
+        terms.products.forEach { product ->
+            product.image?.let { image ->
+                if (REGEX_PRODUCT_IMAGE.matchEntire(image) == null) {
+                    throw MalformedURLException("Invalid image data URL for 
${product.description}")
+                }
+            }
+        }
+        return terms
     }
 
     @UiThread
diff --git a/app/src/main/java/net/taler/wallet/payment/ProductAdapter.kt 
b/app/src/main/java/net/taler/wallet/payment/ProductAdapter.kt
index 3a0dca6..4b1b062 100644
--- a/app/src/main/java/net/taler/wallet/payment/ProductAdapter.kt
+++ b/app/src/main/java/net/taler/wallet/payment/ProductAdapter.kt
@@ -16,25 +16,40 @@
 
 package net.taler.wallet.payment
 
+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
+import android.view.View.VISIBLE
 import android.view.ViewGroup
+import android.widget.ImageView
 import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
 import androidx.recyclerview.widget.RecyclerView.ViewHolder
 import net.taler.wallet.R
 import net.taler.wallet.payment.ProductAdapter.ProductViewHolder
 
+internal interface ProductImageClickListener {
+    fun onImageClick(image: Bitmap)
+}
 
-internal class ProductAdapter : RecyclerView.Adapter<ProductViewHolder>() {
+internal class ProductAdapter(private val listener: ProductImageClickListener) 
:
+    RecyclerView.Adapter<ProductViewHolder>() {
 
     private val items = ArrayList<ContractProduct>()
 
     override fun getItemCount() = items.size
 
+    override fun getItemViewType(position: Int): Int {
+        return if (itemCount == 1) 1 else 0
+    }
+
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): 
ProductViewHolder {
-        val view =
-            
LayoutInflater.from(parent.context).inflate(R.layout.list_item_product, parent, 
false)
+        val res =
+            if (viewType == 1) R.layout.list_item_product_single else 
R.layout.list_item_product
+        val view = LayoutInflater.from(parent.context).inflate(res, parent, 
false)
         return ProductViewHolder(view)
     }
 
@@ -50,11 +65,25 @@ internal class ProductAdapter : 
RecyclerView.Adapter<ProductViewHolder>() {
 
     internal inner class ProductViewHolder(v: View) : ViewHolder(v) {
         private val quantity: TextView = v.findViewById(R.id.quantity)
+        private val image: ImageView = v.findViewById(R.id.image)
         private val name: TextView = v.findViewById(R.id.name)
         private val price: TextView = v.findViewById(R.id.price)
 
         fun bind(product: ContractProduct) {
             quantity.text = product.quantity.toString()
+            if (product.image == null) {
+                image.visibility = GONE
+            } else {
+                image.visibility = VISIBLE
+                // product.image was validated before, so non-null below
+                val match = REGEX_PRODUCT_IMAGE.matchEntire(product.image)!!
+                val decodedString = Base64.decode(match.groups[2]!!.value, 
Base64.DEFAULT)
+                val bitmap = decodeByteArray(decodedString, 0, 
decodedString.size)
+                image.setImageBitmap(bitmap)
+                if (itemCount > 1) image.setOnClickListener {
+                    listener.onImageClick(bitmap)
+                }
+            }
             name.text = product.description
             price.text = product.totalPrice.toString()
         }
diff --git 
a/app/src/main/java/net/taler/wallet/payment/PaymentSuccessfulFragment.kt 
b/app/src/main/java/net/taler/wallet/payment/ProductImageFragment.kt
similarity index 63%
copy from 
app/src/main/java/net/taler/wallet/payment/PaymentSuccessfulFragment.kt
copy to app/src/main/java/net/taler/wallet/payment/ProductImageFragment.kt
index 2084c45..02414a6 100644
--- a/app/src/main/java/net/taler/wallet/payment/PaymentSuccessfulFragment.kt
+++ b/app/src/main/java/net/taler/wallet/payment/ProductImageFragment.kt
@@ -16,34 +16,37 @@
 
 package net.taler.wallet.payment
 
+import android.graphics.Bitmap
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import androidx.navigation.fragment.findNavController
-import kotlinx.android.synthetic.main.fragment_payment_successful.*
+import androidx.fragment.app.DialogFragment
+import kotlinx.android.synthetic.main.fragment_product_image.*
 import net.taler.wallet.R
-import net.taler.wallet.fadeIn
 
-/**
- * Fragment that shows the success message for a payment.
- */
-class PaymentSuccessfulFragment : Fragment() {
+class ProductImageFragment private constructor() : DialogFragment() {
+
+    companion object {
+        private const val IMAGE = "image"
+
+        fun new(image: Bitmap) = ProductImageFragment().apply {
+            arguments = Bundle().apply {
+                putParcelable(IMAGE, image)
+            }
+        }
+    }
 
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.fragment_payment_successful, 
container, false)
+        return inflater.inflate(R.layout.fragment_product_image, container, 
false)
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
-        successImageView.fadeIn()
-        successTextView.fadeIn()
-        backButton.setOnClickListener {
-            findNavController().navigateUp()
-        }
+        val bitmap = arguments!!.getParcelable<Bitmap>(IMAGE)
+        productImageView.setImageBitmap(bitmap)
     }
 
 }
diff --git 
a/app/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt 
b/app/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt
index 2f7807a..5a53556 100644
--- a/app/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt
+++ b/app/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt
@@ -17,6 +17,7 @@
 package net.taler.wallet.payment
 
 import android.annotation.SuppressLint
+import android.graphics.Bitmap
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
@@ -41,11 +42,11 @@ import net.taler.wallet.fadeOut
 /**
  * Show a payment and ask the user to accept/decline.
  */
-class PromptPaymentFragment : Fragment() {
+class PromptPaymentFragment : Fragment(), ProductImageClickListener {
 
     private val model: WalletViewModel by activityViewModels()
     private val paymentManager by lazy { model.paymentManager }
-    private val adapter = ProductAdapter()
+    private val adapter = ProductAdapter(this)
 
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
@@ -158,4 +159,9 @@ class PromptPaymentFragment : Fragment() {
         totalView.fadeIn()
     }
 
+    override fun onImageClick(image: Bitmap) {
+        val f = ProductImageFragment.new(image)
+        f.show(parentFragmentManager, "image")
+    }
+
 }
diff --git a/app/src/main/res/menu/pending_operations.xml 
b/app/src/main/res/layout/fragment_product_image.xml
similarity index 69%
copy from app/src/main/res/menu/pending_operations.xml
copy to app/src/main/res/layout/fragment_product_image.xml
index 980ea66..9f65d4d 100644
--- a/app/src/main/res/menu/pending_operations.xml
+++ b/app/src/main/res/layout/fragment_product_image.xml
@@ -14,11 +14,11 @@
   ~ GNU Taler; see the file COPYING.  If not, see 
<http://www.gnu.org/licenses/>
   -->
 
-<menu xmlns:android="http://schemas.android.com/apk/res/android";
-        xmlns:app="http://schemas.android.com/apk/res-auto";>
-    <item
-            android:id="@+id/retry_pending"
-            android:orderInCategory="100"
-            android:title="@string/menu_retry_pending_operations"
-            app:showAsAction="never" />
-</menu>
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android";
+        xmlns:tools="http://schemas.android.com/tools";
+        android:id="@+id/productImageView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        tools:ignore="ContentDescription">
+
+</ImageView>
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_product.xml 
b/app/src/main/res/layout/list_item_product.xml
index 606022e..fe6ba23 100644
--- a/app/src/main/res/layout/list_item_product.xml
+++ b/app/src/main/res/layout/list_item_product.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
   ~ This file is part of GNU Taler
   ~ (C) 2020 Taler Systems S.A.
   ~
@@ -20,9 +19,7 @@
         xmlns:tools="http://schemas.android.com/tools";
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:paddingStart="8dp"
-        android:paddingTop="8dp"
-        android:paddingEnd="8dp">
+        android:padding="8dp">
 
     <TextView
             android:id="@+id/quantity"
@@ -30,27 +27,49 @@
             android:layout_height="wrap_content"
             android:gravity="end"
             android:minWidth="24dp"
+            app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintVertical_bias="0.0"
             tools:text="31" />
 
+    <ImageView
+            android:id="@+id/image"
+            android:layout_width="wrap_content"
+            android:layout_height="0dp"
+            android:layout_marginStart="8dp"
+            app:layout_constrainedWidth="true"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintDimensionRatio="H,4:3"
+            app:layout_constraintEnd_toStartOf="@+id/name"
+            app:layout_constraintStart_toEndOf="@+id/quantity"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintWidth_max="64dp"
+            tools:ignore="ContentDescription"
+            tools:srcCompat="@tools:sample/avatars"
+            tools:visibility="visible" />
+
     <TextView
             android:id="@+id/name"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_marginStart="8dp"
             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"
+            app:layout_constraintVertical_bias="0.0"
             tools:text="A product item that in some cases could have a very 
long name" />
 
     <TextView
             android:id="@+id/price"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintVertical_bias="0.0"
             tools:text="23.42" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/history_payment.xml 
b/app/src/main/res/layout/list_item_product_single.xml
similarity index 59%
copy from app/src/main/res/layout/history_payment.xml
copy to app/src/main/res/layout/list_item_product_single.xml
index dd135e7..a4578b3 100644
--- a/app/src/main/res/layout/history_payment.xml
+++ b/app/src/main/res/layout/list_item_product_single.xml
@@ -19,69 +19,58 @@
         xmlns:tools="http://schemas.android.com/tools";
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginStart="16dp"
-        android:layout_marginTop="8dp"
-        android:layout_marginEnd="16dp"
-        android:layout_marginBottom="8dp"
-        android:background="?attr/selectableItemBackground">
-
-    <ImageView
-            android:id="@+id/icon"
-            android:layout_width="32dp"
-            android:layout_height="32dp"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="parent"
-            app:srcCompat="@drawable/history_withdrawn"
-            app:tint="?android:colorControlNormal"
-            tools:ignore="ContentDescription" />
+        android:padding="8dp">
 
     <TextView
-            android:id="@+id/title"
-            style="@style/HistoryTitle"
-            android:layout_width="0dp"
+            android:id="@+id/quantity"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginStart="8dp"
-            android:layout_marginEnd="8dp"
-            app:layout_constraintEnd_toStartOf="@+id/amountPaidWithFees"
-            app:layout_constraintStart_toEndOf="@+id/icon"
+            app:layout_constraintEnd_toStartOf="@+id/name"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintHorizontal_chainStyle="packed"
+            app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent"
-            tools:text="Lots of books with very long titles" />
+            app:layout_constraintVertical_bias="0.0"
+            tools:text="31" />
 
-    <TextView
-            android:id="@+id/summary"
-            android:layout_width="wrap_content"
+    <ImageView
+            android:id="@+id/image"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
-            android:layout_marginStart="8dp"
             android:layout_marginTop="8dp"
-            app:layout_constrainedWidth="true"
             app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toStartOf="@+id/amountPaidWithFees"
-            app:layout_constraintHorizontal_bias="0.0"
-            app:layout_constraintStart_toEndOf="@+id/icon"
-            app:layout_constraintTop_toBottomOf="@+id/title"
-            app:layout_constraintVertical_bias="0.0"
-            tools:text="@string/history_event_payment_sent" />
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/name"
+            tools:ignore="ContentDescription"
+            tools:srcCompat="@tools:sample/avatars"
+            tools:visibility="visible" />
 
     <TextView
-            android:id="@+id/amountPaidWithFees"
+            android:id="@+id/name"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textColor="@color/red"
-            android:textSize="16sp"
-            app:layout_constraintBottom_toTopOf="@+id/time"
+            android:layout_marginStart="8dp"
+            android:layout_marginEnd="8dp"
+            app:layout_constrainedWidth="true"
+            app:layout_constraintBottom_toTopOf="@+id/image"
             app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/price"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintStart_toEndOf="@+id/quantity"
             app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintVertical_bias="0.0"
-            tools:text="0.2 TESTKUDOS" />
+            app:layout_goneMarginEnd="0dp"
+            tools:text="A product item that can have a very long name that 
wraps over two lines" />
 
     <TextView
-            android:id="@+id/time"
+            android:id="@+id/price"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textSize="14sp"
+            android:visibility="gone"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
-            tools:text="23 min ago" />
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintVertical_bias="0.0"
+            tools:text="23.42" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]