summaryrefslogtreecommitdiff
path: root/wallet/src/main/java/net/taler/wallet/transactions
diff options
context:
space:
mode:
authorTorsten Grote <t@grobox.de>2020-04-16 15:06:06 -0300
committerTorsten Grote <t@grobox.de>2020-04-16 15:06:06 -0300
commitf920fa7fa12db5d6fd40844ffb8402426d0a2b07 (patch)
treebff6056188d6424c63eba240d67f9875ea866daa /wallet/src/main/java/net/taler/wallet/transactions
parentbe8c9a25fe8df7d5bf8e55b38103522f90737e92 (diff)
downloadtaler-android-f920fa7fa12db5d6fd40844ffb8402426d0a2b07.tar.gz
taler-android-f920fa7fa12db5d6fd40844ffb8402426d0a2b07.tar.bz2
taler-android-f920fa7fa12db5d6fd40844ffb8402426d0a2b07.zip
[wallet] allow transactions to be selected by long tap
Diffstat (limited to 'wallet/src/main/java/net/taler/wallet/transactions')
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt47
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt85
2 files changed, 120 insertions, 12 deletions
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
+ }
+ }
+
}