commit 9077c822a1c6b934e91734427dc09209a0c21a90
parent 662fe62a9ce5204eb86620932e5f97b8c53e8344
Author: Iván Ávalos <avalos@disroot.org>
Date: Wed, 17 Jul 2024 12:40:32 -0600
[wallet] Optimize adapter updates with diff
Diffstat:
7 files changed, 136 insertions(+), 39 deletions(-)
diff --git a/wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt b/wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt
@@ -22,6 +22,7 @@ import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.TextView
+import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Adapter
import net.taler.wallet.R
@@ -52,9 +53,14 @@ class BalanceAdapter(private val listener: BalanceClickListener) : Adapter<Balan
holder.bind(item)
}
- fun setItems(items: List<BalanceItem>) {
- this.items = items
- this.notifyDataSetChanged()
+ fun update(newItems: List<BalanceItem>) {
+ val oldItems = this.items
+
+ val diffCallback = BalanceDiffCallback(oldItems, newItems)
+ val diffResult = DiffUtil.calculateDiff(diffCallback)
+ diffResult.dispatchUpdatesTo(this)
+
+ this.items = newItems
}
inner class BalanceViewHolder(private val v: View) : RecyclerView.ViewHolder(v) {
@@ -97,5 +103,27 @@ class BalanceAdapter(private val listener: BalanceClickListener) : Adapter<Balan
}
}
}
-
}
+
+internal class BalanceDiffCallback(
+ private val oldList: List<BalanceItem>,
+ private val newList: List<BalanceItem>,
+): DiffUtil.Callback() {
+ override fun getOldListSize() = oldList.size
+
+ override fun getNewListSize() = newList.size
+
+ override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+ val old = oldList[oldItemPosition]
+ val new = newList[newItemPosition]
+
+ return old.scopeInfo == new.scopeInfo
+ }
+
+ override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+ val old = oldList[oldItemPosition]
+ val new = newList[newItemPosition]
+
+ return old == new
+ }
+}
+\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/balances/BalancesFragment.kt b/wallet/src/main/java/net/taler/wallet/balances/BalancesFragment.kt
@@ -83,7 +83,7 @@ class BalancesFragment : Fragment(),
ui.mainEmptyState.visibility = VISIBLE
ui.mainList.visibility = GONE
} else {
- balancesAdapter.setItems(state.balances)
+ balancesAdapter.update(state.balances)
ui.mainEmptyState.visibility = INVISIBLE
ui.mainList.fadeIn()
}
diff --git a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeAdapter.kt b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeAdapter.kt
@@ -24,6 +24,7 @@ import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.TextView
import androidx.appcompat.widget.PopupMenu
+import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Adapter
import net.taler.wallet.R
@@ -42,7 +43,7 @@ internal class ExchangeAdapter(
private val listener: ExchangeClickListener,
) : Adapter<ExchangeItemViewHolder>() {
- private val items = ArrayList<ExchangeItem>()
+ private var items = emptyList<ExchangeItem>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExchangeItemViewHolder {
val view = LayoutInflater.from(parent.context)
@@ -57,9 +58,13 @@ internal class ExchangeAdapter(
}
fun update(newItems: List<ExchangeItem>) {
- items.clear()
- items.addAll(newItems)
- notifyDataSetChanged()
+ val oldItems = this.items
+
+ val diffCallback = ExchangeDiffCallback(oldItems, newItems)
+ val diffResult = DiffUtil.calculateDiff(diffCallback)
+ diffResult.dispatchUpdatesTo(this)
+
+ items = newItems
}
internal inner class ExchangeItemViewHolder(v: View) : RecyclerView.ViewHolder(v) {
@@ -114,5 +119,27 @@ internal class ExchangeAdapter(
show()
}
}
-
}
+
+internal class ExchangeDiffCallback(
+ private val oldList: List<ExchangeItem>,
+ private val newList: List<ExchangeItem>,
+): DiffUtil.Callback() {
+ override fun getOldListSize() = oldList.size
+
+ override fun getNewListSize() = newList.size
+
+ override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+ val old = oldList[oldItemPosition]
+ val new = newList[newItemPosition]
+
+ return old.exchangeBaseUrl == new.exchangeBaseUrl
+ }
+
+ override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+ val old = oldList[oldItemPosition]
+ val new = newList[newItemPosition]
+
+ return old == new
+ }
+}
+\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/payment/ProductAdapter.kt b/wallet/src/main/java/net/taler/wallet/payment/ProductAdapter.kt
@@ -26,6 +26,7 @@ import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
+import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import net.taler.common.ContractProduct
@@ -39,7 +40,7 @@ internal interface ProductImageClickListener {
internal class ProductAdapter(private val listener: ProductImageClickListener) :
RecyclerView.Adapter<ProductViewHolder>() {
- private val items = ArrayList<ContractProduct>()
+ private var items = emptyList<ContractProduct>()
override fun getItemCount() = items.size
@@ -53,10 +54,14 @@ internal class ProductAdapter(private val listener: ProductImageClickListener) :
holder.bind(items[position])
}
- fun setItems(items: List<ContractProduct>) {
- this.items.clear()
- this.items.addAll(items)
- notifyDataSetChanged()
+ fun update(newItems: List<ContractProduct>) {
+ val oldItems = this.items
+
+ val diffCallback = ProductDiffCallback(oldItems, newItems)
+ val diffResult = DiffUtil.calculateDiff(diffCallback)
+ diffResult.dispatchUpdatesTo(this)
+
+ items = newItems
}
internal inner class ProductViewHolder(v: View) : ViewHolder(v) {
@@ -88,5 +93,27 @@ internal class ProductAdapter(private val listener: ProductImageClickListener) :
} ?: GONE
}
}
-
}
+
+internal class ProductDiffCallback(
+ private val oldList: List<ContractProduct>,
+ private val newList: List<ContractProduct>,
+): DiffUtil.Callback() {
+ override fun getOldListSize() = oldList.size
+
+ override fun getNewListSize() = newList.size
+
+ override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+ val old = oldList[oldItemPosition]
+ val new = newList[newItemPosition]
+
+ return old.productId == new.productId
+ }
+
+ override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+ val old = oldList[oldItemPosition]
+ val new = newList[newItemPosition]
+
+ return old == new
+ }
+}
+\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt b/wallet/src/main/java/net/taler/wallet/payment/PromptPaymentFragment.kt
@@ -155,7 +155,7 @@ class PromptPaymentFragment : Fragment(), ProductImageClickListener {
private fun showOrder(contractTerms: ContractTerms, amount: Amount, totalFees: Amount? = null) {
ui.details.orderView.text = contractTerms.summary
- adapter.setItems(contractTerms.products)
+ adapter.update(contractTerms.products)
ui.details.productsList.fadeIn()
ui.bottom.totalView.text = amount.toString()
if (totalFees != null && !totalFees.isZero()) {
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
@@ -16,7 +16,6 @@
package net.taler.wallet.transactions
-import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.MotionEvent
@@ -76,25 +75,32 @@ internal class TransactionAdapter(
holder.bind(transaction, tracker.isSelected(transaction.transactionId))
}
- @SuppressLint("NotifyDataSetChanged")
- fun setCurrencySpec(spec: CurrencySpecification?) {
- this.currencySpec = spec
- this.notifyDataSetChanged()
- }
-
- @SuppressLint("NotifyDataSetChanged")
- fun update(updatedTransactions: List<Transaction>? = null, networkAvailable: Boolean? = null) {
- updatedTransactions?.let {
- val diffCallback = TransactionDiffCallback(transactions, updatedTransactions)
- val diffResult = DiffUtil.calculateDiff(diffCallback)
- this.transactions = it
- diffResult.dispatchUpdatesTo(this)
- }
-
- networkAvailable?.let {
- this.networkAvailable = it
- this.notifyDataSetChanged()
- }
+ fun update(
+ updatedTransactions: List<Transaction>? = null,
+ updatedNetworkAvailable: Boolean? = null,
+ updatedCurrencySpec: CurrencySpecification? = null,
+ ) {
+ val oldTransactions = transactions
+ val newTransactions = updatedTransactions ?: oldTransactions
+ val oldNetworkAvailable = networkAvailable
+ val newNetworkAvailable = updatedNetworkAvailable ?: oldNetworkAvailable
+ val oldCurrencySpec = currencySpec
+ val newCurrencySpec = updatedCurrencySpec ?: oldCurrencySpec
+
+ val diffCallback = TransactionDiffCallback(
+ oldTransactions,
+ newTransactions,
+ oldNetworkAvailable,
+ newNetworkAvailable,
+ oldCurrencySpec,
+ newCurrencySpec,
+ )
+ val diffResult = DiffUtil.calculateDiff(diffCallback)
+ diffResult.dispatchUpdatesTo(this)
+
+ transactions = newTransactions
+ networkAvailable = newNetworkAvailable
+ currencySpec = newCurrencySpec
}
fun selectAll() = transactions.forEach {
@@ -274,6 +280,10 @@ internal class TransactionLookup(
internal class TransactionDiffCallback(
private val oldList: List<Transaction>,
private val newList: List<Transaction>,
+ private val oldNetworkAvailable: Boolean?,
+ private val newNetworkAvailable: Boolean?,
+ private val oldCurrencySpec: CurrencySpecification?,
+ private val newCurrencySpec: CurrencySpecification?,
): DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
@@ -292,5 +302,7 @@ internal class TransactionDiffCallback(
return oldTx.txState == newTx.txState
&& oldTx.error == newTx.error
+ && oldNetworkAvailable == newNetworkAvailable
+ && oldCurrencySpec == newCurrencySpec
}
}
\ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
@@ -120,7 +120,7 @@ class TransactionsFragment : Fragment(), OnTransactionClickListener, ActionMode.
balances.find { it.scopeInfo == scopeInfo }?.let { balance ->
ui.actionsBar.amount.text = balance.available.toString(showSymbol = false)
- transactionAdapter.setCurrencySpec(balance.available.spec)
+ transactionAdapter.update(updatedCurrencySpec = balance.available.spec)
}
}
@@ -134,7 +134,7 @@ class TransactionsFragment : Fragment(), OnTransactionClickListener, ActionMode.
}
networkManager.networkStatus.observe(viewLifecycleOwner) { state ->
- transactionAdapter.update(networkAvailable = state)
+ transactionAdapter.update(updatedNetworkAvailable = state)
}
ui.actionsBar.sendButton.setOnClickListener {