From 17b684b004ee062dcd22909c846e0d8ce2dce21d Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Tue, 30 Jan 2024 18:34:07 -0500 Subject: [PATCH 01/19] Added a function that checks to see if a view is visible in scrollview. --- .../kotlin/com/woocommerce/android/util/ViewUtils.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ViewUtils.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ViewUtils.kt index bda46067d06..2e2f2908b5f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ViewUtils.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ViewUtils.kt @@ -1,6 +1,9 @@ package com.woocommerce.android.util import android.content.Context +import android.graphics.Rect +import android.view.View +import android.widget.ScrollView /** * Converts a pixel to a density pixel to match the density of @@ -10,3 +13,11 @@ fun getDensityPixel(context: Context, dps: Int): Int { val scale = context.resources.displayMetrics.density return (dps * scale + 0.5f).toInt() } + +fun isViewVisibleInScrollView(scrollView: ScrollView, targetView: View): Boolean { + val scrollBounds = Rect() + scrollView.getDrawingRect(scrollBounds) + val top = targetView.y + scrollView.y + val bottom = top + targetView.height + return scrollBounds.top < top && scrollBounds.bottom > bottom +} From d6660b2716e9aa133d8b12cdb3a096ae633f4246 Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Tue, 30 Jan 2024 18:34:19 -0500 Subject: [PATCH 02/19] Added the id that is needed to the scroll view. --- .../src/main/res/layout/fragment_edit_shipping_label_address.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml b/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml index f0fd9547657..d77d29d27cc 100644 --- a/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml +++ b/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml @@ -2,6 +2,7 @@ From b30e4f0bcc3f269eb125489ce76ed3dc745d1b5a Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Tue, 30 Jan 2024 18:35:00 -0500 Subject: [PATCH 03/19] Implemented logic to determine where the error exists and scrolls to it. --- .../EditShippingLabelAddressFragment.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt index 0e22edcb5f8..6ec017c0a71 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt @@ -40,6 +40,7 @@ import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAd import com.woocommerce.android.ui.searchfilter.SearchFilterItem import com.woocommerce.android.util.ActivityUtils.dialPhoneNumber import com.woocommerce.android.util.UiHelpers +import com.woocommerce.android.util.isViewVisibleInScrollView import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ExitWithResult import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowSnackbar @@ -216,6 +217,35 @@ class EditShippingLabelAddressFragment : new.isContactCustomerButtonVisible.takeIfNotEqualTo(old?.isContactCustomerButtonVisible) { isVisible -> binding.contactCustomerButton.isVisible = isVisible } + + scrollToFirstErrorFieldIfNeeded(new, binding) + } + } + + private fun scrollToFirstErrorFieldIfNeeded( + viewState: EditShippingLabelAddressViewModel.ViewState, + binding: FragmentEditShippingLabelAddressBinding + ) { + val firstErrorField: Pair, View>? = listOf, View>>( + viewState.nameField to binding.name, + viewState.companyField to binding.company, + viewState.phoneField to binding.phone, + viewState.address1Field to binding.address1, + viewState.address2Field to binding.address2, + viewState.cityField to binding.city, + viewState.zipField to binding.zip, + viewState.stateField to if (viewState.isStateFieldSpinner == true) binding.stateSpinner else binding.state, + viewState.countryField to binding.countrySpinner + ).firstOrNull { it.first.error != null } + + firstErrorField?.let { (_, view) -> + if (!isViewVisibleInScrollView(binding.scrollView, view)) { + ActivityUtils.hideKeyboard(requireActivity()) + + binding.scrollView.post { + binding.scrollView.smoothScrollTo(0, view.top) + } + } } } From 722609306f2f162300df632e4838504d21a6426f Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Tue, 30 Jan 2024 18:39:29 -0500 Subject: [PATCH 04/19] Attempted to clear focus and then request it. --- .../creation/EditShippingLabelAddressFragment.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt index 6ec017c0a71..a291b773cb9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt @@ -240,10 +240,13 @@ class EditShippingLabelAddressFragment : firstErrorField?.let { (_, view) -> if (!isViewVisibleInScrollView(binding.scrollView, view)) { + binding.root.clearFocus() + ActivityUtils.hideKeyboard(requireActivity()) binding.scrollView.post { binding.scrollView.smoothScrollTo(0, view.top) + view.requestFocus() } } } From c97bfd881ae8b9800ae81782dfa97900e980f64a Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Wed, 31 Jan 2024 09:52:35 -0500 Subject: [PATCH 05/19] Moving the scroll logic to an actual event since it should happen once. --- .../creation/CreateShippingLabelEvent.kt | 1 + .../EditShippingLabelAddressFragment.kt | 33 +++++++++++-------- .../EditShippingLabelAddressViewModel.kt | 2 ++ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt index d04195e2f53..b39ea2438f7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt @@ -68,4 +68,5 @@ sealed class CreateShippingLabelEvent : MultiLiveEvent.Event() { data class ShowPrintShippingLabels(val orderId: Long, val labels: List) : CreateShippingLabelEvent() object ShowWooDiscountBottomSheet : CreateShippingLabelEvent() + data class ScrollToFirstErrorField(val viewState: EditShippingLabelAddressViewModel.ViewState) : CreateShippingLabelEvent() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt index a291b773cb9..4627d0e3201 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt @@ -70,6 +70,9 @@ class EditShippingLabelAddressFragment : val viewModel: EditShippingLabelAddressViewModel by viewModels() + private var _binding: FragmentEditShippingLabelAddressBinding? = null + private val binding get() = _binding!! + private var screenTitle = "" set(value) { field = value @@ -93,12 +96,17 @@ class EditShippingLabelAddressFragment : } } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) requireActivity().addMenuProvider(this, viewLifecycleOwner) - val binding = FragmentEditShippingLabelAddressBinding.bind(view) + _binding = FragmentEditShippingLabelAddressBinding.bind(view) initializeViewModel(binding) initializeViews(binding) @@ -217,8 +225,6 @@ class EditShippingLabelAddressFragment : new.isContactCustomerButtonVisible.takeIfNotEqualTo(old?.isContactCustomerButtonVisible) { isVisible -> binding.contactCustomerButton.isVisible = isVisible } - - scrollToFirstErrorFieldIfNeeded(new, binding) } } @@ -226,7 +232,7 @@ class EditShippingLabelAddressFragment : viewState: EditShippingLabelAddressViewModel.ViewState, binding: FragmentEditShippingLabelAddressBinding ) { - val firstErrorField: Pair, View>? = listOf, View>>( + val firstErrorField: Pair, View>? = listOf( viewState.nameField to binding.name, viewState.companyField to binding.company, viewState.phoneField to binding.phone, @@ -238,17 +244,16 @@ class EditShippingLabelAddressFragment : viewState.countryField to binding.countrySpinner ).firstOrNull { it.first.error != null } - firstErrorField?.let { (_, view) -> - if (!isViewVisibleInScrollView(binding.scrollView, view)) { - binding.root.clearFocus() + firstErrorField?.let { (_, errorView) -> + binding.root.clearFocus() - ActivityUtils.hideKeyboard(requireActivity()) + ActivityUtils.hideKeyboard(requireActivity()) - binding.scrollView.post { - binding.scrollView.smoothScrollTo(0, view.top) - view.requestFocus() - } - } + binding.scrollView.postDelayed({ + binding.scrollView.smoothScrollTo(0, errorView.top) + + errorView.requestFocus() + }, 300) } } @@ -298,6 +303,8 @@ class EditShippingLabelAddressFragment : } is OpenMapWithAddress -> launchMapsWithAddress(event.address) is DialPhoneNumber -> dialPhoneNumber(requireContext(), event.phoneNumber) + is CreateShippingLabelEvent.ScrollToFirstErrorField -> scrollToFirstErrorFieldIfNeeded(event.viewState, binding) + else -> event.isHandled = false } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt index d4099fa89f7..31f4ac48500 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt @@ -115,6 +115,8 @@ class EditShippingLabelAddressViewModel @Inject constructor( handleValidationResult(address, result) viewState = viewState.copy(isValidationProgressDialogVisible = false) } + }else { + triggerEvent(CreateShippingLabelEvent.ScrollToFirstErrorField(viewState)) } } From fe828e24f0ff921f709d07b05f89d87b2d7e7d56 Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Wed, 31 Jan 2024 11:44:09 -0500 Subject: [PATCH 06/19] Moved the logic used to trigger the various events to the viewmodel --- .../creation/CreateShippingLabelEvent.kt | 5 +- .../EditShippingLabelAddressFragment.kt | 57 ++++++++++--------- .../EditShippingLabelAddressViewModel.kt | 24 +++++++- 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt index b39ea2438f7..b484c215e80 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt @@ -68,5 +68,8 @@ sealed class CreateShippingLabelEvent : MultiLiveEvent.Event() { data class ShowPrintShippingLabels(val orderId: Long, val labels: List) : CreateShippingLabelEvent() object ShowWooDiscountBottomSheet : CreateShippingLabelEvent() - data class ScrollToFirstErrorField(val viewState: EditShippingLabelAddressViewModel.ViewState) : CreateShippingLabelEvent() + data class ScrollToFirstErrorField( + val field: EditShippingLabelAddressViewModel.Field, + val isStateFieldSpinner: Boolean? + ) : CreateShippingLabelEvent() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt index 4627d0e3201..4396deb9edd 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt @@ -64,7 +64,8 @@ class EditShippingLabelAddressFragment : const val EDIT_ADDRESS_CLOSED = "key_edit_address_dialog_closed" } - @Inject lateinit var uiMessageResolver: UIMessageResolver + @Inject + lateinit var uiMessageResolver: UIMessageResolver private var progressDialog: CustomProgressDialog? = null @@ -146,6 +147,7 @@ class EditShippingLabelAddressFragment : viewModel.onDoneButtonClicked() true } + else -> false } } @@ -228,33 +230,26 @@ class EditShippingLabelAddressFragment : } } - private fun scrollToFirstErrorFieldIfNeeded( - viewState: EditShippingLabelAddressViewModel.ViewState, - binding: FragmentEditShippingLabelAddressBinding - ) { - val firstErrorField: Pair, View>? = listOf( - viewState.nameField to binding.name, - viewState.companyField to binding.company, - viewState.phoneField to binding.phone, - viewState.address1Field to binding.address1, - viewState.address2Field to binding.address2, - viewState.cityField to binding.city, - viewState.zipField to binding.zip, - viewState.stateField to if (viewState.isStateFieldSpinner == true) binding.stateSpinner else binding.state, - viewState.countryField to binding.countrySpinner - ).firstOrNull { it.first.error != null } - - firstErrorField?.let { (_, errorView) -> - binding.root.clearFocus() - - ActivityUtils.hideKeyboard(requireActivity()) - - binding.scrollView.postDelayed({ - binding.scrollView.smoothScrollTo(0, errorView.top) - - errorView.requestFocus() - }, 300) + private fun scrollToFirstErrorField(field: EditShippingLabelAddressViewModel.Field, isStateFieldSpinner: Boolean?) { + val errorView = when (field) { + Field.Name -> binding.name + Field.Company -> binding.company + Field.Phone -> binding.phone + Field.Address1 -> binding.address1 + Field.Address2 -> binding.address2 + Field.City -> binding.city + Field.Zip -> binding.zip + Field.State -> if (isStateFieldSpinner == true) binding.stateSpinner else binding.state + Field.Country -> binding.countrySpinner } + + binding.root.clearFocus() + ActivityUtils.hideKeyboard(requireActivity()) + + binding.scrollView.postDelayed({ + binding.scrollView.smoothScrollTo(0, errorView.top) + errorView.requestFocus() + }, 300) } @SuppressLint("SetTextI18n") @@ -273,6 +268,7 @@ class EditShippingLabelAddressFragment : ) findNavController().navigateSafely(action) } + is ShowCountrySelector -> { val action = EditShippingLabelAddressFragmentDirections.actionSearchFilterFragment( items = event.locations.map { @@ -287,6 +283,7 @@ class EditShippingLabelAddressFragment : ) findNavController().navigateSafely(action) } + is ShowStateSelector -> { val action = EditShippingLabelAddressFragmentDirections.actionSearchFilterFragment( items = event.locations.map { @@ -301,9 +298,13 @@ class EditShippingLabelAddressFragment : ) findNavController().navigateSafely(action) } + is OpenMapWithAddress -> launchMapsWithAddress(event.address) is DialPhoneNumber -> dialPhoneNumber(requireContext(), event.phoneNumber) - is CreateShippingLabelEvent.ScrollToFirstErrorField -> scrollToFirstErrorFieldIfNeeded(event.viewState, binding) + is CreateShippingLabelEvent.ScrollToFirstErrorField -> scrollToFirstErrorField( + event.field, + event.isStateFieldSpinner + ) else -> event.isHandled = false } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt index 31f4ac48500..7e58ba11def 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt @@ -115,8 +115,27 @@ class EditShippingLabelAddressViewModel @Inject constructor( handleValidationResult(address, result) viewState = viewState.copy(isValidationProgressDialogVisible = false) } - }else { - triggerEvent(CreateShippingLabelEvent.ScrollToFirstErrorField(viewState)) + } else { + triggerScrollToFirstErrorFieldEvent() + } + } + + private fun triggerScrollToFirstErrorFieldEvent() { + val firstErrorField = when { + viewState.nameField.error != null -> Field.Name + viewState.companyField.error != null -> Field.Company + viewState.phoneField.error != null -> Field.Phone + viewState.address1Field.error != null -> Field.Address1 + viewState.address2Field.error != null -> Field.Address2 + viewState.cityField.error != null -> Field.City + viewState.zipField.error != null -> Field.Zip + viewState.stateField.error != null -> Field.State + viewState.countryField.error != null -> Field.Country + else -> null + } + + firstErrorField?.let { + triggerEvent(CreateShippingLabelEvent.ScrollToFirstErrorField(it, viewState.isStateFieldSpinner)) } } @@ -149,6 +168,7 @@ class EditShippingLabelAddressViewModel @Inject constructor( ValidationResult.Valid -> { exitWithAddress(address) } + is ValidationResult.Invalid -> { val validationErrorMessage = getAddressErrorStringRes(result.message) viewState = viewState.copy( From 0efa3dd8c51ab7807523f986d92df178ad8842d1 Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Wed, 31 Jan 2024 12:17:02 -0500 Subject: [PATCH 07/19] Optimized the scrolling solution for the error view --- .../EditShippingLabelAddressFragment.kt | 10 +++------- .../EditShippingLabelAddressViewModel.kt | 18 +++++------------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt index 4396deb9edd..1256fb6c408 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt @@ -230,7 +230,7 @@ class EditShippingLabelAddressFragment : } } - private fun scrollToFirstErrorField(field: EditShippingLabelAddressViewModel.Field, isStateFieldSpinner: Boolean?) { + private fun scrollToFirstErrorField(field: Field, isStateFieldSpinner: Boolean?) { val errorView = when (field) { Field.Name -> binding.name Field.Company -> binding.company @@ -243,13 +243,9 @@ class EditShippingLabelAddressFragment : Field.Country -> binding.countrySpinner } - binding.root.clearFocus() - ActivityUtils.hideKeyboard(requireActivity()) - - binding.scrollView.postDelayed({ + if (!isViewVisibleInScrollView(binding.scrollView, errorView)) { binding.scrollView.smoothScrollTo(0, errorView.top) - errorView.requestFocus() - }, 300) + } } @SuppressLint("SetTextI18n") diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt index 7e58ba11def..91b00a8db7f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt @@ -121,24 +121,16 @@ class EditShippingLabelAddressViewModel @Inject constructor( } private fun triggerScrollToFirstErrorFieldEvent() { - val firstErrorField = when { - viewState.nameField.error != null -> Field.Name - viewState.companyField.error != null -> Field.Company - viewState.phoneField.error != null -> Field.Phone - viewState.address1Field.error != null -> Field.Address1 - viewState.address2Field.error != null -> Field.Address2 - viewState.cityField.error != null -> Field.City - viewState.zipField.error != null -> Field.Zip - viewState.stateField.error != null -> Field.State - viewState.countryField.error != null -> Field.Country - else -> null - } - + val firstErrorField = viewState.findFirstErrorField() firstErrorField?.let { triggerEvent(CreateShippingLabelEvent.ScrollToFirstErrorField(it, viewState.isStateFieldSpinner)) } } + private fun ViewState.findFirstErrorField(): Field? { + return Field.values().firstOrNull { this[it].error != null } + } + private fun loadCountriesAndStates() { launch { if (countries.isEmpty()) { From 8d0cb6c84fceff40cd4ffb70b77acb487da383f8 Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Wed, 31 Jan 2024 12:18:51 -0500 Subject: [PATCH 08/19] Show snackbar if all required fields aren't present. --- .../shippinglabels/creation/EditShippingLabelAddressViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt index 91b00a8db7f..ffd26e45383 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt @@ -116,6 +116,7 @@ class EditShippingLabelAddressViewModel @Inject constructor( viewState = viewState.copy(isValidationProgressDialogVisible = false) } } else { + triggerEvent(ShowSnackbar(R.string.shipping_label_address_data_invalid_snackbar_message)) triggerScrollToFirstErrorFieldEvent() } } From 7c41607a31ced55c6403c9b76d34a65f6ec0d313 Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Wed, 31 Jan 2024 15:24:11 -0500 Subject: [PATCH 09/19] Wrote unit tests. --- .../EditShippingLabelAddressViewModelTest.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt index 30db74a54f3..9933104c69e 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt @@ -380,4 +380,37 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { val viewState = viewModel.viewStateData.liveData.value!! assertThat(viewState.areAllRequiredFieldsValid).isTrue() } + + + @Test + fun `when validation fails for a set of fields, ScrollToFirstErrorField event is triggered with correct field`() = testBlocking { + + viewModel.onFieldEdited(Field.Name, "") + viewModel.onFieldEdited(Field.Company, "") + + var event: Event? = null + viewModel.event.observeForever { event = it } + + viewModel.onDoneButtonClicked() + + verify(addressValidator, never()).validateAddress(any(), any(), any()) + + assertThat(event).isInstanceOf(CreateShippingLabelEvent.ScrollToFirstErrorField::class.java) + if (event is CreateShippingLabelEvent.ScrollToFirstErrorField) { + assertThat((event as CreateShippingLabelEvent.ScrollToFirstErrorField).field).isEqualTo(Field.Name) + } + } + + @Test + fun `when all fields are valid, ScrollToFirstErrorField event is not triggered`() = testBlocking { + + var event: Event? = null + viewModel.event.observeForever { event = it } + + viewModel.onDoneButtonClicked() + + verify(addressValidator, atLeastOnce()).validateAddress(any(), any(), any()) + + assertThat(event).isNotInstanceOf(CreateShippingLabelEvent.ScrollToFirstErrorField::class.java) + } } From 0c264f12a9dd7ecdc18b3a1945719405bf99a736 Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Wed, 31 Jan 2024 15:49:06 -0500 Subject: [PATCH 10/19] added const for scroll delay and also requested focus for error view. --- .../creation/EditShippingLabelAddressFragment.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt index 1256fb6c408..e9e48082b61 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt @@ -2,6 +2,7 @@ package com.woocommerce.android.ui.orders.shippinglabels.creation import android.annotation.SuppressLint import android.content.ActivityNotFoundException +import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle @@ -9,7 +10,9 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View +import android.view.inputmethod.InputMethodManager import android.widget.Button +import android.widget.EditText import androidx.core.view.MenuProvider import androidx.core.view.isVisible import androidx.fragment.app.viewModels @@ -62,6 +65,7 @@ class EditShippingLabelAddressFragment : const val SELECT_STATE_REQUEST = "select_state_request" const val EDIT_ADDRESS_RESULT = "key_edit_address_dialog_result" const val EDIT_ADDRESS_CLOSED = "key_edit_address_dialog_closed" + const val ERROR_SCROLL_DELAY = 300L } @Inject @@ -244,7 +248,10 @@ class EditShippingLabelAddressFragment : } if (!isViewVisibleInScrollView(binding.scrollView, errorView)) { - binding.scrollView.smoothScrollTo(0, errorView.top) + binding.scrollView.postDelayed({ + binding.scrollView.smoothScrollTo(0, errorView.top) + errorView.requestFocus() + }, ERROR_SCROLL_DELAY) } } From c115272b494d9fd1c554a60f5125ec53b32f5318 Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Wed, 31 Jan 2024 15:58:15 -0500 Subject: [PATCH 11/19] Fixed detekt issues --- .../creation/EditShippingLabelAddressFragment.kt | 3 --- .../creation/EditShippingLabelAddressViewModelTest.kt | 1 - 2 files changed, 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt index e9e48082b61..6513755d72a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt @@ -2,7 +2,6 @@ package com.woocommerce.android.ui.orders.shippinglabels.creation import android.annotation.SuppressLint import android.content.ActivityNotFoundException -import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle @@ -10,9 +9,7 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View -import android.view.inputmethod.InputMethodManager import android.widget.Button -import android.widget.EditText import androidx.core.view.MenuProvider import androidx.core.view.isVisible import androidx.fragment.app.viewModels diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt index 9933104c69e..517e893f014 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt @@ -381,7 +381,6 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { assertThat(viewState.areAllRequiredFieldsValid).isTrue() } - @Test fun `when validation fails for a set of fields, ScrollToFirstErrorField event is triggered with correct field`() = testBlocking { From 8de8971c54ada30193eec5a2035f0ee0dd018130 Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Thu, 1 Feb 2024 16:20:19 -0500 Subject: [PATCH 12/19] Fixed the test names. --- .../creation/EditShippingLabelAddressViewModelTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt index 517e893f014..8aa75c31265 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt @@ -382,7 +382,7 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { } @Test - fun `when validation fails for a set of fields, ScrollToFirstErrorField event is triggered with correct field`() = testBlocking { + fun `given validation fails for a set of fields, when on done clicked, then ScrollToFirstErrorField event is triggered with correct field`() = testBlocking { viewModel.onFieldEdited(Field.Name, "") viewModel.onFieldEdited(Field.Company, "") @@ -401,7 +401,7 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { } @Test - fun `when all fields are valid, ScrollToFirstErrorField event is not triggered`() = testBlocking { + fun `given all fields are valid, when on done clicked, then ScrollToFirstErrorField event is not triggered`() = testBlocking { var event: Event? = null viewModel.event.observeForever { event = it } From 04759157eda0f0d28ea2a40a86fc92f5f7ff4feb Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Thu, 1 Feb 2024 17:08:47 -0500 Subject: [PATCH 13/19] Fixed keyboard and focus issues. --- .../shippinglabels/creation/CreateShippingLabelEvent.kt | 1 + .../creation/EditShippingLabelAddressFragment.kt | 6 ++++-- .../creation/EditShippingLabelAddressViewModel.kt | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt index b484c215e80..95548aed33e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelEvent.kt @@ -68,6 +68,7 @@ sealed class CreateShippingLabelEvent : MultiLiveEvent.Event() { data class ShowPrintShippingLabels(val orderId: Long, val labels: List) : CreateShippingLabelEvent() object ShowWooDiscountBottomSheet : CreateShippingLabelEvent() + object CloseKeyboard : CreateShippingLabelEvent() data class ScrollToFirstErrorField( val field: EditShippingLabelAddressViewModel.Field, val isStateFieldSpinner: Boolean? diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt index 6513755d72a..49107836727 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt @@ -144,7 +144,6 @@ class EditShippingLabelAddressFragment : override fun onMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.menu_done -> { - ActivityUtils.hideKeyboard(activity) viewModel.onDoneButtonClicked() true } @@ -247,7 +246,7 @@ class EditShippingLabelAddressFragment : if (!isViewVisibleInScrollView(binding.scrollView, errorView)) { binding.scrollView.postDelayed({ binding.scrollView.smoothScrollTo(0, errorView.top) - errorView.requestFocus() + errorView.editText?.requestFocusFromTouch() }, ERROR_SCROLL_DELAY) } } @@ -305,6 +304,9 @@ class EditShippingLabelAddressFragment : event.field, event.isStateFieldSpinner ) + CreateShippingLabelEvent.CloseKeyboard -> { + activity?.let { ActivityUtils.hideKeyboard(it) } + } else -> event.isHandled = false } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt index ffd26e45383..78eb150bbaf 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt @@ -102,6 +102,7 @@ class EditShippingLabelAddressViewModel @Inject constructor( viewState = viewState.validateAllFields() val address = viewState.getAddress() if (viewState.areAllRequiredFieldsValid) { + triggerEvent(CreateShippingLabelEvent.CloseKeyboard) launch { viewState = viewState.copy( isValidationProgressDialogVisible = true, @@ -224,9 +225,11 @@ class EditShippingLabelAddressViewModel @Inject constructor( // Validate fields locally viewState = viewState.validateAllFields() if (viewState.areAllRequiredFieldsValid) { + triggerEvent(CreateShippingLabelEvent.CloseKeyboard) exitWithAddress(viewState.getAddress()) } else { triggerEvent(ShowSnackbar(R.string.shipping_label_address_data_invalid_snackbar_message)) + triggerScrollToFirstErrorFieldEvent() } } From e29f375b8e8f9ae33a3205658cc56e6d1d5a32bb Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Thu, 1 Feb 2024 17:12:20 -0500 Subject: [PATCH 14/19] Added unit tests for the new keyboard behavior. --- .../EditShippingLabelAddressViewModelTest.kt | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt index 8aa75c31265..77b6dd65298 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt @@ -412,4 +412,51 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { assertThat(event).isNotInstanceOf(CreateShippingLabelEvent.ScrollToFirstErrorField::class.java) } + + @Test + fun `given all fields are valid, when onDoneButtonClicked, then CloseKeyboard event is triggered`() = testBlocking { + + var event: Event? = null + viewModel.event.observeForever { event = it } + + viewModel.onDoneButtonClicked() + + assertThat(event).isEqualTo(CreateShippingLabelEvent.CloseKeyboard) + } + + @Test + fun `given all fields are valid, when onUseAddressAsIsButtonClicked, then CloseKeyboard event is triggered`() = testBlocking { + val events = mutableListOf() + viewModel.event.observeForever { events.add(it) } + + viewModel.onUseAddressAsIsButtonClicked() + + assertThat(events).contains(CreateShippingLabelEvent.CloseKeyboard) + } + + @Test + fun `given fields are invalid, when onDoneButtonClicked, then CloseKeyboard event is not triggered`() = testBlocking { + viewModel.onFieldEdited(Field.Name, "") + viewModel.onFieldEdited(Field.Company, "") + + var event: Event? = null + viewModel.event.observeForever { event = it } + + viewModel.onDoneButtonClicked() + + assertThat(event).isNotEqualTo(CreateShippingLabelEvent.CloseKeyboard) + } + + @Test + fun `given fields are invalid, when onUseAddressAsIsButtonClicked, then CloseKeyboard event is not triggered`() = testBlocking { + viewModel.onFieldEdited(Field.Name, "") + viewModel.onFieldEdited(Field.Company, "") + + var event: Event? = null + viewModel.event.observeForever { event = it } + + viewModel.onUseAddressAsIsButtonClicked() + + assertThat(event).isNotEqualTo(CreateShippingLabelEvent.CloseKeyboard) + } } From 67d98c1ca693de7b9aca96b0a6e79681133b32ca Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Thu, 1 Feb 2024 17:19:23 -0500 Subject: [PATCH 15/19] Added release notes. --- RELEASE-NOTES.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index a2e77d4a0ee..e04b2b4ea8f 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,4 +1,9 @@ *** PLEASE FOLLOW THIS FORMAT: [] [] + +17.3 +----- +- [*] [Internal] Enhanced user experience in shipping label creation with automatic scrolling to the first invalid field upon form submission failure [https://github.com/woocommerce/woocommerce-android/pull/10657] + 17.1 ----- - [*] [Internal] Fixed crash when going to background from the order creation screen [https://github.com/woocommerce/woocommerce-android/pull/10600] From 934c08036c40137f091f61756e6cfa2684fc89bd Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Thu, 1 Feb 2024 20:29:07 -0500 Subject: [PATCH 16/19] Fixed import of classes. --- .../EditShippingLabelAddressFragment.kt | 6 ++++-- .../EditShippingLabelAddressViewModel.kt | 5 +++-- .../EditShippingLabelAddressViewModelTest.kt | 18 ++++++++++-------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt index 49107836727..5ab785803ce 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt @@ -34,6 +34,8 @@ import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingL import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowCountrySelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowStateSelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowSuggestedAddress +import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ScrollToFirstErrorField +import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.CloseKeyboard import com.woocommerce.android.ui.orders.shippinglabels.creation.EditShippingLabelAddressViewModel.Field import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressSuggestionFragment.Companion.SELECTED_ADDRESS_ACCEPTED import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressSuggestionFragment.Companion.SELECTED_ADDRESS_TO_BE_EDITED @@ -300,11 +302,11 @@ class EditShippingLabelAddressFragment : is OpenMapWithAddress -> launchMapsWithAddress(event.address) is DialPhoneNumber -> dialPhoneNumber(requireContext(), event.phoneNumber) - is CreateShippingLabelEvent.ScrollToFirstErrorField -> scrollToFirstErrorField( + is ScrollToFirstErrorField -> scrollToFirstErrorField( event.field, event.isStateFieldSpinner ) - CreateShippingLabelEvent.CloseKeyboard -> { + CloseKeyboard -> { activity?.let { ActivityUtils.hideKeyboard(it) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt index 78eb150bbaf..acd40a3bb6f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt @@ -22,6 +22,7 @@ import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingL import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowCountrySelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowStateSelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowSuggestedAddress +import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.CloseKeyboard import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressValidator.AddressType import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressValidator.AddressType.DESTINATION import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressValidator.AddressType.ORIGIN @@ -102,7 +103,7 @@ class EditShippingLabelAddressViewModel @Inject constructor( viewState = viewState.validateAllFields() val address = viewState.getAddress() if (viewState.areAllRequiredFieldsValid) { - triggerEvent(CreateShippingLabelEvent.CloseKeyboard) + triggerEvent(CloseKeyboard) launch { viewState = viewState.copy( isValidationProgressDialogVisible = true, @@ -225,7 +226,7 @@ class EditShippingLabelAddressViewModel @Inject constructor( // Validate fields locally viewState = viewState.validateAllFields() if (viewState.areAllRequiredFieldsValid) { - triggerEvent(CreateShippingLabelEvent.CloseKeyboard) + triggerEvent(CloseKeyboard) exitWithAddress(viewState.getAddress()) } else { triggerEvent(ShowSnackbar(R.string.shipping_label_address_data_invalid_snackbar_message)) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt index 77b6dd65298..0f05ad0ac8a 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt @@ -7,6 +7,8 @@ import com.woocommerce.android.model.toAppModel import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.DialPhoneNumber import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.OpenMapWithAddress +import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ScrollToFirstErrorField +import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.CloseKeyboard import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowCountrySelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowStateSelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowSuggestedAddress @@ -394,9 +396,9 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { verify(addressValidator, never()).validateAddress(any(), any(), any()) - assertThat(event).isInstanceOf(CreateShippingLabelEvent.ScrollToFirstErrorField::class.java) - if (event is CreateShippingLabelEvent.ScrollToFirstErrorField) { - assertThat((event as CreateShippingLabelEvent.ScrollToFirstErrorField).field).isEqualTo(Field.Name) + assertThat(event).isInstanceOf(ScrollToFirstErrorField::class.java) + if (event is ScrollToFirstErrorField) { + assertThat((event as ScrollToFirstErrorField).field).isEqualTo(Field.Name) } } @@ -410,7 +412,7 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { verify(addressValidator, atLeastOnce()).validateAddress(any(), any(), any()) - assertThat(event).isNotInstanceOf(CreateShippingLabelEvent.ScrollToFirstErrorField::class.java) + assertThat(event).isNotInstanceOf(ScrollToFirstErrorField::class.java) } @Test @@ -421,7 +423,7 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { viewModel.onDoneButtonClicked() - assertThat(event).isEqualTo(CreateShippingLabelEvent.CloseKeyboard) + assertThat(event).isEqualTo(CloseKeyboard) } @Test @@ -431,7 +433,7 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { viewModel.onUseAddressAsIsButtonClicked() - assertThat(events).contains(CreateShippingLabelEvent.CloseKeyboard) + assertThat(events).contains(CloseKeyboard) } @Test @@ -444,7 +446,7 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { viewModel.onDoneButtonClicked() - assertThat(event).isNotEqualTo(CreateShippingLabelEvent.CloseKeyboard) + assertThat(event).isNotEqualTo(CloseKeyboard) } @Test @@ -457,6 +459,6 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { viewModel.onUseAddressAsIsButtonClicked() - assertThat(event).isNotEqualTo(CreateShippingLabelEvent.CloseKeyboard) + assertThat(event).isNotEqualTo(CloseKeyboard) } } From 0e93ec5444408834602af4cb43d40504bf7d9226 Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Thu, 1 Feb 2024 21:23:07 -0500 Subject: [PATCH 17/19] Fixed some detekt issues. --- .../creation/EditShippingLabelAddressViewModel.kt | 2 +- .../creation/EditShippingLabelAddressViewModelTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt index acd40a3bb6f..3ebb36a7abe 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt @@ -17,12 +17,12 @@ import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.common.InputField import com.woocommerce.android.ui.common.OptionalField import com.woocommerce.android.ui.common.RequiredField +import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.CloseKeyboard import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.DialPhoneNumber import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.OpenMapWithAddress import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowCountrySelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowStateSelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowSuggestedAddress -import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.CloseKeyboard import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressValidator.AddressType import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressValidator.AddressType.DESTINATION import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressValidator.AddressType.ORIGIN diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt index 0f05ad0ac8a..56ee130e6a9 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt @@ -5,10 +5,10 @@ import com.woocommerce.android.R.string import com.woocommerce.android.model.UiString.UiStringRes import com.woocommerce.android.model.toAppModel import com.woocommerce.android.tools.SelectedSite +import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.CloseKeyboard import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.DialPhoneNumber import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.OpenMapWithAddress import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ScrollToFirstErrorField -import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.CloseKeyboard import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowCountrySelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowStateSelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowSuggestedAddress From 967ce9d3ff6ad6859524ef88e0282722d9df07af Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Thu, 1 Feb 2024 21:34:39 -0500 Subject: [PATCH 18/19] Fixed various detekt issues. --- .../EditShippingLabelAddressFragment.kt | 4 +- .../EditShippingLabelAddressViewModel.kt | 30 +++++-- .../EditShippingLabelAddressViewModelTest.kt | 88 ++++++++++--------- 3 files changed, 68 insertions(+), 54 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt index 5ab785803ce..895cb5b4e4d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt @@ -29,13 +29,13 @@ import com.woocommerce.android.ui.base.BaseFragment import com.woocommerce.android.ui.base.UIMessageResolver import com.woocommerce.android.ui.common.InputField import com.woocommerce.android.ui.main.MainActivity.Companion.BackPressListener +import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.CloseKeyboard import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.DialPhoneNumber import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.OpenMapWithAddress +import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ScrollToFirstErrorField import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowCountrySelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowStateSelector import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ShowSuggestedAddress -import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.ScrollToFirstErrorField -import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.CloseKeyboard import com.woocommerce.android.ui.orders.shippinglabels.creation.EditShippingLabelAddressViewModel.Field import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressSuggestionFragment.Companion.SELECTED_ADDRESS_ACCEPTED import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressSuggestionFragment.Companion.SELECTED_ADDRESS_TO_BE_EDITED diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt index 3ebb36a7abe..fbc37ebc822 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModel.kt @@ -76,7 +76,9 @@ class EditShippingLabelAddressViewModel @Inject constructor( val fullCountriesList = dataStore.getCountries() val supportedCountries = if (arguments.addressType == ORIGIN) { fullCountriesList.filter { ACCEPTED_USPS_ORIGIN_COUNTRIES.contains(it.code) } - } else fullCountriesList + } else { + fullCountriesList + } return supportedCountries.map { it.toAppModel() } } @@ -169,8 +171,11 @@ class EditShippingLabelAddressViewModel @Inject constructor( viewState = viewState.copy( address1Field = viewState.address1Field.copy(validationError = validationErrorMessage).validate(), bannerMessage = resourceProvider.getString( - if (arguments.addressType == ORIGIN) R.string.shipping_label_edit_origin_address_error_warning - else R.string.shipping_label_edit_address_error_warning + if (arguments.addressType == ORIGIN) { + R.string.shipping_label_edit_origin_address_error_warning + } else { + R.string.shipping_label_edit_address_error_warning + } ) ) } @@ -456,8 +461,11 @@ class EditShippingLabelAddressViewModel @Inject constructor( val companyContent: String ) : InputField(content) { override fun validateInternal(): UiString? { - return if (content.isNotBlank() || companyContent.isNotBlank()) null - else UiStringRes(R.string.error_required_field) + return if (content.isNotBlank() || companyContent.isNotBlank()) { + null + } else { + UiStringRes(R.string.error_required_field) + } } } @@ -482,8 +490,9 @@ class EditShippingLabelAddressViewModel @Inject constructor( val addressType: AddressType ) : InputField(content) { override fun validateInternal(): UiString? { - return if (content.isValidPhoneNumber(addressType, isCustomsFormRequired)) null - else { + return if (content.isValidPhoneNumber(addressType, isCustomsFormRequired)) { + null + } else { when { content.isBlank() -> UiStringRes(R.string.shipping_label_address_phone_required) addressType == ORIGIN -> @@ -504,8 +513,11 @@ class EditShippingLabelAddressViewModel @Inject constructor( val isRequired: Boolean = false ) : InputField(location.name) { override fun validateInternal(): UiString? { - return if (isRequired && content.isBlank()) UiStringRes(R.string.error_required_field) - else null + return if (isRequired && content.isBlank()) { + UiStringRes(R.string.error_required_field) + } else { + null + } } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt index 56ee130e6a9..e73894bfac0 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressViewModelTest.kt @@ -384,40 +384,39 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { } @Test - fun `given validation fails for a set of fields, when on done clicked, then ScrollToFirstErrorField event is triggered with correct field`() = testBlocking { - - viewModel.onFieldEdited(Field.Name, "") - viewModel.onFieldEdited(Field.Company, "") + fun `given validation fails for a set of fields, when on done clicked, then ScrollToFirstErrorField event is triggered with correct field`() = + testBlocking { + viewModel.onFieldEdited(Field.Name, "") + viewModel.onFieldEdited(Field.Company, "") - var event: Event? = null - viewModel.event.observeForever { event = it } + var event: Event? = null + viewModel.event.observeForever { event = it } - viewModel.onDoneButtonClicked() + viewModel.onDoneButtonClicked() - verify(addressValidator, never()).validateAddress(any(), any(), any()) + verify(addressValidator, never()).validateAddress(any(), any(), any()) - assertThat(event).isInstanceOf(ScrollToFirstErrorField::class.java) - if (event is ScrollToFirstErrorField) { - assertThat((event as ScrollToFirstErrorField).field).isEqualTo(Field.Name) + assertThat(event).isInstanceOf(ScrollToFirstErrorField::class.java) + if (event is ScrollToFirstErrorField) { + assertThat((event as ScrollToFirstErrorField).field).isEqualTo(Field.Name) + } } - } @Test - fun `given all fields are valid, when on done clicked, then ScrollToFirstErrorField event is not triggered`() = testBlocking { - - var event: Event? = null - viewModel.event.observeForever { event = it } + fun `given all fields are valid, when on done clicked, then ScrollToFirstErrorField event is not triggered`() = + testBlocking { + var event: Event? = null + viewModel.event.observeForever { event = it } - viewModel.onDoneButtonClicked() + viewModel.onDoneButtonClicked() - verify(addressValidator, atLeastOnce()).validateAddress(any(), any(), any()) + verify(addressValidator, atLeastOnce()).validateAddress(any(), any(), any()) - assertThat(event).isNotInstanceOf(ScrollToFirstErrorField::class.java) - } + assertThat(event).isNotInstanceOf(ScrollToFirstErrorField::class.java) + } @Test fun `given all fields are valid, when onDoneButtonClicked, then CloseKeyboard event is triggered`() = testBlocking { - var event: Event? = null viewModel.event.observeForever { event = it } @@ -427,38 +426,41 @@ class EditShippingLabelAddressViewModelTest : BaseUnitTest() { } @Test - fun `given all fields are valid, when onUseAddressAsIsButtonClicked, then CloseKeyboard event is triggered`() = testBlocking { - val events = mutableListOf() - viewModel.event.observeForever { events.add(it) } + fun `given all fields are valid, when onUseAddressAsIsButtonClicked, then CloseKeyboard event is triggered`() = + testBlocking { + val events = mutableListOf() + viewModel.event.observeForever { events.add(it) } - viewModel.onUseAddressAsIsButtonClicked() + viewModel.onUseAddressAsIsButtonClicked() - assertThat(events).contains(CloseKeyboard) - } + assertThat(events).contains(CloseKeyboard) + } @Test - fun `given fields are invalid, when onDoneButtonClicked, then CloseKeyboard event is not triggered`() = testBlocking { - viewModel.onFieldEdited(Field.Name, "") - viewModel.onFieldEdited(Field.Company, "") + fun `given fields are invalid, when onDoneButtonClicked, then CloseKeyboard event is not triggered`() = + testBlocking { + viewModel.onFieldEdited(Field.Name, "") + viewModel.onFieldEdited(Field.Company, "") - var event: Event? = null - viewModel.event.observeForever { event = it } + var event: Event? = null + viewModel.event.observeForever { event = it } - viewModel.onDoneButtonClicked() + viewModel.onDoneButtonClicked() - assertThat(event).isNotEqualTo(CloseKeyboard) - } + assertThat(event).isNotEqualTo(CloseKeyboard) + } @Test - fun `given fields are invalid, when onUseAddressAsIsButtonClicked, then CloseKeyboard event is not triggered`() = testBlocking { - viewModel.onFieldEdited(Field.Name, "") - viewModel.onFieldEdited(Field.Company, "") + fun `given fields are invalid, when onUseAddressAsIsButtonClicked, then CloseKeyboard event is not triggered`() = + testBlocking { + viewModel.onFieldEdited(Field.Name, "") + viewModel.onFieldEdited(Field.Company, "") - var event: Event? = null - viewModel.event.observeForever { event = it } + var event: Event? = null + viewModel.event.observeForever { event = it } - viewModel.onUseAddressAsIsButtonClicked() + viewModel.onUseAddressAsIsButtonClicked() - assertThat(event).isNotEqualTo(CloseKeyboard) - } + assertThat(event).isNotEqualTo(CloseKeyboard) + } } From a9b26433028f138f74c2a0f0682c8210d4a0d2c7 Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Fri, 2 Feb 2024 10:24:00 -0500 Subject: [PATCH 19/19] Utilized the normal request focus. --- .../shippinglabels/creation/EditShippingLabelAddressFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt index 895cb5b4e4d..730c6d819c0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/EditShippingLabelAddressFragment.kt @@ -248,7 +248,7 @@ class EditShippingLabelAddressFragment : if (!isViewVisibleInScrollView(binding.scrollView, errorView)) { binding.scrollView.postDelayed({ binding.scrollView.smoothScrollTo(0, errorView.top) - errorView.editText?.requestFocusFromTouch() + errorView.editText?.requestFocus() }, ERROR_SCROLL_DELAY) } }