gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-android] 03/03: [wallet] allow transactions to be selected


From: gnunet
Subject: [taler-taler-android] 03/03: [wallet] allow transactions to be selected by long tap
Date: Thu, 16 Apr 2020 20:07:32 +0200

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

torsten-grote pushed a commit to branch master
in repository taler-android.

commit f920fa7fa12db5d6fd40844ffb8402426d0a2b07
Author: Torsten Grote <address@hidden>
AuthorDate: Thu Apr 16 15:06:06 2020 -0300

    [wallet] allow transactions to be selected by long tap
---
 .../main/res/drawable/selectable_background.xml    |  5 --
 merchant-terminal/src/main/res/values/colors.xml   |  6 --
 .../main/res/drawable/selectable_background.xml    | 15 ++--
 .../src/main/res/values-night/colors.xml           |  0
 .../src/main/res/values/colors.xml                 | 10 +--
 wallet/build.gradle                                |  4 +
 .../wallet/transactions/TransactionAdapter.kt      | 47 ++++++++++--
 .../wallet/transactions/TransactionsFragment.kt    | 85 ++++++++++++++++++++--
 wallet/src/main/res/drawable/ic_delete.xml         | 10 +++
 wallet/src/main/res/drawable/ic_select_all.xml     | 10 +++
 .../src/main/res/layout/list_item_transaction.xml  |  3 +-
 .../transactions_action_mode.xml}                  | 18 +++--
 wallet/src/main/res/values/colors.xml              |  3 -
 wallet/src/main/res/values/strings.xml             |  2 +
 wallet/src/main/res/values/styles.xml              |  2 +
 15 files changed, 171 insertions(+), 49 deletions(-)

diff --git a/merchant-terminal/src/main/res/drawable/selectable_background.xml 
b/merchant-terminal/src/main/res/drawable/selectable_background.xml
deleted file mode 100644
index b82de92..0000000
--- a/merchant-terminal/src/main/res/drawable/selectable_background.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android";>
-    <item android:drawable="@color/selectedBackground" 
android:state_activated="true" />
-    <item android:drawable="@android:color/transparent" />
-</selector>
\ No newline at end of file
diff --git a/merchant-terminal/src/main/res/values/colors.xml 
b/merchant-terminal/src/main/res/values/colors.xml
index bf0c849..950c107 100644
--- a/merchant-terminal/src/main/res/values/colors.xml
+++ b/merchant-terminal/src/main/res/values/colors.xml
@@ -4,11 +4,5 @@
     <color name="colorPrimaryDark">#5D4037</color>
     <color name="colorAccent">#FFEB3B</color>
 
-    <color name="highlightedBackground">#E4E4E4</color>
-    <color name="selectedBackground">#DADADA</color>
     <color name="bottomButtons">#9E9D24</color>
-
-    <color name="green">#388E3C</color>
-    <color name="red">#C62828</color>
-
 </resources>
diff --git a/wallet/src/main/res/values/colors.xml 
b/taler-kotlin-common/src/main/res/drawable/selectable_background.xml
similarity index 71%
copy from wallet/src/main/res/values/colors.xml
copy to taler-kotlin-common/src/main/res/drawable/selectable_background.xml
index a6b1731..3c383a8 100644
--- a/wallet/src/main/res/values/colors.xml
+++ b/taler-kotlin-common/src/main/res/drawable/selectable_background.xml
@@ -1,4 +1,5 @@
-<?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.
   ~
@@ -14,11 +15,7 @@
   ~ GNU Taler; see the file COPYING.  If not, see 
<http://www.gnu.org/licenses/>
   -->
 
-<resources>
-    <color name="colorPrimary">#283593</color>
-    <color name="colorPrimaryDark">#1A237E</color>
-    <color name="colorAccent">#AE1010</color>
-
-    <color name="red">#C62828</color>
-    <color name="green">#558B2F</color>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android";>
+    <item android:drawable="@color/selectedBackground" 
android:state_activated="true" />
+    <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/merchant-terminal/src/main/res/values-night/colors.xml 
b/taler-kotlin-common/src/main/res/values-night/colors.xml
similarity index 100%
rename from merchant-terminal/src/main/res/values-night/colors.xml
rename to taler-kotlin-common/src/main/res/values-night/colors.xml
diff --git a/wallet/src/main/res/values/colors.xml 
b/taler-kotlin-common/src/main/res/values/colors.xml
similarity index 77%
copy from wallet/src/main/res/values/colors.xml
copy to taler-kotlin-common/src/main/res/values/colors.xml
index a6b1731..c916442 100644
--- a/wallet/src/main/res/values/colors.xml
+++ b/taler-kotlin-common/src/main/res/values/colors.xml
@@ -1,4 +1,5 @@
-<?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.
   ~
@@ -15,10 +16,9 @@
   -->
 
 <resources>
-    <color name="colorPrimary">#283593</color>
-    <color name="colorPrimaryDark">#1A237E</color>
-    <color name="colorAccent">#AE1010</color>
+    <color name="highlightedBackground">#E4E4E4</color>
+    <color name="selectedBackground">#DADADA</color>
 
+    <color name="green">#388E3C</color>
     <color name="red">#C62828</color>
-    <color name="green">#558B2F</color>
 </resources>
diff --git a/wallet/build.gradle b/wallet/build.gradle
index 0095b27..a872e8c 100644
--- a/wallet/build.gradle
+++ b/wallet/build.gradle
@@ -71,6 +71,10 @@ dependencies {
     implementation 'com.google.android.material:material:1.1.0'
     implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
 
+    // Lists and Selection
+    implementation "androidx.recyclerview:recyclerview:1.1.0"
+    implementation "androidx.recyclerview:recyclerview-selection:1.1.0-rc01"
+
     // Navigation Library
     implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
     implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
index 809f6a9..a72b8a8 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
@@ -18,13 +18,17 @@ package net.taler.wallet.transactions
 
 import android.content.Context
 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.annotation.CallSuper
+import androidx.recyclerview.selection.ItemDetailsLookup
+import androidx.recyclerview.selection.ItemKeyProvider
+import androidx.recyclerview.selection.SelectionTracker
+import androidx.recyclerview.widget.RecyclerView
 import androidx.recyclerview.widget.RecyclerView.Adapter
 import androidx.recyclerview.widget.RecyclerView.ViewHolder
 import net.taler.common.exhaustive
@@ -39,6 +43,9 @@ internal class TransactionAdapter(
     private var transactions: Transactions = Transactions()
 ) : Adapter<TransactionViewHolder>() {
 
+    lateinit var tracker: SelectionTracker<String>
+    val keyProvider = TransactionKeyProvider()
+
     init {
         setHasStableIds(false)
     }
@@ -52,8 +59,8 @@ internal class TransactionAdapter(
     override fun getItemCount(): Int = transactions.size
 
     override fun onBindViewHolder(holder: TransactionViewHolder, position: 
Int) {
-        val event = transactions[position]
-        holder.bind(event)
+        val transaction = transactions[position]
+        holder.bind(transaction, tracker.isSelected(transaction.eventId))
     }
 
     fun update(updatedTransactions: Transactions) {
@@ -61,6 +68,10 @@ internal class TransactionAdapter(
         this.notifyDataSetChanged()
     }
 
+    fun selectAll() = transactions.forEach {
+        tracker.select(it.eventId)
+    }
+
     internal open inner class TransactionViewHolder(private val v: View) : 
ViewHolder(v) {
 
         protected val context: Context = v.context
@@ -73,15 +84,15 @@ internal class TransactionAdapter(
         private val selectableBackground = v.background
         private val amountColor = amount.currentTextColor
 
-        @CallSuper
-        open fun bind(transaction: Transaction) {
+        open fun bind(transaction: Transaction, selected: Boolean) {
             if (devMode || transaction.detailPageLayout != 0) {
                 v.background = selectableBackground
-                v.setOnClickListener { listener.onEventClicked(transaction) }
+                v.setOnClickListener { 
listener.onTransactionClicked(transaction) }
             } else {
                 v.background = null
                 v.setOnClickListener(null)
             }
+            v.isActivated = selected
             icon.setImageResource(transaction.icon)
 
             title.text = if (transaction.title == null) {
@@ -140,4 +151,28 @@ internal class TransactionAdapter(
 
     }
 
+    internal inner class TransactionKeyProvider : 
ItemKeyProvider<String>(SCOPE_MAPPED) {
+        override fun getKey(position: Int) = transactions[position].eventId
+        override fun getPosition(key: String): Int {
+            return transactions.indexOfFirst { it.eventId == key }
+        }
+    }
+
+}
+
+internal class TransactionLookup(
+    private val list: RecyclerView,
+    private val adapter: TransactionAdapter
+) : ItemDetailsLookup<String>() {
+    override fun getItemDetails(e: MotionEvent): ItemDetails<String>? {
+        list.findChildViewUnder(e.x, e.y)?.let { view ->
+            val holder = list.getChildViewHolder(view)
+            val position = holder.adapterPosition
+            return object : ItemDetails<String>() {
+                override fun getPosition(): Int = position
+                override fun getSelectionKey(): String = 
adapter.keyProvider.getKey(position)
+            }
+        }
+        return null
+    }
 }
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
index 0d6e9ce..e7adaf1 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
@@ -17,6 +17,7 @@
 package net.taler.wallet.transactions
 
 import android.os.Bundle
+import android.view.ActionMode
 import android.view.LayoutInflater
 import android.view.Menu
 import android.view.MenuInflater
@@ -25,10 +26,15 @@ import android.view.View
 import android.view.View.INVISIBLE
 import android.view.View.VISIBLE
 import android.view.ViewGroup
+import android.widget.Toast
+import android.widget.Toast.LENGTH_LONG
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
 import androidx.lifecycle.Observer
 import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.selection.SelectionPredicates
+import androidx.recyclerview.selection.SelectionTracker
+import androidx.recyclerview.selection.StorageStrategy
 import androidx.recyclerview.widget.DividerItemDecoration
 import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
 import kotlinx.android.synthetic.main.fragment_transactions.*
@@ -38,16 +44,18 @@ import net.taler.wallet.MainViewModel
 import net.taler.wallet.R
 
 interface OnEventClickListener {
-    fun onEventClicked(event: Transaction)
+    fun onTransactionClicked(transaction: Transaction)
 }
 
-class TransactionsFragment : Fragment(), OnEventClickListener {
+class TransactionsFragment : Fragment(), OnEventClickListener, 
ActionMode.Callback {
 
     private val model: MainViewModel by activityViewModels()
     private val transactionManager by lazy { model.transactionManager }
 
     private val transactionAdapter by lazy { 
TransactionAdapter(model.devMode.value == true, this) }
     private val currency by lazy { transactionManager.selectedCurrency!! }
+    private var tracker: SelectionTracker<String>? = null
+    private var actionMode: ActionMode? = null
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
@@ -66,6 +74,32 @@ class TransactionsFragment : Fragment(), 
OnEventClickListener {
             adapter = transactionAdapter
             addItemDecoration(DividerItemDecoration(context, VERTICAL))
         }
+        val tracker = SelectionTracker.Builder(
+            "transaction-selection-id",
+            list,
+            transactionAdapter.keyProvider,
+            TransactionLookup(list, transactionAdapter),
+            StorageStrategy.createStringStorage()
+        ).withSelectionPredicate(
+            SelectionPredicates.createSelectAnything()
+        ).build()
+        savedInstanceState?.let { tracker.onRestoreInstanceState(it) }
+        transactionAdapter.tracker = tracker
+        this.tracker = tracker
+        tracker.addObserver(object : 
SelectionTracker.SelectionObserver<String>() {
+            override fun onItemStateChanged(key: String, selected: Boolean) {
+                if (selected && actionMode == null) {
+                    actionMode = 
requireActivity().startActionMode(this@TransactionsFragment)
+                    updateActionModeTitle()
+                } else if (actionMode != null) {
+                    if (selected || tracker.hasSelection()) {
+                        updateActionModeTitle()
+                    } else {
+                        actionMode!!.finish()
+                    }
+                }
+            }
+        })
 
         transactionManager.progress.observe(viewLifecycleOwner, Observer { 
show ->
             progressBar.visibility = if (show) VISIBLE else INVISIBLE
@@ -88,6 +122,11 @@ class TransactionsFragment : Fragment(), 
OnEventClickListener {
         })
     }
 
+    override fun onSaveInstanceState(outState: Bundle) {
+        super.onSaveInstanceState(outState)
+        tracker?.onSaveInstanceState(outState)
+    }
+
     override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
         inflater.inflate(R.menu.transactions, menu)
     }
@@ -98,12 +137,13 @@ class TransactionsFragment : Fragment(), 
OnEventClickListener {
         }
     }
 
-    override fun onEventClicked(event: Transaction) {
-        if (event.detailPageLayout != 0) {
-            transactionManager.selectedEvent = event
+    override fun onTransactionClicked(transaction: Transaction) {
+        if (actionMode != null) return // don't react on clicks while in 
action mode
+        if (transaction.detailPageLayout != 0) {
+            transactionManager.selectedEvent = transaction
             findNavController().navigate(R.id.action_nav_transaction_detail)
         } else if (model.devMode.value == true) {
-            JsonDialogFragment.new(event.json.toString(2))
+            JsonDialogFragment.new(transaction.json.toString(2))
                 .show(parentFragmentManager, null)
         }
     }
@@ -121,4 +161,37 @@ class TransactionsFragment : Fragment(), 
OnEventClickListener {
         }
     }
 
+    override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
+        val inflater = mode.menuInflater
+        inflater.inflate(R.menu.transactions_action_mode, menu)
+        return true
+    }
+
+    override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
+        return false // no update needed
+    }
+
+    override fun onActionItemClicked(mode: ActionMode, item: MenuItem): 
Boolean {
+        when (item.itemId) {
+            R.id.transaction_delete -> {
+                val s = "Not yet implemented. Pester Florian! ;)"
+                Toast.makeText(requireContext(), s, LENGTH_LONG).show()
+                mode.finish()
+            }
+            R.id.transaction_select_all -> transactionAdapter.selectAll()
+        }
+        return true
+    }
+
+    override fun onDestroyActionMode(mode: ActionMode) {
+        tracker?.clearSelection()
+        actionMode = null
+    }
+
+    private fun updateActionModeTitle() {
+        tracker?.selection?.size()?.toString()?.let { num ->
+            actionMode?.title = num
+        }
+    }
+
 }
diff --git a/wallet/src/main/res/drawable/ic_delete.xml 
b/wallet/src/main/res/drawable/ic_delete.xml
new file mode 100644
index 0000000..88caaa1
--- /dev/null
+++ b/wallet/src/main/res/drawable/ic_delete.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android";
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="?attr/colorControlNormal"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 
2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z" />
+</vector>
diff --git a/wallet/src/main/res/drawable/ic_select_all.xml 
b/wallet/src/main/res/drawable/ic_select_all.xml
new file mode 100644
index 0000000..56adb23
--- /dev/null
+++ b/wallet/src/main/res/drawable/ic_select_all.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android";
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="?attr/colorControlNormal"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3,5h2L5,3c-1.1,0 -2,0.9 
-2,2zM3,13h2v-2L3,11v2zM7,21h2v-2L7,19v2zM3,9h2L5,7L3,7v2zM13,3h-2v2h2L13,3zM19,3v2h2c0,-1.1
 -0.9,-2 -2,-2zM5,21v-2L3,19c0,1.1 0.9,2 
2,2zM3,17h2v-2L3,15v2zM9,3L7,3v2h2L9,3zM11,21h2v-2h-2v2zM19,13h2v-2h-2v2zM19,21c1.1,0
 2,-0.9 
2,-2h-2v2zM19,9h2L21,7h-2v2zM19,17h2v-2h-2v2zM15,21h2v-2h-2v2zM15,5h2L17,3h-2v2zM7,17h10L17,7L7,7v10zM9,9h6v6L9,15L9,9z"
 />
+</vector>
diff --git a/wallet/src/main/res/layout/list_item_transaction.xml 
b/wallet/src/main/res/layout/list_item_transaction.xml
index a3ac980..2fabe1d 100644
--- a/wallet/src/main/res/layout/list_item_transaction.xml
+++ b/wallet/src/main/res/layout/list_item_transaction.xml
@@ -19,7 +19,8 @@
     xmlns:tools="http://schemas.android.com/tools";
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="?attr/selectableItemBackground"
+    android:background="@drawable/selectable_background"
+    android:foreground="?attr/selectableItemBackground"
     android:paddingStart="16dp"
     android:paddingTop="8dp"
     android:paddingEnd="16dp"
diff --git a/wallet/src/main/res/values/colors.xml 
b/wallet/src/main/res/menu/transactions_action_mode.xml
similarity index 66%
copy from wallet/src/main/res/values/colors.xml
copy to wallet/src/main/res/menu/transactions_action_mode.xml
index a6b1731..b290b9e 100644
--- a/wallet/src/main/res/values/colors.xml
+++ b/wallet/src/main/res/menu/transactions_action_mode.xml
@@ -14,11 +14,13 @@
   ~ GNU Taler; see the file COPYING.  If not, see 
<http://www.gnu.org/licenses/>
   -->
 
-<resources>
-    <color name="colorPrimary">#283593</color>
-    <color name="colorPrimaryDark">#1A237E</color>
-    <color name="colorAccent">#AE1010</color>
-
-    <color name="red">#C62828</color>
-    <color name="green">#558B2F</color>
-</resources>
+<menu xmlns:android="http://schemas.android.com/apk/res/android";>
+    <item
+        android:id="@+id/transaction_select_all"
+        android:icon="@drawable/ic_select_all"
+        android:title="@string/transactions_select_all" />
+    <item
+        android:id="@+id/transaction_delete"
+        android:icon="@drawable/ic_delete"
+        android:title="@string/transactions_delete" />
+</menu>
diff --git a/wallet/src/main/res/values/colors.xml 
b/wallet/src/main/res/values/colors.xml
index a6b1731..6413bb8 100644
--- a/wallet/src/main/res/values/colors.xml
+++ b/wallet/src/main/res/values/colors.xml
@@ -18,7 +18,4 @@
     <color name="colorPrimary">#283593</color>
     <color name="colorPrimaryDark">#1A237E</color>
     <color name="colorAccent">#AE1010</color>
-
-    <color name="red">#C62828</color>
-    <color name="green">#558B2F</color>
 </resources>
diff --git a/wallet/src/main/res/values/strings.xml 
b/wallet/src/main/res/values/strings.xml
index b4af3b8..4531785 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -49,6 +49,8 @@
     <string name="transactions_detail_title">Transaction</string>
     <string name="transactions_detail_title_balance">Balance: %s</string>
     <string name="transactions_detail_json">Show JSON</string>
+    <string name="transactions_delete">Delete</string>
+    <string name="transactions_select_all">Select All</string>
 
     <!-- Transactions -->
     <string name="transaction_reserve_balance_updated">Reserve Balance 
Updated</string>
diff --git a/wallet/src/main/res/values/styles.xml 
b/wallet/src/main/res/values/styles.xml
index c8a2c3b..093f43f 100644
--- a/wallet/src/main/res/values/styles.xml
+++ b/wallet/src/main/res/values/styles.xml
@@ -21,6 +21,8 @@
         <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
         <item name="colorAccent">@color/colorAccent</item>
         <item name="colorOnPrimary">@android:color/white</item>
+
+        <item name="windowActionModeOverlay">true</item>
     </style>
 
     <style name="AppTheme.NoActionBar">

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



reply via email to

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