[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-merchant-terminal-android] 17/19: Make order sorting deterministi
From: |
gnunet |
Subject: |
[taler-merchant-terminal-android] 17/19: Make order sorting deterministic |
Date: |
Fri, 21 Feb 2020 19:00:10 +0100 |
This is an automated email from the git hooks/post-receive script.
torsten-grote pushed a commit to branch master
in repository merchant-terminal-android.
commit 2256d2fa3e6b9b25a1e90c4a690a4af3820d651e
Author: Torsten Grote <address@hidden>
AuthorDate: Thu Feb 20 16:55:29 2020 -0300
Make order sorting deterministic
---
.../net/taler/merchantpos/order/Definitions.kt | 54 ++++++++++++++++------
.../net/taler/merchantpos/order/OrderManager.kt | 10 ++--
.../taler/merchantpos/order/OrderStateFragment.kt | 54 ++++++++++++++--------
.../taler/merchantpos/payment/PaymentManager.kt | 2 +-
4 files changed, 81 insertions(+), 39 deletions(-)
diff --git a/app/src/main/java/net/taler/merchantpos/order/Definitions.kt
b/app/src/main/java/net/taler/merchantpos/order/Definitions.kt
index ce2e464..872f2f5 100644
--- a/app/src/main/java/net/taler/merchantpos/order/Definitions.kt
+++ b/app/src/main/java/net/taler/merchantpos/order/Definitions.kt
@@ -1,5 +1,6 @@
package net.taler.merchantpos.order
+import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonProperty
import net.taler.merchantpos.Amount
@@ -24,9 +25,24 @@ data class ConfigProduct(
override val price: String,
@JsonProperty("delivery_location")
override val location: String?,
- val categories: List<Int>
+ val categories: List<Int>,
+ @JsonIgnore
+ val quantity: Int = 0
) : Product {
val priceAsDouble by lazy { Amount.fromString(price).amount.toDouble() }
+
+ override fun equals(other: Any?): Boolean {
+ return other is ConfigProduct && id == other.id
+ }
+
+ override fun hashCode(): Int {
+ var result = id.hashCode()
+ result = 31 * result + description.hashCode()
+ result = 31 * result + price.hashCode()
+ result = 31 * result + (location?.hashCode() ?: 0)
+ result = 31 * result + categories.hashCode()
+ return result
+ }
}
data class ContractProduct(
@@ -38,25 +54,25 @@ data class ContractProduct(
override val location: String?,
val quantity: Int
) : Product {
- constructor(product: ConfigProduct, quantity: Int) : this(
+ constructor(product: ConfigProduct) : this(
product.id,
product.description,
product.price,
product.location,
- quantity
+ product.quantity
)
}
data class Order(val availableCategories: Map<Int, Category>) {
- val products = HashMap<ConfigProduct, Int>()
+ val products = ArrayList<ConfigProduct>()
val summary: String
get() {
val categories = HashMap<Category, Int>()
- products.forEach { (product, quantity) ->
+ products.forEach { product ->
val categoryId = product.categories[0]
val category = availableCategories.getValue(categoryId)
val oldQuantity = categories[category] ?: 0
- categories[category] = oldQuantity + quantity
+ categories[category] = oldQuantity + product.quantity
}
return categories.map { (category, quantity) ->
"$quantity x ${category.name}"
@@ -65,9 +81,9 @@ data class Order(val availableCategories: Map<Int, Category>)
{
val total: Double
get() {
var total = 0.0
- products.forEach { (product, quantity) ->
+ products.forEach { product ->
val price = product.priceAsDouble
- total += price * quantity
+ total += price * product.quantity
}
return total
}
@@ -75,17 +91,25 @@ data class Order(val availableCategories: Map<Int,
Category>) {
get() = String.format("%.2f", total)
operator fun plus(product: ConfigProduct): Order {
- products[product] = (products[product] ?: 0) + 1
+ val i = products.indexOf(product)
+ if (i == -1) {
+ products.add(product.copy(quantity = 1))
+ } else {
+ val quantity = products[i].quantity
+ products[i] = products[i].copy(quantity = quantity + 1)
+ }
return this
}
operator fun minus(product: ConfigProduct): Order {
- var quantity = products[product] ?: throw IllegalStateException()
- quantity -= 1
- if (quantity > 0) products[product] = quantity
- else products.remove(product)
+ val i = products.indexOf(product)
+ if (i == -1) return this
+ val quantity = products[i].quantity
+ if (quantity <= 1) {
+ products.remove(product)
+ } else {
+ products[i] = products[i].copy(quantity = quantity - 1)
+ }
return this
}
}
-
-typealias OrderLine = Pair<ConfigProduct, Int>
diff --git a/app/src/main/java/net/taler/merchantpos/order/OrderManager.kt
b/app/src/main/java/net/taler/merchantpos/order/OrderManager.kt
index 449d741..1ff04d8 100644
--- a/app/src/main/java/net/taler/merchantpos/order/OrderManager.kt
+++ b/app/src/main/java/net/taler/merchantpos/order/OrderManager.kt
@@ -41,7 +41,7 @@ class OrderManager(private val mapper: ObjectMapper) :
ConfigurationReceiver {
private val mRestartState = MutableLiveData<RestartState>().apply { value
= DISABLED }
internal val restartState: LiveData<RestartState> = mRestartState
- private val mSelectedOrderLine = MutableLiveData<OrderLine>()
+ private val mSelectedOrderLine = MutableLiveData<ConfigProduct>()
internal val modifyOrderAllowed =
CombinedLiveData(restartState, mSelectedOrderLine) { restartState,
selectedOrderLine ->
@@ -134,20 +134,20 @@ class OrderManager(private val mapper: ObjectMapper) :
ConfigurationReceiver {
}
@UiThread
- fun selectOrderLine(orderLine: OrderLine?) {
- mSelectedOrderLine.value = orderLine
+ fun selectOrderLine(product: ConfigProduct?) {
+ mSelectedOrderLine.value = product
}
@UiThread
fun increaseSelectedOrderLine() {
val orderLine = mSelectedOrderLine.value ?: throw
IllegalStateException()
- addProduct(orderLine.first)
+ addProduct(orderLine)
}
@UiThread
fun decreaseSelectedOrderLine() {
val orderLine = mSelectedOrderLine.value ?: throw
IllegalStateException()
- removeProduct(orderLine.first)
+ removeProduct(orderLine)
}
}
diff --git
a/app/src/main/java/net/taler/merchantpos/order/OrderStateFragment.kt
b/app/src/main/java/net/taler/merchantpos/order/OrderStateFragment.kt
index 240ee3b..3988f17 100644
--- a/app/src/main/java/net/taler/merchantpos/order/OrderStateFragment.kt
+++ b/app/src/main/java/net/taler/merchantpos/order/OrderStateFragment.kt
@@ -14,6 +14,8 @@ import androidx.recyclerview.selection.ItemKeyProvider
import androidx.recyclerview.selection.SelectionPredicates
import androidx.recyclerview.selection.SelectionTracker
import androidx.recyclerview.selection.StorageStrategy
+import androidx.recyclerview.widget.AsyncListDiffer
+import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Adapter
@@ -24,7 +26,6 @@ import net.taler.merchantpos.R
import net.taler.merchantpos.order.OrderAdapter.OrderLineLookup
import net.taler.merchantpos.order.OrderAdapter.OrderViewHolder
-
class OrderStateFragment : Fragment() {
private val viewModel: MainViewModel by activityViewModels()
@@ -67,7 +68,14 @@ class OrderStateFragment : Fragment() {
this.tracker = tracker
orderManager.order.observe(viewLifecycleOwner, Observer { order ->
- adapter.setItems(order.products)
+ adapter.setItems(order.products) {
+ // workaround for bug: SelectionObserver doesn't update when
removing selected item
+ if (tracker.hasSelection()) {
+ val key = tracker.selection.first()
+ val product = order.products.find { it.id == key }
+ if (product == null) tracker.clearSelection()
+ }
+ }
})
orderManager.orderTotal.observe(viewLifecycleOwner, Observer {
orderTotal ->
if (orderTotal == 0.0) {
@@ -89,9 +97,18 @@ private class OrderAdapter : Adapter<OrderViewHolder>() {
lateinit var tracker: SelectionTracker<String>
val keyProvider = OrderKeyProvider()
- private val orderLines = ArrayList<OrderLine>()
+ private val itemCallback = object : DiffUtil.ItemCallback<ConfigProduct>()
{
+ override fun areItemsTheSame(oldItem: ConfigProduct, newItem:
ConfigProduct): Boolean {
+ return oldItem == newItem
+ }
- override fun getItemCount() = orderLines.size
+ override fun areContentsTheSame(oldItem: ConfigProduct, newItem:
ConfigProduct): Boolean {
+ return oldItem.quantity == newItem.quantity
+ }
+ }
+ private val differ = AsyncListDiffer<ConfigProduct>(this, itemCallback)
+
+ override fun getItemCount() = differ.currentList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
OrderViewHolder {
val view =
@@ -100,18 +117,19 @@ private class OrderAdapter : Adapter<OrderViewHolder>() {
}
override fun onBindViewHolder(holder: OrderViewHolder, position: Int) {
- val item = orderLines[position]
- holder.bind(item, tracker.isSelected(item.first.id))
+ val item = getItem(position)!!
+ holder.bind(item, tracker.isSelected(item.id))
}
- fun setItems(items: HashMap<ConfigProduct, Int>) {
- orderLines.clear()
- items.forEach { t -> orderLines.add(t.toPair()) }
- notifyDataSetChanged()
+ fun setItems(items: List<ConfigProduct>, commitCallback: () -> Unit) {
+ // toMutableList() is needed for some reason, otherwise doesn't update
adapter
+ differ.submitList(items.toMutableList(), commitCallback)
}
- fun getItemByKey(key: String): OrderLine? {
- return orderLines.find { it.first.id == key }
+ fun getItem(position: Int): ConfigProduct? = differ.currentList[position]
+
+ fun getItemByKey(key: String): ConfigProduct? {
+ return differ.currentList.find { it.id == key }
}
private inner class OrderViewHolder(private val v: View) : ViewHolder(v) {
@@ -119,18 +137,18 @@ private class OrderAdapter : Adapter<OrderViewHolder>() {
private val name: TextView = v.findViewById(R.id.name)
private val price: TextView = v.findViewById(R.id.price)
- fun bind(orderLine: OrderLine, selected: Boolean) {
+ fun bind(product: ConfigProduct, selected: Boolean) {
v.isActivated = selected
- quantity.text = orderLine.second.toString()
- name.text = orderLine.first.description
- price.text = String.format("%.2f", orderLine.first.priceAsDouble *
orderLine.second)
+ quantity.text = product.quantity.toString()
+ name.text = product.description
+ price.text = String.format("%.2f", product.priceAsDouble *
product.quantity)
}
}
private inner class OrderKeyProvider :
ItemKeyProvider<String>(SCOPE_MAPPED) {
- override fun getKey(position: Int) = orderLines[position].first.id
+ override fun getKey(position: Int) = getItem(position)!!.id
override fun getPosition(key: String): Int {
- return orderLines.indexOfFirst { it.first.id == key }
+ return differ.currentList.indexOfFirst { it.id == key }
}
}
diff --git a/app/src/main/java/net/taler/merchantpos/payment/PaymentManager.kt
b/app/src/main/java/net/taler/merchantpos/payment/PaymentManager.kt
index 30b417d..8167f86 100644
--- a/app/src/main/java/net/taler/merchantpos/payment/PaymentManager.kt
+++ b/app/src/main/java/net/taler/merchantpos/payment/PaymentManager.kt
@@ -79,7 +79,7 @@ class PaymentManager(
}
private fun Order.getProductsJson(): JSONArray {
- val contractProducts = products.map { ContractProduct(it.key,
it.value) }
+ val contractProducts = products.map { ContractProduct(it) }
val productsStr = mapper.writeValueAsString(contractProducts)
return JSONArray(productsStr)
}
--
To stop receiving notification emails like this one, please contact
address@hidden.
- [taler-merchant-terminal-android] 08/19: Use actual taler icon for the app, (continued)
- [taler-merchant-terminal-android] 08/19: Use actual taler icon for the app, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 09/19: Factor out NFC code from MainActivity, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 06/19: Create payments directly from the order, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 04/19: Fetch merchant config from central configuration JSON, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 02/19: Add screen to process an order, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 18/19: Don't talk about NFC if it is not supported, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 14/19: Use product categories for order summary, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 11/19: Allow user to decide if they want to save password, add FORGET option, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 13/19: Make NFC and QR code re-useable in another app, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 15/19: Introduce different product classes for re-use in other taler apps, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 17/19: Make order sorting deterministic,
gnunet <=
- [taler-merchant-terminal-android] 12/19: Fix invalid product configuration, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 19/19: Check for duplicate product IDs, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 10/19: Require valid configuration before showing UI, gnunet, 2020/02/21
- [taler-merchant-terminal-android] 16/19: Allow editing order with -1 and +1 buttons, gnunet, 2020/02/21