Skip to content

Commit 37c5583

Browse files
authored
Merge pull request #13227 from woocommerce/task/bulk-order-config-change
[Bulk Update Orders] Persist selection on configuration change and load more
2 parents 22e1f7f + 5639575 commit 37c5583

File tree

5 files changed

+63
-36
lines changed

5 files changed

+63
-36
lines changed

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/DefaultOrderListItemLookup.kt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,3 @@ class DefaultOrderItemDetailsLookup(
3030
override fun getPosition() = position
3131
override fun getSelectionKey() = orderId
3232
}
33-
34-
class SelectableOrderItemDetailsLookup(
35-
private val position: Int,
36-
private val orderId: Long
37-
) : ItemDetailsLookup.ItemDetails<Long>() {
38-
override fun getPosition() = position
39-
override fun getSelectionKey() = orderId
40-
override fun inSelectionHotspot(e: MotionEvent) = true
41-
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderSelectionItemKeyProvider.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ class OrderSelectionItemKeyProvider(private val recyclerView: RecyclerView) :
1717
}
1818
}
1919

20-
override fun getPosition(key: Long): Int {
21-
return (recyclerView.adapter as? OrderListAdapter)?.currentList
22-
?.indexOfFirst { item ->
23-
item is OrderListItemUIType.OrderListItemUI && item.orderId == key
24-
} ?: RecyclerView.NO_POSITION
25-
}
20+
override fun getPosition(key: Long): Int =
21+
(recyclerView.adapter as? OrderListAdapter)?.orderIdAndPosition[key] ?: RecyclerView.NO_POSITION
2622
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListAdapter.kt

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.woocommerce.android.ui.orders.list.OrderListItemUIType.SectionHeader
2525
import com.woocommerce.android.util.CurrencyFormatter
2626
import com.woocommerce.android.widgets.tags.TagView
2727
import org.wordpress.android.fluxc.model.WCOrderStatusModel
28+
2829
class OrderListAdapter(
2930
val listener: OrderListListener,
3031
val currencyFormatter: CurrencyFormatter
@@ -38,6 +39,7 @@ class OrderListAdapter(
3839
var activeOrderStatusMap: Map<String, WCOrderStatusModel> = emptyMap()
3940
var allOrderIds: List<Long> = listOf()
4041
var tracker: SelectionTracker<Long>? = null
42+
var orderIdAndPosition = mutableMapOf<Long, Int>()
4143

4244
override fun getItemViewType(position: Int): Int {
4345
return when (getItem(position)) {
@@ -61,10 +63,12 @@ class OrderListAdapter(
6163
)
6264
)
6365
}
66+
6467
VIEW_TYPE_LOADING -> {
6568
val view = inflater.inflate(R.layout.skeleton_order_list_item_auto, parent, false)
6669
LoadingViewHolder(view)
6770
}
71+
6872
VIEW_TYPE_SECTION_HEADER -> {
6973
SectionHeaderViewHolder(
7074
OrderListHeaderBinding.inflate(
@@ -74,6 +78,7 @@ class OrderListAdapter(
7478
)
7579
)
7680
}
81+
7782
else -> {
7883
// Fail fast if a new view type is added so we can handle it
7984
throw IllegalStateException("The view type '$viewType' needs to be handled")
@@ -97,7 +102,9 @@ class OrderListAdapter(
97102
allOrderIds,
98103
isActivated = tracker?.isSelected(item.orderId) ?: false
99104
)
105+
orderIdAndPosition[item.orderId] = position
100106
}
107+
101108
is SectionHeaderViewHolder -> {
102109
if (BuildConfig.DEBUG && item !is SectionHeader) {
103110
error(
@@ -107,6 +114,7 @@ class OrderListAdapter(
107114
}
108115
holder.onBind((item as SectionHeader))
109116
}
117+
110118
else -> {}
111119
}
112120
}
@@ -126,7 +134,11 @@ class OrderListAdapter(
126134
fun setOrderStatusOptions(orderStatusOptions: Map<String, WCOrderStatusModel>) {
127135
if (orderStatusOptions.keys != activeOrderStatusMap.keys) {
128136
this.activeOrderStatusMap = orderStatusOptions
129-
notifyDataSetChanged()
137+
for (position in 0 until itemCount) {
138+
if (getItem(position) is OrderListItemUI) {
139+
notifyItemChanged(position)
140+
}
141+
}
130142
}
131143
}
132144

@@ -184,6 +196,7 @@ class OrderListAdapter(
184196
viewBinding.root.context.getColor(R.color.color_item_selected)
185197
)
186198
}
199+
187200
else -> {
188201
viewBinding.orderItemLayout.setBackgroundColor(Color.TRANSPARENT)
189202
}
@@ -209,6 +222,7 @@ class OrderListAdapter(
209222
extras[SwipeToComplete.OLD_STATUS] = orderItemUI.status
210223

211224
this.itemView.setOnClickListener {
225+
if (shouldPreventDetailNavigation(orderId)) return@setOnClickListener
212226
listener.openOrderDetail(
213227
orderId = orderItemUI.orderId,
214228
allOrderIds = allOrderIds,
@@ -218,6 +232,23 @@ class OrderListAdapter(
218232
}
219233
}
220234

235+
// Some edge cases in order selection mode, like tapping the screen with 4 fingers or using TalkBack,
236+
// cause the order's onClick listener to gain focus over the selection tracker.
237+
// This quick fix will prevent the app from entering an unexpected status when the app is in selection mode.
238+
private fun shouldPreventDetailNavigation(orderId: Long): Boolean {
239+
if (tracker?.selection?.size() != 0) {
240+
tracker?.let { selectionTracker ->
241+
if (selectionTracker.isSelected(orderId)) {
242+
selectionTracker.deselect(orderId)
243+
} else {
244+
selectionTracker.select(orderId)
245+
}
246+
}
247+
return true
248+
}
249+
return false
250+
}
251+
221252
/**
222253
* Converts the order status label into an [OrderStatusTag], creates the associated [TagView],
223254
* and add it to the holder. No need to trim the label text since this is done in [OrderStatusTag]

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListFragment.kt

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,11 @@ class OrderListFragment :
356356

357357
private fun adjustLayoutForNonTablet(savedInstanceState: Bundle?) {
358358
if (wasLastWindowSizeLargerThanCompact(savedInstanceState)) {
359-
displayDetailPaneOnly()
359+
if (viewModel.isSelecting()) {
360+
displayListPaneOnly()
361+
} else {
362+
displayDetailPaneOnly()
363+
}
360364
} else {
361365
displayListPaneOnly()
362366
}
@@ -406,6 +410,23 @@ class OrderListFragment :
406410
outState.putBoolean(LAST_WINDOW_SIZE_WAS_LARGER_THAN_COMPACT, true)
407411
}
408412
}
413+
tracker?.onSaveInstanceState(outState)
414+
viewModel.orderIdAndPositionBackup =
415+
((binding.orderListView.ordersList.adapter as? OrderListAdapter)?.orderIdAndPosition ?: emptyMap())
416+
as MutableMap<Long, Int>
417+
}
418+
419+
override fun onViewStateRestored(savedInstanceState: Bundle?) {
420+
tracker?.run {
421+
onRestoreInstanceState(savedInstanceState)
422+
(binding.orderListView.ordersList.adapter as? OrderListAdapter)?.orderIdAndPosition =
423+
viewModel.orderIdAndPositionBackup
424+
if (hasSelection()) {
425+
setItemsSelected(selection.toList(), true)
426+
}
427+
}
428+
429+
super.onViewStateRestored(savedInstanceState)
409430
}
410431

411432
override fun onDestroyView() {
@@ -414,6 +435,8 @@ class OrderListFragment :
414435
searchView = null
415436
orderListMenu = null
416437
searchMenuItem = null
438+
tracker = null
439+
actionMode = null
417440
super.onDestroyView()
418441
_binding = null
419442
}
@@ -608,9 +631,11 @@ class OrderListFragment :
608631
actionText = event.actionText,
609632
action = event.action
610633
)
634+
611635
is OrderListViewModel.OrderListEvent.RetryLoadingOrders -> refreshOrders()
612636
is OrderListViewModel.OrderListEvent.OpenOrderCreationWithSimplePaymentsMigration ->
613637
openOrderCreationFragment(indicateSimplePaymentsMigration = true)
638+
614639
is OrderListViewModel.OrderListEvent.ShowUpdateStatusDialog -> {
615640
showBulkUpdateStatusDialog(event.currentStatus, event.orderStatusList)
616641
}
@@ -627,6 +652,7 @@ class OrderListFragment :
627652
viewModel.trashOrder(event.orderId)
628653
selectedOrder.selectOrder(-1L)
629654
}
655+
630656
else -> event.isHandled = false
631657
}
632658
}
@@ -893,32 +919,13 @@ class OrderListFragment :
893919
binding.orderListView.submitPagedList(pagedListData)
894920
}
895921

896-
// Some edge cases in order selection mode, like tapping the screen with 4 fingers or using TalkBack,
897-
// cause the order's onClick listener to gain focus over the selection tracker.
898-
// This quick fix will prevent the app from entering an unexpected status when the app is in selection mode.
899-
private fun shouldPreventDetailNavigation(orderId: Long): Boolean {
900-
if (viewModel.isSelecting()) {
901-
tracker?.let { selectionTracker ->
902-
if (selectionTracker.isSelected(orderId)) {
903-
selectionTracker.deselect(orderId)
904-
} else {
905-
selectionTracker.select(orderId)
906-
}
907-
}
908-
return true
909-
}
910-
return false
911-
}
912-
913922
override fun openOrderDetail(
914923
orderId: Long,
915924
allOrderIds: List<Long>,
916925
orderStatus: String,
917926
sharedView: View?,
918927
startPaymentsFlow: Boolean,
919928
) {
920-
if (shouldPreventDetailNavigation(orderId)) return
921-
922929
viewModel.trackOrderClickEvent(
923930
orderId,
924931
orderStatus,

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ class OrderListViewModel @Inject constructor(
181181

182182
val orderId: LiveData<Long> = savedState.getLiveData<Long>("orderId")
183183

184+
var orderIdAndPositionBackup = mutableMapOf<Long, Int>()
185+
184186
private val _emptyViewType: ThrottleLiveData<EmptyViewType?> by lazy {
185187
ThrottleLiveData(
186188
offset = EMPTY_VIEW_THROTTLE,

0 commit comments

Comments
 (0)