diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/DefaultOrderListItemLookup.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/DefaultOrderListItemLookup.kt index d1b04ccd209..51e469c0632 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/DefaultOrderListItemLookup.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/DefaultOrderListItemLookup.kt @@ -30,12 +30,3 @@ class DefaultOrderItemDetailsLookup( override fun getPosition() = position override fun getSelectionKey() = orderId } - -class SelectableOrderItemDetailsLookup( - private val position: Int, - private val orderId: Long -) : ItemDetailsLookup.ItemDetails() { - override fun getPosition() = position - override fun getSelectionKey() = orderId - override fun inSelectionHotspot(e: MotionEvent) = true -} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderSelectionItemKeyProvider.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderSelectionItemKeyProvider.kt index b776f59bedb..f332adcac4f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderSelectionItemKeyProvider.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderSelectionItemKeyProvider.kt @@ -17,10 +17,6 @@ class OrderSelectionItemKeyProvider(private val recyclerView: RecyclerView) : } } - override fun getPosition(key: Long): Int { - return (recyclerView.adapter as? OrderListAdapter)?.currentList - ?.indexOfFirst { item -> - item is OrderListItemUIType.OrderListItemUI && item.orderId == key - } ?: RecyclerView.NO_POSITION - } + override fun getPosition(key: Long): Int = + (recyclerView.adapter as? OrderListAdapter)?.orderIdAndPosition[key] ?: RecyclerView.NO_POSITION } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListAdapter.kt index 5eee41474ed..8e54f1bf0a3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListAdapter.kt @@ -25,6 +25,7 @@ import com.woocommerce.android.ui.orders.list.OrderListItemUIType.SectionHeader import com.woocommerce.android.util.CurrencyFormatter import com.woocommerce.android.widgets.tags.TagView import org.wordpress.android.fluxc.model.WCOrderStatusModel + class OrderListAdapter( val listener: OrderListListener, val currencyFormatter: CurrencyFormatter @@ -38,6 +39,7 @@ class OrderListAdapter( var activeOrderStatusMap: Map = emptyMap() var allOrderIds: List = listOf() var tracker: SelectionTracker? = null + var orderIdAndPosition = mutableMapOf() override fun getItemViewType(position: Int): Int { return when (getItem(position)) { @@ -61,10 +63,12 @@ class OrderListAdapter( ) ) } + VIEW_TYPE_LOADING -> { val view = inflater.inflate(R.layout.skeleton_order_list_item_auto, parent, false) LoadingViewHolder(view) } + VIEW_TYPE_SECTION_HEADER -> { SectionHeaderViewHolder( OrderListHeaderBinding.inflate( @@ -74,6 +78,7 @@ class OrderListAdapter( ) ) } + else -> { // Fail fast if a new view type is added so we can handle it throw IllegalStateException("The view type '$viewType' needs to be handled") @@ -97,7 +102,9 @@ class OrderListAdapter( allOrderIds, isActivated = tracker?.isSelected(item.orderId) ?: false ) + orderIdAndPosition[item.orderId] = position } + is SectionHeaderViewHolder -> { if (BuildConfig.DEBUG && item !is SectionHeader) { error( @@ -107,6 +114,7 @@ class OrderListAdapter( } holder.onBind((item as SectionHeader)) } + else -> {} } } @@ -126,7 +134,11 @@ class OrderListAdapter( fun setOrderStatusOptions(orderStatusOptions: Map) { if (orderStatusOptions.keys != activeOrderStatusMap.keys) { this.activeOrderStatusMap = orderStatusOptions - notifyDataSetChanged() + for (position in 0 until itemCount) { + if (getItem(position) is OrderListItemUI) { + notifyItemChanged(position) + } + } } } @@ -184,6 +196,7 @@ class OrderListAdapter( viewBinding.root.context.getColor(R.color.color_item_selected) ) } + else -> { viewBinding.orderItemLayout.setBackgroundColor(Color.TRANSPARENT) } @@ -209,6 +222,7 @@ class OrderListAdapter( extras[SwipeToComplete.OLD_STATUS] = orderItemUI.status this.itemView.setOnClickListener { + if (shouldPreventDetailNavigation(orderId)) return@setOnClickListener listener.openOrderDetail( orderId = orderItemUI.orderId, allOrderIds = allOrderIds, @@ -218,6 +232,23 @@ class OrderListAdapter( } } + // Some edge cases in order selection mode, like tapping the screen with 4 fingers or using TalkBack, + // cause the order's onClick listener to gain focus over the selection tracker. + // This quick fix will prevent the app from entering an unexpected status when the app is in selection mode. + private fun shouldPreventDetailNavigation(orderId: Long): Boolean { + if (tracker?.selection?.size() != 0) { + tracker?.let { selectionTracker -> + if (selectionTracker.isSelected(orderId)) { + selectionTracker.deselect(orderId) + } else { + selectionTracker.select(orderId) + } + } + return true + } + return false + } + /** * Converts the order status label into an [OrderStatusTag], creates the associated [TagView], * and add it to the holder. No need to trim the label text since this is done in [OrderStatusTag] diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListFragment.kt index 98b1c3c313f..b9705b75ae7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListFragment.kt @@ -356,7 +356,11 @@ class OrderListFragment : private fun adjustLayoutForNonTablet(savedInstanceState: Bundle?) { if (wasLastWindowSizeLargerThanCompact(savedInstanceState)) { - displayDetailPaneOnly() + if (viewModel.isSelecting()) { + displayListPaneOnly() + } else { + displayDetailPaneOnly() + } } else { displayListPaneOnly() } @@ -406,6 +410,23 @@ class OrderListFragment : outState.putBoolean(LAST_WINDOW_SIZE_WAS_LARGER_THAN_COMPACT, true) } } + tracker?.onSaveInstanceState(outState) + viewModel.orderIdAndPositionBackup = + ((binding.orderListView.ordersList.adapter as? OrderListAdapter)?.orderIdAndPosition ?: emptyMap()) + as MutableMap + } + + override fun onViewStateRestored(savedInstanceState: Bundle?) { + tracker?.run { + onRestoreInstanceState(savedInstanceState) + (binding.orderListView.ordersList.adapter as? OrderListAdapter)?.orderIdAndPosition = + viewModel.orderIdAndPositionBackup + if (hasSelection()) { + setItemsSelected(selection.toList(), true) + } + } + + super.onViewStateRestored(savedInstanceState) } override fun onDestroyView() { @@ -414,6 +435,8 @@ class OrderListFragment : searchView = null orderListMenu = null searchMenuItem = null + tracker = null + actionMode = null super.onDestroyView() _binding = null } @@ -608,9 +631,11 @@ class OrderListFragment : actionText = event.actionText, action = event.action ) + is OrderListViewModel.OrderListEvent.RetryLoadingOrders -> refreshOrders() is OrderListViewModel.OrderListEvent.OpenOrderCreationWithSimplePaymentsMigration -> openOrderCreationFragment(indicateSimplePaymentsMigration = true) + is OrderListViewModel.OrderListEvent.ShowUpdateStatusDialog -> { showBulkUpdateStatusDialog(event.currentStatus, event.orderStatusList) } @@ -627,6 +652,7 @@ class OrderListFragment : viewModel.trashOrder(event.orderId) selectedOrder.selectOrder(-1L) } + else -> event.isHandled = false } } @@ -893,23 +919,6 @@ class OrderListFragment : binding.orderListView.submitPagedList(pagedListData) } - // Some edge cases in order selection mode, like tapping the screen with 4 fingers or using TalkBack, - // cause the order's onClick listener to gain focus over the selection tracker. - // This quick fix will prevent the app from entering an unexpected status when the app is in selection mode. - private fun shouldPreventDetailNavigation(orderId: Long): Boolean { - if (viewModel.isSelecting()) { - tracker?.let { selectionTracker -> - if (selectionTracker.isSelected(orderId)) { - selectionTracker.deselect(orderId) - } else { - selectionTracker.select(orderId) - } - } - return true - } - return false - } - override fun openOrderDetail( orderId: Long, allOrderIds: List, @@ -917,8 +926,6 @@ class OrderListFragment : sharedView: View?, startPaymentsFlow: Boolean, ) { - if (shouldPreventDetailNavigation(orderId)) return - viewModel.trackOrderClickEvent( orderId, orderStatus, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt index 927ec1c10af..28fdc4ab847 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt @@ -181,6 +181,8 @@ class OrderListViewModel @Inject constructor( val orderId: LiveData = savedState.getLiveData("orderId") + var orderIdAndPositionBackup = mutableMapOf() + private val _emptyViewType: ThrottleLiveData by lazy { ThrottleLiveData( offset = EMPTY_VIEW_THROTTLE,