From 705fed902e6c0dc975aa795029f9459fbee5a5c0 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 1 Mar 2023 12:57:53 +0100 Subject: [PATCH 001/169] Add: change button text in treatment if selected domain is free v. paid --- .../domains/SiteCreationDomainsFragment.kt | 5 +++-- .../domains/SiteCreationDomainsViewModel.kt | 20 ++++++++++++++----- WordPress/src/main/res/values/strings.xml | 2 ++ .../SiteCreationDomainsViewModelTest.kt | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt index 22b0449ce705..63f0fac932e1 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt @@ -4,6 +4,7 @@ import android.content.Context import android.os.Bundle import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -88,8 +89,8 @@ class SiteCreationDomainsFragment : SiteCreationBaseFormFragment() { searchInputWithHeader?.updateHeader(requireActivity(), uiState.headerUiState) searchInputWithHeader?.updateSearchInput(requireActivity(), uiState.searchInputUiState) updateContentUiState(uiState.contentState) - uiHelpers.updateVisibility(createSiteButtonContainer, uiState.createSiteButtonContainerVisibility) - uiHelpers.updateVisibility(createSiteButtonShadow, uiState.createSiteButtonContainerVisibility) + createSiteButtonContainer.isVisible = uiState.createSiteButtonState != null + createSiteButton.text = uiState.createSiteButtonState?.stringRes?.let(::getString) updateTitleVisibility(uiState.headerUiState == null) } }) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt index 55ec92234731..901fc33cbb26 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt @@ -29,6 +29,7 @@ import org.wordpress.android.models.networkresource.ListState.Success import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainSuggestionsQuery.UserQuery +import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainsUiState.CreateSiteButtonState import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainsUiState.DomainsUiContentState import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.ListItemUiState.New import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.ListItemUiState.New.DomainUiState.Cost @@ -246,12 +247,15 @@ class SiteCreationDomainsViewModel @Inject constructor( showDivider = state.data.isNotEmpty() ), contentState = createDomainsUiContentState(query, state, emptyListMessage), - createSiteButtonContainerVisibility = getCreateSiteButtonState() + createSiteButtonState = getCreateSiteButtonState() ) } - private fun getCreateSiteButtonState(): Boolean { - return selectedDomain?.isFree ?: false + private fun getCreateSiteButtonState() = selectedDomain?.run { + when (purchasingFeatureConfig.isEnabledOrManuallyOverridden()) { + true -> if (isFree) CreateSiteButtonState.Free else CreateSiteButtonState.Paid + else -> CreateSiteButtonState.Old + } } private fun createDomainsUiContentState( @@ -382,7 +386,7 @@ class SiteCreationDomainsViewModel @Inject constructor( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) fun onDomainSelected(domain: DomainModel) { - selectedDomain = domain.takeIf { it.isFree } + selectedDomain = domain } private fun isNonEmptyUserQuery(query: DomainSuggestionsQuery?) = query is UserQuery && query.value.isNotBlank() @@ -398,7 +402,7 @@ class SiteCreationDomainsViewModel @Inject constructor( val headerUiState: SiteCreationHeaderUiState?, val searchInputUiState: SiteCreationSearchInputUiState, val contentState: DomainsUiContentState = DomainsUiContentState.Initial, - val createSiteButtonContainerVisibility: Boolean + val createSiteButtonState: CreateSiteButtonState? ) { sealed class DomainsUiContentState( val emptyViewVisibility: Boolean, @@ -423,6 +427,12 @@ class SiteCreationDomainsViewModel @Inject constructor( items = items ) } + + sealed class CreateSiteButtonState(@StringRes val stringRes: Int) { + object Old : CreateSiteButtonState(R.string.site_creation_domain_finish_button) + object Free : CreateSiteButtonState(R.string.site_creation_domain_button_continue_with_subdomain) + object Paid : CreateSiteButtonState(R.string.site_creation_domain_button_purchase_domain) + } } sealed class ListItemUiState(open val type: Type) { diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 89cbc05c74f5..cc888fa46c84 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -3332,6 +3332,8 @@ Recommended Sale This domain is already registered + Purchase domain + Continue with subdomain No available addresses matching your search Your search includes characters not supported in WordPress.com domains. The following characters are allowed: A–Z, a–z, 0–9. This domain is unavailable diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt index cb0d89d48b0b..ad3a0838f24d 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt @@ -464,7 +464,7 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { assertThat(uiState.searchInputUiState.showProgress).isEqualTo(showProgress) assertThat(uiState.searchInputUiState.showClearButton).isEqualTo(showClearButton) assertThat(uiState.contentState).isInstanceOf(DomainsUiContentState.Initial::class.java) - assertThat(uiState.createSiteButtonContainerVisibility).isEqualTo(false) + assertThat(uiState.createSiteButtonState).isNull() } /** From ee17413a17cfb9367c6d171717d67e6ca50be17a Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 1 Mar 2023 14:23:31 +0100 Subject: [PATCH 002/169] Test: change button text in treatment if selected domain is free v. paid --- .../SiteCreationDomainsViewModelTest.kt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt index ad3a0838f24d..e422f649c3d9 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt @@ -33,6 +33,7 @@ import org.wordpress.android.fluxc.store.SiteStore.OnSuggestedDomains import org.wordpress.android.fluxc.store.SiteStore.SuggestDomainError import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainModel import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainsUiState +import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainsUiState.CreateSiteButtonState import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainsUiState.DomainsUiContentState import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.ListItemUiState.New import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.ListItemUiState.New.DomainUiState.Cost @@ -320,6 +321,15 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { ) } + @Test + fun `verify create site button text is not changed when purchasing feature is OFF`() = testWithSuccessResponse { + viewModel.start() + + viewModel.onDomainSelected(mock()) + + assertIs(viewModel.uiState.value?.createSiteButtonState) + } + // region New UI private fun testNewUi(block: suspend CoroutineScope.() -> Unit) = test { @@ -374,6 +384,25 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { verify(productsStore).fetchProducts(eq(TYPE_DOMAINS_PRODUCT)) } + @Test + fun `verify create site button text changes when selecting a free domain`() = testNewUi { + viewModel.start() + + viewModel.onDomainSelected(mockDomain(free = true)) + + assertIs(viewModel.uiState.value?.createSiteButtonState) + } + + @Test + fun `verify create site button text changes when selecting a non-free domain`() = testNewUi { + viewModel.start() + + viewModel.onDomainSelected(mockDomain(free = false)) + + assertIs(viewModel.uiState.value?.createSiteButtonState) + } + + @Test fun `verify all domain results from api are visible`() = testWithSuccessResultNewUi { (query, results) -> viewModel.start() From b7df6764606b82262c4e2bae6845eafe621cc869 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 1 Mar 2023 16:04:20 +0100 Subject: [PATCH 003/169] Update: emit DomainModel instead of string on 'create site button' click --- .../ui/sitecreation/SiteCreationActivity.kt | 3 ++- .../ui/sitecreation/SiteCreationMainVM.kt | 5 +++-- .../domains/DomainsScreenListener.kt | 9 ++++++++- .../domains/SiteCreationDomainsViewModel.kt | 13 +++--------- .../ui/sitecreation/SiteCreationMainVMTest.kt | 5 +++-- .../SiteCreationDomainsViewModelTest.kt | 20 ++++++++----------- 6 files changed, 27 insertions(+), 28 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 5cde5e92fb98..4dce7b8eb13f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -31,6 +31,7 @@ import org.wordpress.android.ui.sitecreation.SiteCreationStep.INTENTS import org.wordpress.android.ui.sitecreation.SiteCreationStep.SITE_DESIGNS import org.wordpress.android.ui.sitecreation.SiteCreationStep.SITE_NAME import org.wordpress.android.ui.sitecreation.SiteCreationStep.SITE_PREVIEW +import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.domains.DomainsScreenListener import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsFragment import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener @@ -205,7 +206,7 @@ class SiteCreationActivity : LocaleAwareActivity(), ActivityUtils.hideKeyboard(this) } - override fun onDomainSelected(domain: String) { + override fun onDomainSelected(domain: DomainModel) { mainViewModel.onDomainsScreenFinished(domain) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 26a0d4ea9fa5..2f1efa87b13b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -22,6 +22,7 @@ import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleEmpty import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount +import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState @@ -230,8 +231,8 @@ class SiteCreationMainVM @Inject constructor( } } - fun onDomainsScreenFinished(domain: String) { - siteCreationState = siteCreationState.copy(domain = domain) + fun onDomainsScreenFinished(domain: DomainModel) { + siteCreationState = siteCreationState.copy(domain = domain.domainName) wizardManager.showNextStep() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt index d79672868bde..b3844664f66b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt @@ -1,5 +1,12 @@ package org.wordpress.android.ui.sitecreation.domains interface DomainsScreenListener { - fun onDomainSelected(domain: String) + fun onDomainSelected(domain: DomainModel) } + +data class DomainModel( + val domainName: String, + val isFree: Boolean, + val cost: String, + val productId: Int, +) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt index 901fc33cbb26..233e0f50e228 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt @@ -90,8 +90,8 @@ class SiteCreationDomainsViewModel @Inject constructor( } } - private val _createSiteBtnClicked = SingleLiveEvent() - val createSiteBtnClicked: LiveData = _createSiteBtnClicked + private val _createSiteBtnClicked = SingleLiveEvent() + val createSiteBtnClicked: LiveData = _createSiteBtnClicked private val _clearBtnClicked = SingleLiveEvent() val clearBtnClicked = _clearBtnClicked @@ -136,7 +136,7 @@ class SiteCreationDomainsViewModel @Inject constructor( "Create site button should not be visible if a domain is not selected" } tracker.trackDomainSelected(domain.domainName, currentQuery?.value ?: "") - _createSiteBtnClicked.value = domain.domainName + _createSiteBtnClicked.value = domain } fun onClearTextBtnClicked() = _clearBtnClicked.call() @@ -391,13 +391,6 @@ class SiteCreationDomainsViewModel @Inject constructor( private fun isNonEmptyUserQuery(query: DomainSuggestionsQuery?) = query is UserQuery && query.value.isNotBlank() - data class DomainModel( - val domainName: String, - val isFree: Boolean, - val cost: String, - val productId: Int, - ) - data class DomainsUiState( val headerUiState: SiteCreationHeaderUiState?, val searchInputUiState: SiteCreationSearchInputUiState, diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 70bee937febc..2c9cb7bc451b 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -31,6 +31,7 @@ import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleEmpty import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount +import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState @@ -47,7 +48,7 @@ import org.wordpress.android.viewmodel.helpers.DialogHolder private const val LOCAL_SITE_ID = 1 private const val SEGMENT_ID = 1L private const val VERTICAL = "Test Vertical" -private const val DOMAIN = "test.domain.com" +private val DOMAIN = DomainModel("test.domain.com", true, "$0", 1) private const val STEP_COUNT = 20 private const val FIRST_STEP_INDEX = 1 private const val LAST_STEP_INDEX = STEP_COUNT @@ -135,7 +136,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun siteCreationStateUpdatedWithSelectedDomain() { viewModel.onDomainsScreenFinished(DOMAIN) - assertThat(currentWizardState(viewModel).domain).isEqualTo(DOMAIN) + assertThat(currentWizardState(viewModel).domain).isEqualTo(DOMAIN.domainName) } @Test diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt index e422f649c3d9..c80e8c770e20 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt @@ -11,9 +11,9 @@ import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any +import org.mockito.kotlin.argWhere import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq -import org.mockito.kotlin.firstValue import org.mockito.kotlin.lastValue import org.mockito.kotlin.mock import org.mockito.kotlin.secondValue @@ -31,7 +31,6 @@ import org.wordpress.android.fluxc.store.ProductsStore import org.wordpress.android.fluxc.store.ProductsStore.OnProductsFetched import org.wordpress.android.fluxc.store.SiteStore.OnSuggestedDomains import org.wordpress.android.fluxc.store.SiteStore.SuggestDomainError -import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainModel import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainsUiState import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainsUiState.CreateSiteButtonState import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsViewModel.DomainsUiState.DomainsUiContentState @@ -76,7 +75,7 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { private lateinit var uiStateObserver: Observer @Mock - private lateinit var createSiteBtnObserver: Observer + private lateinit var createSiteBtnObserver: Observer @Mock private lateinit var clearBtnObserver: Observer @@ -293,17 +292,14 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { verify(clearBtnObserver, times(1)).onChanged(captor.capture()) } - /** - * Verifies that create site button is properly propagated when a domain is selected. - */ @Test - fun verifyCreateSiteBtnClickedPropagated() = testWithSuccessResponse { - val domainName = "test.domain" - viewModel.onDomainSelected(mockDomain(domainName)) + fun `verify click on the create site button emits the selected domain`() = testWithSuccessResponse { + val selectedDomain = mockDomain("test.domain") + viewModel.onDomainSelected(selectedDomain) + viewModel.onCreateSiteBtnClicked() - val captor = ArgumentCaptor.forClass(String::class.java) - verify(createSiteBtnObserver, times(1)).onChanged(captor.capture()) - assertThat(captor.firstValue).isEqualTo(domainName) + + verify(createSiteBtnObserver).onChanged(argWhere { it == selectedDomain }) } @Test From 65970a58b90ef85582bb083a5181df08b3b904cf Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 12:05:11 +0100 Subject: [PATCH 004/169] Refactor: reorder fields in site creation preview fragment --- .../previews/SiteCreationPreviewFragment.kt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 24c002fdb551..413f8f4dd209 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -5,7 +5,7 @@ import android.animation.AnimatorListenerAdapter import android.animation.AnimatorSet import android.animation.ObjectAnimator import android.content.Context -import android.content.res.Configuration +import android.content.res.Configuration.ORIENTATION_LANDSCAPE import android.os.Bundle import android.text.Spannable import android.text.SpannableString @@ -53,16 +53,15 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), * We need to connect to the service, so the service knows when the app is in the background. The service * automatically shows system notifications when site creation is in progress and the app is in the background. */ - private var serviceEventConnection: ServiceEventConnection? = null - private val viewModel: SitePreviewViewModel by viewModels() - private var animatorSet: AnimatorSet? = null - private val isLandscape: Boolean - get() = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE - @Inject internal lateinit var uiHelpers: UiHelpers + private var serviceEventConnection: ServiceEventConnection? = null + private var animatorSet: AnimatorSet? = null + private val isLandscape get() = resources.configuration.orientation == ORIENTATION_LANDSCAPE + private var binding: SiteCreationPreviewScreenBinding? = null + private val viewModel: SitePreviewViewModel by viewModels() @Suppress("UseCheckOrError") override fun onAttach(context: Context) { From 632a364e7036f30ccf8979dfe73585996205fa0e Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 12:12:07 +0100 Subject: [PATCH 005/169] Refactor: solve suppressed `UseCheckOrError` detekt rule in `onAttach` --- .../sitecreation/previews/SiteCreationPreviewFragment.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 413f8f4dd209..cfa82dd13547 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -63,15 +63,10 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), private var binding: SiteCreationPreviewScreenBinding? = null private val viewModel: SitePreviewViewModel by viewModels() - @Suppress("UseCheckOrError") override fun onAttach(context: Context) { super.onAttach(context) - if (context !is SitePreviewScreenListener) { - throw IllegalStateException("Parent activity must implement SitePreviewScreenListener.") - } - if (context !is OnHelpClickedListener) { - throw IllegalStateException("Parent activity must implement OnHelpClickedListener.") - } + check(context is SitePreviewScreenListener) { "Parent activity must implement SitePreviewScreenListener." } + check(context is OnHelpClickedListener) { "Parent activity must implement OnHelpClickedListener." } } override fun onCreate(savedInstanceState: Bundle?) { From e89dc40751fcb7246ed82470426f967ba4ea629b Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 12:12:18 +0100 Subject: [PATCH 006/169] Refactor: suppress `OVERRIDE_DEPRECATION` for `onActivityCreated` --- .../ui/sitecreation/previews/SiteCreationPreviewFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index cfa82dd13547..07c5cd3b6427 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -78,7 +78,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } } - @Suppress("DEPRECATION") + @Suppress("DEPRECATION", "OVERRIDE_DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) From 8f0f52f48692538ae02931e4be9904220d9b7503 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 12:16:05 +0100 Subject: [PATCH 007/169] Refactor: extract duplicated initialisation logic --- .../sitecreation/previews/SiteCreationPreviewFragment.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 07c5cd3b6427..5e3488924d65 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -81,14 +81,15 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), @Suppress("DEPRECATION", "OVERRIDE_DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - - (requireActivity() as AppCompatActivity).supportActionBar?.hide() - - viewModel.start(requireArguments()[ARG_DATA] as SiteCreationState, savedInstanceState) + init(savedInstanceState) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + init(savedInstanceState) + } + + private fun init(savedInstanceState: Bundle?) { (requireActivity() as AppCompatActivity).supportActionBar?.hide() viewModel.start(requireArguments()[ARG_DATA] as SiteCreationState, savedInstanceState) From 691f496eabe61d114ccacb91d64cb95fd0efdce6 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 12:16:46 +0100 Subject: [PATCH 008/169] Refactor: convert `getContentLayout` to expression body 1 liner --- .../ui/sitecreation/previews/SiteCreationPreviewFragment.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 5e3488924d65..6b0156ac49a9 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -95,9 +95,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), viewModel.start(requireArguments()[ARG_DATA] as SiteCreationState, savedInstanceState) } - override fun getContentLayout(): Int { - return R.layout.site_creation_preview_screen - } + override fun getContentLayout() = R.layout.site_creation_preview_screen @Suppress("UseCheckOrError") override val screenTitle: String From 76cf41cedc216808cd2a24e6e5e3dd74075be881 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 12:18:54 +0100 Subject: [PATCH 009/169] Refactor: solve suppressed `UseCheckOrError` detekt rule for arg. getter --- .../ui/sitecreation/previews/SiteCreationPreviewFragment.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 6b0156ac49a9..7c4299fec46a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -97,10 +97,8 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), override fun getContentLayout() = R.layout.site_creation_preview_screen - @Suppress("UseCheckOrError") override val screenTitle: String - get() = arguments?.getString(EXTRA_SCREEN_TITLE) - ?: throw IllegalStateException("Required argument screen title is missing.") + get() = requireNotNull(arguments?.getString(EXTRA_SCREEN_TITLE)) { "Missing required argument 'screenTitle'." } override fun setBindingViewStubListener(parentBinding: SiteCreationFormScreenBinding) { parentBinding.siteCreationFormContentStub.setOnInflateListener { _, inflated -> From a54968fc983911c439edf6469f9c84d58f4caa46 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 12:20:46 +0100 Subject: [PATCH 010/169] Refactor: use run to remove namespacing dupes in `setupContent` --- .../previews/SiteCreationPreviewFragment.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 7c4299fec46a..d10197c5a31d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -107,11 +107,13 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } override fun setupContent() { - binding?.siteCreationPreviewScreenDefault?.initViewModel() - binding?.siteCreationPreviewScreenDefault?.fullscreenErrorWithRetry?.initRetryButton() - binding?.siteCreationPreviewScreenDefault?.initOkButton() - binding?.siteCreationPreviewScreenDefault?.fullscreenErrorWithRetry?.initCancelWizardButton() - binding?.siteCreationPreviewScreenDefault?.fullscreenErrorWithRetry?.initContactSupportButton() + binding?.siteCreationPreviewScreenDefault?.run { + initViewModel() + fullscreenErrorWithRetry.initRetryButton() + initOkButton() + fullscreenErrorWithRetry.initCancelWizardButton() + fullscreenErrorWithRetry.initContactSupportButton() + } } private fun SiteCreationPreviewScreenDefaultBinding.initViewModel() { From d56c3c2a27a135e1739d21d8fd1452e56ecea442 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 12:36:46 +0100 Subject: [PATCH 011/169] Refactor: move `fullscreenErrorWithRetry` setup calls together --- .../ui/sitecreation/previews/SiteCreationPreviewFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index d10197c5a31d..e94c7b96ff96 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -109,8 +109,8 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), override fun setupContent() { binding?.siteCreationPreviewScreenDefault?.run { initViewModel() - fullscreenErrorWithRetry.initRetryButton() initOkButton() + fullscreenErrorWithRetry.initRetryButton() fullscreenErrorWithRetry.initCancelWizardButton() fullscreenErrorWithRetry.initContactSupportButton() } From 4a57d4310bb0f7ea5eb5b385151929a48ef91411 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 12:39:13 +0100 Subject: [PATCH 012/169] Refactor: move all lambda arguments out of parentheses --- .../previews/SiteCreationPreviewFragment.kt | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index e94c7b96ff96..3ace401237ad 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -117,7 +117,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } private fun SiteCreationPreviewScreenDefaultBinding.initViewModel() { - viewModel.uiState.observe(this@SiteCreationPreviewFragment, { uiState -> + viewModel.uiState.observe(this@SiteCreationPreviewFragment) { uiState -> uiState?.let { when (uiState) { is SitePreviewContentUiState -> updateContentLayout(uiState.data) @@ -151,9 +151,9 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), uiState.fullscreenErrorLayoutVisibility ) } - }) + } - viewModel.preloadPreview.observe(this@SiteCreationPreviewFragment, { url -> + viewModel.preloadPreview.observe(this@SiteCreationPreviewFragment) { url -> url?.let { urlString -> siteCreationPreviewWebViewContainer.sitePreviewWebView.webViewClient = URLFilteredWebViewClient(urlString, this@SiteCreationPreviewFragment) @@ -161,9 +161,9 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), WordPress.getUserAgent() siteCreationPreviewWebViewContainer.sitePreviewWebView.loadUrl(urlString) } - }) + } - viewModel.startCreateSiteService.observe(this@SiteCreationPreviewFragment, { startServiceData -> + viewModel.startCreateSiteService.observe(this@SiteCreationPreviewFragment) { startServiceData -> startServiceData?.let { SiteCreationService.createSite( requireNotNull(activity), @@ -171,28 +171,28 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), startServiceData.serviceData ) } - }) + } initClickObservers() } private fun initClickObservers() { - viewModel.onHelpClicked.observe(this, { + viewModel.onHelpClicked.observe(this) { (requireActivity() as OnHelpClickedListener).onHelpClicked(HelpActivity.Origin.SITE_CREATION_CREATING) - }) - viewModel.onSiteCreationCompleted.observe(this, { + } + viewModel.onSiteCreationCompleted.observe(this) { (requireActivity() as SitePreviewScreenListener).onSiteCreationCompleted() - }) - viewModel.onOkButtonClicked.observe(this, { createSiteState -> + } + viewModel.onOkButtonClicked.observe(this) { createSiteState -> createSiteState?.let { (requireActivity() as SitePreviewScreenListener).onSitePreviewScreenDismissed(createSiteState) } - }) - viewModel.onCancelWizardClicked.observe(this, { createSiteState -> + } + viewModel.onCancelWizardClicked.observe(this) { createSiteState -> createSiteState?.let { (requireActivity() as SitePreviewScreenListener).onSitePreviewScreenDismissed(createSiteState) } - }) + } } private fun FullscreenErrorWithRetryBinding.initRetryButton() { From dabc2d5926ce0c01592791aa6f5f52c160e305c4 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 13:01:06 +0100 Subject: [PATCH 013/169] Refactor: separate and cleanup observers to make the split simpler The fragment will be split into 2: Progress and Preview: - `Progress` handles site creation service connection and loading UI - `Preview` handles site creation service result and preview or error UI --- .../previews/SiteCreationPreviewFragment.kt | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 3ace401237ad..7cf404f1a27e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -41,6 +41,7 @@ import org.wordpress.android.util.AppLog import org.wordpress.android.util.AutoForeground.ServiceEventConnection import org.wordpress.android.util.ErrorManagedWebViewClient.ErrorManagedWebViewClientListener import org.wordpress.android.util.URLFilteredWebViewClient +import org.wordpress.android.widgets.NestedWebView import javax.inject.Inject private const val ARG_DATA = "arg_site_creation_data" @@ -108,7 +109,11 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), override fun setupContent() { binding?.siteCreationPreviewScreenDefault?.run { - initViewModel() + observeState() + observePreview(siteCreationPreviewWebViewContainer.sitePreviewWebView) + observeSiteCreationService() + observeHelpClicks(requireActivity() as OnHelpClickedListener) + observePreviewClicks(requireActivity() as SitePreviewScreenListener) initOkButton() fullscreenErrorWithRetry.initRetryButton() fullscreenErrorWithRetry.initCancelWizardButton() @@ -116,7 +121,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } } - private fun SiteCreationPreviewScreenDefaultBinding.initViewModel() { + private fun SiteCreationPreviewScreenDefaultBinding.observeState() { viewModel.uiState.observe(this@SiteCreationPreviewFragment) { uiState -> uiState?.let { when (uiState) { @@ -152,18 +157,20 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), ) } } + } - viewModel.preloadPreview.observe(this@SiteCreationPreviewFragment) { url -> + private fun observePreview(webView: NestedWebView) { + viewModel.preloadPreview.observe(this) { url -> url?.let { urlString -> - siteCreationPreviewWebViewContainer.sitePreviewWebView.webViewClient = - URLFilteredWebViewClient(urlString, this@SiteCreationPreviewFragment) - siteCreationPreviewWebViewContainer.sitePreviewWebView.settings.userAgentString = - WordPress.getUserAgent() - siteCreationPreviewWebViewContainer.sitePreviewWebView.loadUrl(urlString) + webView.webViewClient = URLFilteredWebViewClient(urlString, this) + webView.settings.userAgentString = WordPress.getUserAgent() + webView.loadUrl(urlString) } } + } - viewModel.startCreateSiteService.observe(this@SiteCreationPreviewFragment) { startServiceData -> + private fun observeSiteCreationService() { + viewModel.startCreateSiteService.observe(this) { startServiceData -> startServiceData?.let { SiteCreationService.createSite( requireNotNull(activity), @@ -172,26 +179,23 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), ) } } - - initClickObservers() } - private fun initClickObservers() { + private fun observeHelpClicks(listener: OnHelpClickedListener) { viewModel.onHelpClicked.observe(this) { - (requireActivity() as OnHelpClickedListener).onHelpClicked(HelpActivity.Origin.SITE_CREATION_CREATING) + listener.onHelpClicked(HelpActivity.Origin.SITE_CREATION_CREATING) } + } + + private fun observePreviewClicks(listener: SitePreviewScreenListener) { viewModel.onSiteCreationCompleted.observe(this) { - (requireActivity() as SitePreviewScreenListener).onSiteCreationCompleted() + listener.onSiteCreationCompleted() } viewModel.onOkButtonClicked.observe(this) { createSiteState -> - createSiteState?.let { - (requireActivity() as SitePreviewScreenListener).onSitePreviewScreenDismissed(createSiteState) - } + createSiteState?.let { listener.onSitePreviewScreenDismissed(it) } } viewModel.onCancelWizardClicked.observe(this) { createSiteState -> - createSiteState?.let { - (requireActivity() as SitePreviewScreenListener).onSitePreviewScreenDismissed(createSiteState) - } + createSiteState?.let { listener.onSitePreviewScreenDismissed(it) } } } From b8a9c0d5db6ad19c390b4eec969b85ea0c3789b0 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 13:06:41 +0100 Subject: [PATCH 014/169] Refactor: group and unify listeners init to make the split simpler --- .../previews/SiteCreationPreviewFragment.kt | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 7cf404f1a27e..f472e0c31d2c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -114,10 +114,8 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), observeSiteCreationService() observeHelpClicks(requireActivity() as OnHelpClickedListener) observePreviewClicks(requireActivity() as SitePreviewScreenListener) - initOkButton() - fullscreenErrorWithRetry.initRetryButton() - fullscreenErrorWithRetry.initCancelWizardButton() - fullscreenErrorWithRetry.initContactSupportButton() + fullscreenErrorWithRetry.setOnClickListeners() + okButton.setOnClickListener { viewModel.onOkButtonClicked() } } } @@ -199,19 +197,9 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } } - private fun FullscreenErrorWithRetryBinding.initRetryButton() { + private fun FullscreenErrorWithRetryBinding.setOnClickListeners() { errorRetry.setOnClickListener { viewModel.retry() } - } - - private fun SiteCreationPreviewScreenDefaultBinding.initOkButton() { - okButton.setOnClickListener { viewModel.onOkButtonClicked() } - } - - private fun FullscreenErrorWithRetryBinding.initCancelWizardButton() { cancelWizardButton.setOnClickListener { viewModel.onCancelWizardClicked() } - } - - private fun FullscreenErrorWithRetryBinding.initContactSupportButton() { contactSupport.setOnClickListener { viewModel.onHelpClicked() } } From 305fb43b51c52cb648af8f22759b52e36ff04005 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 13:11:36 +0100 Subject: [PATCH 015/169] Refactor: group logic for error with retry UI --- .../previews/SiteCreationPreviewFragment.kt | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index f472e0c31d2c..3e7b72c243b8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -203,6 +203,15 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), contactSupport.setOnClickListener { viewModel.onHelpClicked() } } + private fun FullscreenErrorWithRetryBinding.updateErrorLayout(errorUiState: SitePreviewFullscreenErrorUiState) { + errorUiState.apply { + uiHelpers.setTextOrHide(errorTitle, titleResId) + uiHelpers.setTextOrHide(errorSubtitle, subtitleResId) + uiHelpers.updateVisibility(contactSupport, errorUiState.showContactSupport) + uiHelpers.updateVisibility(cancelWizardButton, errorUiState.showCancelWizardButton) + } + } + private fun SiteCreationPreviewScreenDefaultBinding.updateContentLayout(sitePreviewData: SitePreviewData) { sitePreviewData.apply { siteCreationPreviewWebViewContainer.sitePreviewWebUrlTitle.text = createSpannableUrl( @@ -267,17 +276,6 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } } - private fun FullscreenErrorWithRetryBinding.updateErrorLayout( - errorUiStateState: SitePreviewFullscreenErrorUiState - ) { - errorUiStateState.apply { - uiHelpers.setTextOrHide(errorTitle, titleResId) - uiHelpers.setTextOrHide(errorSubtitle, subtitleResId) - uiHelpers.updateVisibility(contactSupport, errorUiStateState.showContactSupport) - uiHelpers.updateVisibility(cancelWizardButton, errorUiStateState.showCancelWizardButton) - } - } - /** * Creates a spannable url with 2 different text colors for the subdomain and domain. * From df5266611a5b74b770c749cb5f6a868925408a92 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 13:17:27 +0100 Subject: [PATCH 016/169] Refactor: convert single line methods to expression body 1 liners --- .../previews/SiteCreationPreviewFragment.kt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 3e7b72c243b8..09dc7b18a2d2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -308,17 +308,11 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), return spannableTitle } - override fun onWebViewPageLoaded() { - viewModel.onUrlLoaded() - } + override fun onWebViewPageLoaded() = viewModel.onUrlLoaded() - override fun onWebViewReceivedError() { - viewModel.onWebViewError() - } + override fun onWebViewReceivedError() = viewModel.onWebViewError() - override fun onHelp() { - viewModel.onHelpClicked() - } + override fun onHelp() = viewModel.onHelpClicked() private fun SiteCreationPreviewScreenDefaultBinding.animateContentTransition() { contentLayout.addOnLayoutChangeListener( From a6309454f41eeb4a1d454cce13bc760408d7cb11 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 15:35:33 +0100 Subject: [PATCH 017/169] Refactor: convert `newInstance` to expression body using `apply` --- .../previews/SiteCreationPreviewFragment.kt | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 09dc7b18a2d2..19df858db99e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -157,7 +157,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } } - private fun observePreview(webView: NestedWebView) { + private fun observePreview(webView: NestedWebView) { viewModel.preloadPreview.observe(this) { url -> url?.let { urlString -> webView.webViewClient = URLFilteredWebViewClient(urlString, this) @@ -400,16 +400,12 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), companion object { const val TAG = "site_creation_preview_fragment_tag" - fun newInstance( - screenTitle: String, - siteCreationData: SiteCreationState - ): SiteCreationPreviewFragment { - val fragment = SiteCreationPreviewFragment() - val bundle = Bundle() - bundle.putString(EXTRA_SCREEN_TITLE, screenTitle) - bundle.putParcelable(ARG_DATA, siteCreationData) - fragment.arguments = bundle - return fragment - } + fun newInstance(screenTitle: String, siteCreationData: SiteCreationState) = SiteCreationPreviewFragment() + .apply { + arguments = Bundle().apply { + putString(EXTRA_SCREEN_TITLE, screenTitle) + putParcelable(ARG_DATA, siteCreationData) + } + } } } From 6ed3b0a087f8a51fd6e0a3f4d622d92f365d0593 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 18:05:38 +0100 Subject: [PATCH 018/169] Refactor: group create site completion observer with the start one --- .../previews/SiteCreationPreviewFragment.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 19df858db99e..f2c3d1cc5f33 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -111,7 +111,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), binding?.siteCreationPreviewScreenDefault?.run { observeState() observePreview(siteCreationPreviewWebViewContainer.sitePreviewWebView) - observeSiteCreationService() + observeSiteCreationService(requireActivity() as SitePreviewScreenListener) observeHelpClicks(requireActivity() as OnHelpClickedListener) observePreviewClicks(requireActivity() as SitePreviewScreenListener) fullscreenErrorWithRetry.setOnClickListeners() @@ -167,7 +167,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } } - private fun observeSiteCreationService() { + private fun observeSiteCreationService(listener: SitePreviewScreenListener) { viewModel.startCreateSiteService.observe(this) { startServiceData -> startServiceData?.let { SiteCreationService.createSite( @@ -177,6 +177,9 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), ) } } + viewModel.onSiteCreationCompleted.observe(this) { + listener.onSiteCreationCompleted() + } } private fun observeHelpClicks(listener: OnHelpClickedListener) { @@ -186,9 +189,6 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } private fun observePreviewClicks(listener: SitePreviewScreenListener) { - viewModel.onSiteCreationCompleted.observe(this) { - listener.onSiteCreationCompleted() - } viewModel.onOkButtonClicked.observe(this) { createSiteState -> createSiteState?.let { listener.onSitePreviewScreenDismissed(it) } } From 007863638106676fd8c54797eb3631b79e0aad66 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 18:51:40 +0100 Subject: [PATCH 019/169] Update: replace string with domain for site creation wizard state --- .../android/ui/sitecreation/SiteCreationMainVM.kt | 6 ++---- .../ui/sitecreation/domains/DomainsScreenListener.kt | 6 +++++- .../ui/sitecreation/previews/SitePreviewViewModel.kt | 2 +- .../android/ui/sitecreation/SiteCreationMainVMTest.kt | 2 +- .../ui/sitecreation/previews/SitePreviewViewModelTest.kt | 7 ++++--- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 2f1efa87b13b..06ea161cbbcd 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -1,6 +1,5 @@ package org.wordpress.android.ui.sitecreation -import android.annotation.SuppressLint import android.content.Context import android.os.Bundle import android.os.Parcelable @@ -49,13 +48,12 @@ const val KEY_SITE_CREATION_COMPLETED = "key_site_creation_completed" const val KEY_SITE_CREATION_STATE = "key_site_creation_state" @Parcelize -@SuppressLint("ParcelCreator") data class SiteCreationState( val siteIntent: String? = null, val siteName: String? = null, val segmentId: Long? = null, val siteDesign: String? = null, - val domain: String? = null + val domain: DomainModel? = null ) : WizardState, Parcelable typealias NavigationTarget = WizardNavigationTarget @@ -232,7 +230,7 @@ class SiteCreationMainVM @Inject constructor( } fun onDomainsScreenFinished(domain: DomainModel) { - siteCreationState = siteCreationState.copy(domain = domain.domainName) + siteCreationState = siteCreationState.copy(domain = domain) wizardManager.showNextStep() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt index b3844664f66b..be96ecd25dc3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt @@ -1,12 +1,16 @@ package org.wordpress.android.ui.sitecreation.domains +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + interface DomainsScreenListener { fun onDomainSelected(domain: DomainModel) } +@Parcelize data class DomainModel( val domainName: String, val isFree: Boolean, val cost: String, val productId: Int, -) +) : Parcelable diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index e78740aa5e8b..ec07647becef 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -134,7 +134,7 @@ class SitePreviewViewModel @Inject constructor( } isStarted = true this.siteCreationState = siteCreationState - urlWithoutScheme = siteCreationState.domain + urlWithoutScheme = siteCreationState.domain?.domainName siteTitle = siteCreationState.siteName val restoredState = savedState?.getParcelable(KEY_CREATE_SITE_STATE) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 2c9cb7bc451b..d29d574f57e6 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -136,7 +136,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun siteCreationStateUpdatedWithSelectedDomain() { viewModel.onDomainsScreenFinished(DOMAIN) - assertThat(currentWizardState(viewModel).domain).isEqualTo(DOMAIN.domainName) + assertThat(currentWizardState(viewModel).domain).isEqualTo(DOMAIN) } @Test diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index edbb991c60d2..818f8b1b33ef 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -25,6 +25,7 @@ import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged import org.wordpress.android.fluxc.store.SiteStore.SiteError import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType.GENERIC_ERROR import org.wordpress.android.ui.sitecreation.SiteCreationState +import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState.SiteCreationCompleted @@ -47,11 +48,11 @@ import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.util.UrlUtilsWrapper private const val SUB_DOMAIN = "test" -private const val DOMAIN = ".wordpress.com" -private const val URL = "$SUB_DOMAIN$DOMAIN" +private const val URL = "$SUB_DOMAIN.wordpress.com" +private val DOMAIN = DomainModel(URL, true, "", 1) private const val REMOTE_SITE_ID = 1L private const val LOCAL_SITE_ID = 2 -private val SITE_CREATION_STATE = SiteCreationState(segmentId = 1, siteDesign = defaultTemplateSlug, domain = URL) +private val SITE_CREATION_STATE = SiteCreationState(segmentId = 1, siteDesign = defaultTemplateSlug, domain = DOMAIN) @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) From e50dc5854fff0b487c25ff04f72e1c3997acddf2 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 2 Mar 2023 18:52:42 +0100 Subject: [PATCH 020/169] Refactor: cleanup warning for Unit in main vm unit test --- .../android/ui/sitecreation/SiteCreationMainVMTest.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index d29d574f57e6..5d9a410d3861 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -112,8 +112,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { fun setUp() { whenever(wizardManager.navigatorLiveData).thenReturn(wizardManagerNavigatorLiveData) whenever(wizardManager.showNextStep()).then { - wizardManagerNavigatorLiveData.value = siteCreationStep - Unit + run { wizardManagerNavigatorLiveData.value = siteCreationStep } } viewModel = getNewViewModel() viewModel.start(null, SiteCreationSource.UNSPECIFIED) From fafc88229e9d7e5d1fe78c4f1400357e18d5e972 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Fri, 3 Mar 2023 13:29:17 +0100 Subject: [PATCH 021/169] Refactor: move comment for `serviceEventConnection` near it --- .../ui/sitecreation/previews/SiteCreationPreviewFragment.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index f2c3d1cc5f33..c56ca72fec17 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -50,13 +50,13 @@ private const val SLIDE_IN_ANIMATION_DURATION = 450L @AndroidEntryPoint class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), ErrorManagedWebViewClientListener { + @Inject + internal lateinit var uiHelpers: UiHelpers + /** * We need to connect to the service, so the service knows when the app is in the background. The service * automatically shows system notifications when site creation is in progress and the app is in the background. */ - @Inject - internal lateinit var uiHelpers: UiHelpers - private var serviceEventConnection: ServiceEventConnection? = null private var animatorSet: AnimatorSet? = null private val isLandscape get() = resources.configuration.orientation == ORIENTATION_LANDSCAPE From 2a29a5cd7790c26962f8219bd5834929ab0581c0 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Fri, 3 Mar 2023 15:59:08 +0100 Subject: [PATCH 022/169] Refactor: rename `observePreviewClicks` to `observeDismissClicks` --- .../ui/sitecreation/previews/SiteCreationPreviewFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index c56ca72fec17..fa580c259cd0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -113,7 +113,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), observePreview(siteCreationPreviewWebViewContainer.sitePreviewWebView) observeSiteCreationService(requireActivity() as SitePreviewScreenListener) observeHelpClicks(requireActivity() as OnHelpClickedListener) - observePreviewClicks(requireActivity() as SitePreviewScreenListener) + observeDismissClicks(requireActivity() as SitePreviewScreenListener) fullscreenErrorWithRetry.setOnClickListeners() okButton.setOnClickListener { viewModel.onOkButtonClicked() } } @@ -188,7 +188,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } } - private fun observePreviewClicks(listener: SitePreviewScreenListener) { + private fun observeDismissClicks(listener: SitePreviewScreenListener) { viewModel.onOkButtonClicked.observe(this) { createSiteState -> createSiteState?.let { listener.onSitePreviewScreenDismissed(it) } } From a47b20f53e356facf924710c3741711102524fe6 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Fri, 3 Mar 2023 18:31:31 +0100 Subject: [PATCH 023/169] Refactor: rename preview screen listener method to aid splitting --- .../android/ui/sitecreation/SiteCreationActivity.kt | 8 ++------ .../sitecreation/previews/SiteCreationPreviewFragment.kt | 4 ++-- .../ui/sitecreation/previews/SitePreviewScreenListener.kt | 2 +- .../android/ui/sitecreation/SiteCreationMainVMTest.kt | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 4dce7b8eb13f..8f26f8d4c82d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -210,13 +210,9 @@ class SiteCreationActivity : LocaleAwareActivity(), mainViewModel.onDomainsScreenFinished(domain) } - override fun onSiteCreationCompleted() { - mainViewModel.onSiteCreationCompleted() - } + override fun onSiteCreationCompleted() = mainViewModel.onSiteCreationCompleted() - override fun onSitePreviewScreenDismissed(createSiteState: CreateSiteState) { - mainViewModel.onSitePreviewScreenFinished(createSiteState) - } + override fun onPreviewScreenDismissed(state: CreateSiteState) = mainViewModel.onProgressOrPreviewFinished(state) override fun onHelpClicked(origin: Origin) { ActivityLauncher.viewHelp(this, origin, null, null) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index fa580c259cd0..7006738733b7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -190,10 +190,10 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), private fun observeDismissClicks(listener: SitePreviewScreenListener) { viewModel.onOkButtonClicked.observe(this) { createSiteState -> - createSiteState?.let { listener.onSitePreviewScreenDismissed(it) } + createSiteState?.let { listener.onPreviewScreenDismissed(it) } } viewModel.onCancelWizardClicked.observe(this) { createSiteState -> - createSiteState?.let { listener.onSitePreviewScreenDismissed(it) } + createSiteState?.let { listener.onPreviewScreenDismissed(it) } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt index d8c4ea075b2c..34deeaf027f0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt @@ -3,6 +3,6 @@ package org.wordpress.android.ui.sitecreation.previews import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState interface SitePreviewScreenListener { - fun onSitePreviewScreenDismissed(createSiteState: CreateSiteState) + fun onPreviewScreenDismissed(state: CreateSiteState) fun onSiteCreationCompleted() } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 5d9a410d3861..2f72f5999ad2 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -141,7 +141,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun wizardFinishedInvokedOnSitePreviewCompleted() { val state = SiteCreationCompleted(LOCAL_SITE_ID, false) - viewModel.onSitePreviewScreenFinished(state) + viewModel.onProgressOrPreviewFinished(state) val captor = ArgumentCaptor.forClass(CreateSiteState::class.java) verify(wizardFinishedObserver).onChanged(captor.capture()) From 845332071fd5ac3f2dbe7d459022d75b532aaa41 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Fri, 3 Mar 2023 18:36:27 +0100 Subject: [PATCH 024/169] Refactor: convert binding to lateinit --- .../ui/sitecreation/previews/SiteCreationPreviewFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 7006738733b7..a49233d4a34e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -61,7 +61,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), private var animatorSet: AnimatorSet? = null private val isLandscape get() = resources.configuration.orientation == ORIENTATION_LANDSCAPE - private var binding: SiteCreationPreviewScreenBinding? = null + private lateinit var binding: SiteCreationPreviewScreenBinding private val viewModel: SitePreviewViewModel by viewModels() override fun onAttach(context: Context) { @@ -108,7 +108,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } override fun setupContent() { - binding?.siteCreationPreviewScreenDefault?.run { + binding.siteCreationPreviewScreenDefault.run { observeState() observePreview(siteCreationPreviewWebViewContainer.sitePreviewWebView) observeSiteCreationService(requireActivity() as SitePreviewScreenListener) From be54585d2304e0ac7fbb27ea834e61be55bccc79 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Fri, 3 Mar 2023 18:37:33 +0100 Subject: [PATCH 025/169] Refactor: cleanup observeState using `run` and `apply` --- .../previews/SiteCreationPreviewFragment.kt | 47 ++++++------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index a49233d4a34e..bbf41853f39e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -120,39 +120,22 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } private fun SiteCreationPreviewScreenDefaultBinding.observeState() { - viewModel.uiState.observe(this@SiteCreationPreviewFragment) { uiState -> - uiState?.let { - when (uiState) { - is SitePreviewContentUiState -> updateContentLayout(uiState.data) - is SitePreviewWebErrorUiState -> updateContentLayout(uiState.data) - is SitePreviewLoadingShimmerState -> updateContentLayout(uiState.data) - is SitePreviewFullscreenProgressUiState -> - siteCreationProgressCreatingSite.updateLoadingLayout(uiState) - is SitePreviewFullscreenErrorUiState -> - fullscreenErrorWithRetry.updateErrorLayout(uiState) + viewModel.uiState.observe(this@SiteCreationPreviewFragment) { + it?.run { + when (val ui = this@run) { + is SitePreviewContentUiState -> updateContentLayout(ui.data) + is SitePreviewWebErrorUiState -> updateContentLayout(ui.data) + is SitePreviewLoadingShimmerState -> updateContentLayout(ui.data) + is SitePreviewFullscreenProgressUiState -> siteCreationProgressCreatingSite.updateLoadingLayout(ui) + is SitePreviewFullscreenErrorUiState -> fullscreenErrorWithRetry.updateErrorLayout(ui) + } + uiHelpers.updateVisibility(contentLayout, contentLayoutVisibility) + uiHelpers.updateVisibility(fullscreenErrorWithRetry.errorLayout, fullscreenErrorLayoutVisibility) + siteCreationPreviewWebViewContainer.apply { + uiHelpers.updateVisibility(sitePreviewWebView, webViewVisibility) + uiHelpers.updateVisibility(sitePreviewWebError, webViewErrorVisibility) + uiHelpers.updateVisibility(sitePreviewWebViewShimmerLayout, shimmerVisibility) } - uiHelpers.updateVisibility( - siteCreationProgressCreatingSite.progressLayout, - uiState.fullscreenProgressLayoutVisibility - ) - - uiHelpers.updateVisibility(contentLayout, uiState.contentLayoutVisibility) - uiHelpers.updateVisibility( - siteCreationPreviewWebViewContainer.sitePreviewWebView, - uiState.webViewVisibility - ) - uiHelpers.updateVisibility( - siteCreationPreviewWebViewContainer.sitePreviewWebError, - uiState.webViewErrorVisibility - ) - uiHelpers.updateVisibility( - siteCreationPreviewWebViewContainer.sitePreviewWebViewShimmerLayout, - uiState.shimmerVisibility - ) - uiHelpers.updateVisibility( - fullscreenErrorWithRetry.errorLayout, - uiState.fullscreenErrorLayoutVisibility - ) } } } From a079c2f783068fc28bf7c576de427a7277951cc0 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Fri, 3 Mar 2023 18:39:38 +0100 Subject: [PATCH 026/169] Refactor: rename leftover `onSitePreviewScreenFinished` to `onProgressOrPreviewFinished` --- .../org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 06ea161cbbcd..d1a68996cb55 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -267,7 +267,7 @@ class SiteCreationMainVM @Inject constructor( _exitFlowObservable.call() } - fun onSitePreviewScreenFinished(createSiteState: CreateSiteState) { + fun onProgressOrPreviewFinished(createSiteState: CreateSiteState) { _wizardFinishedObservable.value = createSiteState } From 4e45d6ce9a1b214b3117d12296c4cbce9b586150 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 6 Mar 2023 17:10:04 +0100 Subject: [PATCH 027/169] Refactor: convert to one line the init of domains fragment --- .../wordpress/android/ui/sitecreation/SiteCreationActivity.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 8f26f8d4c82d..db7439099557 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -228,9 +228,7 @@ class SiteCreationActivity : LocaleAwareActivity(), mainViewModel.preloadingJob?.cancel("Preload did not complete before theme picker was shown.") HomePagePickerFragment.newInstance(target.wizardState.siteIntent) } - DOMAINS -> SiteCreationDomainsFragment.newInstance( - screenTitle - ) + DOMAINS -> SiteCreationDomainsFragment.newInstance(screenTitle) SITE_PREVIEW -> SiteCreationPreviewFragment.newInstance(screenTitle, target.wizardState) } slideInFragment(fragment, target.wizardStep.toString()) From 056d9347bb7a40c9ed6bda5b0c8cc1f42c5bb429 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 6 Mar 2023 17:13:28 +0100 Subject: [PATCH 028/169] Refactor: simplify comment for OK button animation --- .../ui/sitecreation/previews/SiteCreationPreviewFragment.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index bbf41853f39e..9f5dffdce408 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -320,8 +320,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), contentHeight ) - // OK button should slide in if the container exists and fade in otherwise - // difference between land & portrait + // OK button slides in if the container exists else it fades in the diff between land & portrait val okAnim = if (isLandscape) { createFadeInAnimator(okButton) } else { From 56ed780b74a5b89e5ba7882d4e9a5fbee66d2084 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 6 Mar 2023 17:15:37 +0100 Subject: [PATCH 029/169] Refactor: put params of `newInstance` on separate lines --- .../previews/SiteCreationPreviewFragment.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 9f5dffdce408..5fe292dd6c46 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -382,12 +382,14 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), companion object { const val TAG = "site_creation_preview_fragment_tag" - fun newInstance(screenTitle: String, siteCreationData: SiteCreationState) = SiteCreationPreviewFragment() - .apply { - arguments = Bundle().apply { - putString(EXTRA_SCREEN_TITLE, screenTitle) - putParcelable(ARG_DATA, siteCreationData) - } + fun newInstance( + screenTitle: String, + siteCreationData: SiteCreationState, + ) = SiteCreationPreviewFragment().apply { + arguments = Bundle().apply { + putString(EXTRA_SCREEN_TITLE, screenTitle) + putParcelable(ARG_DATA, siteCreationData) } + } } } From 12441e7575a6f0b5e728c42e798e0cb3acda56c2 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 6 Mar 2023 17:18:23 +0100 Subject: [PATCH 030/169] Refactor: convert `onCancelWizardClicked` to one liner expression --- .../android/ui/sitecreation/previews/SitePreviewViewModel.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index ec07647becef..0e2ebfd77a78 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -188,9 +188,7 @@ class SitePreviewViewModel @Inject constructor( _onHelpClicked.call() } - fun onCancelWizardClicked() { - _onCancelWizardClicked.value = createSiteState - } + fun onHelpClicked() = _onHelpClicked.call() fun onOkButtonClicked() { tracker.trackPreviewOkButtonTapped() From 0941a9823ccf0232c4763532b17fa6a5c8e17342 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 6 Mar 2023 17:19:35 +0100 Subject: [PATCH 031/169] Refactor: replace pair ctor with to infix call and `Math.min` with `coerceAtMost` --- .../ui/sitecreation/previews/SitePreviewViewModel.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 0e2ebfd77a78..b7021bdaf60a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -313,11 +313,8 @@ class SitePreviewViewModel @Inject constructor( val url = urlWithoutScheme ?: "" val subDomain = urlUtils.extractSubDomain(url) val fullUrl = urlUtils.addUrlSchemeIfNeeded(url, true) - val subDomainIndices: Pair = Pair(0, subDomain.length) - val domainIndices: Pair = Pair( - Math.min(subDomainIndices.second, url.length), - url.length - ) + val subDomainIndices = 0 to subDomain.length + val domainIndices = subDomainIndices.second.coerceAtMost(url.length) to url.length return SitePreviewData( fullUrl, url, From e503437b42ddf6f4bfbdd91445b4d852efcce4a5 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 07:47:53 +0100 Subject: [PATCH 032/169] Refactor: replace all noop when branches with else --- .../wordpress/android/ui/sitecreation/SiteCreationMainVM.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index d1a68996cb55..657b3b12ee26 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -219,13 +219,10 @@ class SiteCreationMainVM @Inject constructor( private fun clearOldSiteCreationState(wizardStep: SiteCreationStep) { when (wizardStep) { - SiteCreationStep.SITE_DESIGNS -> Unit // Do nothing SiteCreationStep.DOMAINS -> siteCreationState.domain?.let { siteCreationState = siteCreationState.copy(domain = null) } - SiteCreationStep.SITE_PREVIEW -> Unit // Do nothing - SiteCreationStep.INTENTS -> Unit // Do nothing - SiteCreationStep.SITE_NAME -> Unit // Do nothing + else -> Unit // Do nothing } } From d9a28d30380f23a2dfd6f013317e95e6ec161153 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 11:00:13 +0100 Subject: [PATCH 033/169] Refactor: extract `CreateSiteState` out of preview vm to help splitting --- .../ui/sitecreation/SiteCreationActivity.kt | 8 ++--- .../ui/sitecreation/SiteCreationMainVM.kt | 2 +- .../ui/sitecreation/misc/CreateSiteState.kt | 30 +++++++++++++++++++ .../previews/SitePreviewViewModel.kt | 8 ++--- 4 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitecreation/misc/CreateSiteState.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index db7439099557..79712549572e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -38,10 +38,10 @@ import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.previews.SiteCreationPreviewFragment import org.wordpress.android.ui.sitecreation.previews.SitePreviewScreenListener -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState.SiteCreationCompleted -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState.SiteNotCreated -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState.SiteNotInLocalDb +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocalDb import org.wordpress.android.ui.sitecreation.sitename.SiteCreationSiteNameFragment import org.wordpress.android.ui.sitecreation.sitename.SiteCreationSiteNameViewModel import org.wordpress.android.ui.sitecreation.sitename.SiteNameScreenListener diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 657b3b12ee26..c5f6ca9348be 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -24,7 +24,7 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState import org.wordpress.android.ui.sitecreation.usecases.FetchHomePageLayoutsUseCase import org.wordpress.android.ui.utils.UiString.UiStringRes import org.wordpress.android.util.AppLog diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/misc/CreateSiteState.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/misc/CreateSiteState.kt new file mode 100644 index 000000000000..42bfde743cb1 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/misc/CreateSiteState.kt @@ -0,0 +1,30 @@ +package org.wordpress.android.ui.sitecreation.misc + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +sealed class CreateSiteState : Parcelable { + /** + * CreateSite request haven't finished yet or failed. + */ + @Parcelize + object SiteNotCreated : CreateSiteState() + + /** + * FetchSite request haven't finished yet or failed. + * Since we fetch the site without user awareness in background, the user may potentially leave the screen + * before the request is finished. + */ + @Parcelize + data class SiteNotInLocalDb(val remoteSiteId: Long, val isSiteTitleTaskComplete: Boolean) : CreateSiteState() + + /** + * The site has been successfully created and stored into local db. + */ + @Parcelize + data class SiteCreationCompleted( + val localSiteId: Int, + val isSiteTitleTaskComplete: Boolean, + val url: String, + ) : CreateSiteState() +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index b7021bdaf60a..7238b618e1e3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -26,9 +26,9 @@ import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.UNKNOWN import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState.SiteCreationCompleted -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState.SiteNotCreated -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState.SiteNotInLocalDb +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocalDb import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewFullscreenErrorUiState.SitePreviewConnectionErrorUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewFullscreenErrorUiState.SitePreviewGenericErrorUiState @@ -393,8 +393,6 @@ class SitePreviewViewModel @Inject constructor( object SitePreviewGenericErrorUiState : SitePreviewFullscreenErrorUiState( R.string.site_creation_error_generic_title, - R.string.site_creation_error_generic_subtitle, - showContactSupport = true ) object SitePreviewConnectionErrorUiState : SitePreviewFullscreenErrorUiState( From b2110f0c2128afbd117bfb5248dcb1509fdaaf04 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 15:05:35 +0100 Subject: [PATCH 034/169] Add: `ProgressScreenListener` interface --- .../ui/sitecreation/progress/ProgressScreenListener.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt new file mode 100644 index 000000000000..f15de359f261 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt @@ -0,0 +1,8 @@ +package org.wordpress.android.ui.sitecreation.progress + +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState + +interface ProgressScreenListener { + fun onProgressScreenDismissed(state: CreateSiteState) + fun onSiteCreationCompleted(state: CreateSiteState) +} From 4f60278a1c08bd85d705634ba7ea2ce9962a9695 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 15:05:54 +0100 Subject: [PATCH 035/169] Add: Progress screen layout xml --- .../layout/site_creation_progress_screen.xml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 WordPress/src/main/res/layout/site_creation_progress_screen.xml diff --git a/WordPress/src/main/res/layout/site_creation_progress_screen.xml b/WordPress/src/main/res/layout/site_creation_progress_screen.xml new file mode 100644 index 000000000000..99b7e28edcc5 --- /dev/null +++ b/WordPress/src/main/res/layout/site_creation_progress_screen.xml @@ -0,0 +1,17 @@ + + + + + + + From dd57f6e680f6360ea57339189db6864893ca51c6 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 15:07:36 +0100 Subject: [PATCH 036/169] Add: Progress screen fragment and vm --- .../progress/SiteCreationProgressFragment.kt | 216 +++++++++++++ .../progress/SiteProgressViewModel.kt | 298 ++++++++++++++++++ 2 files changed, 514 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt new file mode 100644 index 000000000000..00c7955a0ba2 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt @@ -0,0 +1,216 @@ +package org.wordpress.android.ui.sitecreation.progress + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.AnimatorSet +import android.content.Context +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import dagger.hilt.android.AndroidEntryPoint +import org.wordpress.android.R +import org.wordpress.android.databinding.FullscreenErrorWithRetryBinding +import org.wordpress.android.databinding.SiteCreationProgressCreatingSiteBinding +import org.wordpress.android.databinding.SiteCreationProgressScreenBinding +import org.wordpress.android.ui.accounts.HelpActivity +import org.wordpress.android.ui.sitecreation.SiteCreationState +import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressLoadingUiState +import org.wordpress.android.ui.sitecreation.services.SiteCreationService +import org.wordpress.android.ui.utils.UiHelpers +import org.wordpress.android.util.AniUtils +import org.wordpress.android.util.AppLog +import org.wordpress.android.util.AutoForeground.ServiceEventConnection +import javax.inject.Inject + +@AndroidEntryPoint +class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_screen) { + @Inject + internal lateinit var uiHelpers: UiHelpers + + /** + * We need to connect to the service, so the service knows when the app is in the background. The service + * automatically shows system notifications when site creation is in progress and the app is in the background. + */ + private var serviceEventConnection: ServiceEventConnection? = null + private var animatorSet: AnimatorSet? = null + + private lateinit var binding: SiteCreationProgressScreenBinding + private val viewModel: SiteProgressViewModel by viewModels() + + override fun onAttach(context: Context) { + super.onAttach(context) + check(context is ProgressScreenListener) { "Parent activity must implement ProgressScreenListener." } + check(context is OnHelpClickedListener) { "Parent activity must implement OnHelpClickedListener." } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (savedInstanceState == null) { + // we need to manually clear the service state to avoid sticky events from the previous SiteCreation flow. + SiteCreationService.clearSiteCreationServiceState() + } + } + + @Suppress("DEPRECATION", "OVERRIDE_DEPRECATION") + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + init(savedInstanceState) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding = SiteCreationProgressScreenBinding.bind(view).apply { + observeState() + observeHelpClicks(requireActivity() as OnHelpClickedListener) + observeDismissClicks(requireActivity() as ProgressScreenListener) + observeSiteCreationService(requireActivity() as ProgressScreenListener) + fullscreenErrorWithRetry.setOnClickListeners() + } + + init(savedInstanceState) + } + + private fun init(savedInstanceState: Bundle?) { + (requireActivity() as AppCompatActivity).supportActionBar?.hide() + + viewModel.start(requireArguments()[ARG_DATA] as SiteCreationState, savedInstanceState) + } + + private fun SiteCreationProgressScreenBinding.observeState() { + viewModel.uiState.observe(viewLifecycleOwner) { uiState -> + uiState?.run { + when (val ui = this@run) { + is SiteProgressLoadingUiState -> siteCreationProgressCreatingSite.updateLoadingLayout(ui) + is SiteProgressErrorUiState -> fullscreenErrorWithRetry.updateErrorLayout(ui) + } + siteCreationProgressCreatingSite.progressLayout.isVisible = progressLayoutVisibility + fullscreenErrorWithRetry.errorLayout.isVisible = errorLayoutVisibility + } + } + } + + private fun observeSiteCreationService(listener: ProgressScreenListener) { + viewModel.startCreateSiteService.observe(viewLifecycleOwner) { startServiceData -> + startServiceData?.let { + SiteCreationService.createSite(requireNotNull(activity), it.previousState, it.serviceData) + } + } + viewModel.onSiteCreationCompleted.observe(viewLifecycleOwner) { + view?.announceForAccessibility(getString(R.string.new_site_creation_preview_title)) + listener.onSiteCreationCompleted(it) + } + } + + private fun observeDismissClicks(listener: ProgressScreenListener) { + viewModel.onCancelWizardClicked.observe(viewLifecycleOwner) { createSiteState -> + createSiteState?.let { listener.onProgressScreenDismissed(it) } + } + } + + private fun observeHelpClicks(listener: OnHelpClickedListener) { + viewModel.onHelpClicked.observe(viewLifecycleOwner) { + listener.onHelpClicked(HelpActivity.Origin.SITE_CREATION_CREATING) + } + } + + private fun FullscreenErrorWithRetryBinding.setOnClickListeners() { + errorRetry.setOnClickListener { viewModel.retry() } + cancelWizardButton.setOnClickListener { viewModel.onCancelWizardClicked() } + contactSupport.setOnClickListener { viewModel.onHelpClicked() } + } + + private fun FullscreenErrorWithRetryBinding.updateErrorLayout(errorUiState: SiteProgressErrorUiState) { + errorUiState.run { + uiHelpers.setTextOrHide(errorTitle, titleResId) + uiHelpers.setTextOrHide(errorSubtitle, subtitleResId) + uiHelpers.updateVisibility(contactSupport, errorUiState.showContactSupport) + uiHelpers.updateVisibility(cancelWizardButton, errorUiState.showCancelWizardButton) + } + } + + private fun SiteCreationProgressCreatingSiteBinding.updateLoadingLayout( + progressUiState: SiteProgressLoadingUiState + ) { + progressUiState.apply { + val newText = uiHelpers.getTextOfUiString(progressText.context, loadingTextResId) + AppLog.d(AppLog.T.MAIN, "Changing text - animation: $animate") + if (animate) { + updateLoadingTextWithFadeAnimation(newText) + } else { + progressText.text = newText + } + } + } + + private fun SiteCreationProgressCreatingSiteBinding.updateLoadingTextWithFadeAnimation(newText: CharSequence) { + val animationDuration = AniUtils.Duration.SHORT + val fadeOut = AniUtils.getFadeOutAnim( + progressTextLayout, + animationDuration, + View.VISIBLE + ) + val fadeIn = AniUtils.getFadeInAnim( + progressTextLayout, + animationDuration + ) + + // update the text when the view isn't visible + fadeIn.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationStart(animation: Animator) { + progressText.text = newText + } + + override fun onAnimationEnd(animation: Animator?) { + super.onAnimationEnd(animation) + animatorSet = null + } + }) + // Start the fade-in animation right after the view fades out + fadeIn.startDelay = animationDuration.toMillis(progressTextLayout.context) + + animatorSet = AnimatorSet().apply { + playSequentially(fadeOut, fadeIn) + start() + } + } + + override fun onResume() { + super.onResume() + serviceEventConnection = ServiceEventConnection(context, SiteCreationService::class.java, viewModel) + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + viewModel.writeToBundle(outState) + } + + override fun onPause() { + super.onPause() + serviceEventConnection?.disconnect(context, viewModel) + } + + override fun onStop() { + super.onStop() + if (animatorSet?.isRunning == true) { + animatorSet?.cancel() + } + } + + companion object { + const val TAG = "site_creation_progress_fragment_tag" + private const val ARG_DATA = "arg_site_creation_data" + + fun newInstance(siteCreationData: SiteCreationState) = SiteCreationProgressFragment() + .apply { + arguments = Bundle().apply { + putParcelable(ARG_DATA, siteCreationData) + } + } + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt new file mode 100644 index 000000000000..123b3bd810fc --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt @@ -0,0 +1,298 @@ +package org.wordpress.android.ui.sitecreation.progress + +import android.os.Bundle +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import org.wordpress.android.R +import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.store.SiteStore +import org.wordpress.android.modules.BG_THREAD +import org.wordpress.android.modules.UI_THREAD +import org.wordpress.android.ui.sitecreation.SiteCreationState +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState +import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR +import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.UNKNOWN +import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocalDb +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState.SiteProgressConnectionErrorUiState +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState.SiteProgressGenericErrorUiState +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressLoadingUiState +import org.wordpress.android.ui.sitecreation.services.FetchWpComSiteUseCase +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceData +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.FAILURE +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.IDLE +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.SUCCESS +import org.wordpress.android.ui.utils.UiString +import org.wordpress.android.ui.utils.UiString.UiStringRes +import org.wordpress.android.util.NetworkUtilsWrapper +import org.wordpress.android.util.UrlUtilsWrapper +import org.wordpress.android.viewmodel.SingleLiveEvent +import javax.inject.Inject +import javax.inject.Named +import kotlin.coroutines.CoroutineContext + +const val KEY_CREATE_SITE_STATE = "CREATE_SITE_STATE" +private const val CONNECTION_ERROR_DELAY_TO_SHOW_LOADING_STATE = 1000L +const val LOADING_STATE_TEXT_ANIMATION_DELAY = 2000L +private const val ERROR_CONTEXT = "site_preview" + +private val loadingTexts = listOf( + UiStringRes(R.string.new_site_creation_creating_site_loading_1), + UiStringRes(R.string.new_site_creation_creating_site_loading_2), + UiStringRes(R.string.new_site_creation_creating_site_loading_3), + UiStringRes(R.string.new_site_creation_creating_site_loading_4) +) + +@HiltViewModel +class SiteProgressViewModel @Inject constructor( + private val dispatcher: Dispatcher, + private val siteStore: SiteStore, + private val fetchWpComSiteUseCase: FetchWpComSiteUseCase, + private val networkUtils: NetworkUtilsWrapper, + private val urlUtils: UrlUtilsWrapper, + private val tracker: SiteCreationTracker, + @Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, + @Named(UI_THREAD) private val mainDispatcher: CoroutineDispatcher +) : ViewModel(), CoroutineScope { + private val job = Job() + override val coroutineContext: CoroutineContext + get() = bgDispatcher + job + private var isStarted = false + private var loadingAnimationJob: Job? = null + + private lateinit var siteCreationState: SiteCreationState + private var urlWithoutScheme: String? = null + private var siteTitle: String? = null + private var lastReceivedServiceState: SiteCreationServiceState? = null + private var serviceStateForRetry: SiteCreationServiceState? = null + private var createSiteState: CreateSiteState = SiteNotCreated + + private val _uiState: MutableLiveData = MutableLiveData() + val uiState: LiveData = _uiState + + private val _startCreateSiteService: SingleLiveEvent = SingleLiveEvent() + val startCreateSiteService: LiveData = _startCreateSiteService + + private val _onHelpClicked = SingleLiveEvent() + val onHelpClicked: LiveData = _onHelpClicked + + private val _onCancelWizardClicked = SingleLiveEvent() + val onCancelWizardClicked: LiveData = _onCancelWizardClicked + + private val _onSiteCreationCompleted = SingleLiveEvent() + val onSiteCreationCompleted: LiveData = _onSiteCreationCompleted + + init { + dispatcher.register(fetchWpComSiteUseCase) + } + + override fun onCleared() { + super.onCleared() + dispatcher.unregister(fetchWpComSiteUseCase) + job.cancel() + loadingAnimationJob?.cancel() + } + + fun writeToBundle(outState: Bundle) = outState.putParcelable(KEY_CREATE_SITE_STATE, createSiteState) + + fun start(siteCreationState: SiteCreationState, savedState: Bundle?) { + if (isStarted) return + isStarted = true + this.siteCreationState = siteCreationState + urlWithoutScheme = siteCreationState.domain?.domainName + siteTitle = siteCreationState.siteName + + val restoredState = savedState?.getParcelable(KEY_CREATE_SITE_STATE) + + init(restoredState ?: SiteNotCreated) + } + + private fun init(state: CreateSiteState) { + createSiteState = state + when (state) { + SiteNotCreated -> { + runLoadingAnimationUi() + startCreateSiteService() + } + is SiteNotInLocalDb -> { + runLoadingAnimationUi() + launch { + createSiteState = fetchNewlyCreatedSiteModel(state.remoteSiteId) + } + } + is SiteCreationCompleted -> Unit + } + } + + private fun startCreateSiteService(previousState: SiteCreationServiceState? = null) { + if (networkUtils.isNetworkAvailable()) { + siteCreationState.apply { + // A non-null [segmentId] may invalidate the [siteDesign] selection + // https://github.com/wordpress-mobile/WordPress-Android/issues/13749 + val segmentIdentifier = if (siteDesign != null) null else segmentId + val serviceData = SiteCreationServiceData( + segmentIdentifier, + siteDesign, + urlWithoutScheme, + siteTitle + ) + _startCreateSiteService.value = SitePreviewStartServiceData(serviceData, previousState) + } + } else { + showFullscreenErrorWithDelay() + } + } + + fun retry() { + runLoadingAnimationUi() + startCreateSiteService(serviceStateForRetry) + } + + fun onHelpClicked() = _onHelpClicked.call() + + fun onCancelWizardClicked() { + _onCancelWizardClicked.value = createSiteState + } + + private fun showFullscreenErrorWithDelay() { + runLoadingAnimationUi() + launch(mainDispatcher) { + // We show the loading indicator for a bit so the user has some feedback when they press retry + delay(CONNECTION_ERROR_DELAY_TO_SHOW_LOADING_STATE) + tracker.trackErrorShown(ERROR_CONTEXT, INTERNET_UNAVAILABLE_ERROR) + updateUiState(SiteProgressConnectionErrorUiState) + } + } + + /** + * The service automatically shows system notifications when site creation is in progress and the app is in + * the background. We need to connect to the `AutoForeground` service from the View(Fragment), as only the View + * knows when the app is in the background. Required parameter for `ServiceEventConnection` is also + * the observer/listener of the `SiteCreationServiceState` (VM in our case), therefore we can't simply register + * to the EventBus from the ViewModel and we have to use `sticky` events instead. + */ + @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true) + @Suppress("unused") + fun onSiteCreationServiceStateUpdated(event: SiteCreationServiceState) { + if (lastReceivedServiceState == event) return // filter out events which we've already received + lastReceivedServiceState = event + when (event.step) { + IDLE, CREATE_SITE -> Unit + SUCCESS -> { + val remoteSiteId = (event.payload as Pair<*, *>).first as Long + urlWithoutScheme = urlUtils.removeScheme(event.payload.second as String).trimEnd('/') + createSiteState = SiteNotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) + launch { + createSiteState = fetchNewlyCreatedSiteModel(remoteSiteId) + // move @ end of animation with if + // _onSiteCreationCompleted.postValue(createSiteState) + } + } + FAILURE -> { + serviceStateForRetry = event.payload as SiteCreationServiceState + tracker.trackErrorShown( + ERROR_CONTEXT, + UNKNOWN, + "SiteCreation service failed" + ) + updateUiStateAsync(SiteProgressGenericErrorUiState) + } + } + } + + /** + * Fetch newly created site model - supports retry with linear backoff. + */ + private suspend fun fetchNewlyCreatedSiteModel(remoteSiteId: Long): CreateSiteState { + val onSiteFetched = fetchWpComSiteUseCase.fetchSiteWithRetry(remoteSiteId) + return if (!onSiteFetched.isError) { + val siteBySiteId = requireNotNull(siteStore.getSiteBySiteId(remoteSiteId)) { + "Site successfully fetched but has not been found in the local db." + } + SiteCreationCompleted(siteBySiteId.id, !siteTitle.isNullOrBlank(), siteBySiteId.url) + } else { + SiteNotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) + } + } + + private fun runLoadingAnimationUi() { + loadingAnimationJob?.cancel() + loadingAnimationJob = launch(mainDispatcher) { + var i = 0 + val listSize = loadingTexts.size + repeat(listSize) { + updateUiState( + SiteProgressLoadingUiState( + animate = i != 0, // the first text should appear without an animation + loadingTextResId = loadingTexts[i++ % listSize] + ) + ) + delay(LOADING_STATE_TEXT_ANIMATION_DELAY) + } + + check(createSiteState !is SiteNotCreated) { + "Site should have been created by now." + } + + _onSiteCreationCompleted.postValue(createSiteState) + } + } + + private fun updateUiState(uiState: SiteProgressUiState) { + if (uiState !is SiteProgressLoadingUiState) { + loadingAnimationJob?.cancel() + } + _uiState.value = uiState + } + + private fun updateUiStateAsync(uiState: SiteProgressUiState) { + if (uiState !is SiteProgressLoadingUiState) { + loadingAnimationJob?.cancel() + } + _uiState.postValue(uiState) + } + + sealed class SiteProgressUiState( + val progressLayoutVisibility: Boolean = false, + val errorLayoutVisibility: Boolean = false + ) { + data class SiteProgressLoadingUiState(val loadingTextResId: UiString, val animate: Boolean) : + SiteProgressUiState(progressLayoutVisibility = true) + + sealed class SiteProgressErrorUiState constructor( + val titleResId: Int, + val subtitleResId: Int? = null, + val showContactSupport: Boolean = false, + val showCancelWizardButton: Boolean = true + ) : SiteProgressUiState(errorLayoutVisibility = true) { + object SiteProgressGenericErrorUiState : SiteProgressErrorUiState( + R.string.site_creation_error_generic_title, + R.string.site_creation_error_generic_subtitle, + showContactSupport = true + ) + + object SiteProgressConnectionErrorUiState : SiteProgressErrorUiState( + R.string.no_network_message + ) + } + } + + data class SitePreviewStartServiceData( + val serviceData: SiteCreationServiceData, + val previousState: SiteCreationServiceState? + ) + +} From 37b28a46a00e61ba2139c117eaba8b318f0493a3 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 15:24:42 +0100 Subject: [PATCH 037/169] Refactor: split progress from preview as 2 separate steps in site creation --- .../android/ui/accounts/HelpActivity.kt | 1 + .../ui/sitecreation/SiteCreationActivity.kt | 11 +- .../ui/sitecreation/SiteCreationMainVM.kt | 5 +- .../ui/sitecreation/SiteCreationStep.kt | 9 +- .../previews/SiteCreationPreviewFragment.kt | 161 ++--------- .../previews/SitePreviewScreenListener.kt | 3 +- .../previews/SitePreviewViewModel.kt | 271 +----------------- .../site_creation_preview_screen_default.xml | 5 - .../site_creation_preview_screen_default.xml | 5 - 9 files changed, 47 insertions(+), 424 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/HelpActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/accounts/HelpActivity.kt index 5e31c8ee9575..941e633b3696 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/HelpActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/HelpActivity.kt @@ -354,6 +354,7 @@ class HelpActivity : LocaleAwareActivity() { SIGNUP_MAGIC_LINK("origin:signup-magic-link"), SIGNUP_CONFIRMATION("origin:signup-confirmation"), SITE_CREATION_CREATING("origin:site-create-creating"), + SITE_CREATION_CREATED("origin:site-create-created"), SITE_CREATION_SEGMENTS("origin:site-create-site-segments"), SITE_CREATION_VERTICALS("origin:site-create-site-verticals"), SITE_CREATION_DOMAINS("origin:site-create-domains"), diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 79712549572e..75a9bfec39b1 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -28,6 +28,7 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.SiteCreationStep.DOMAINS import org.wordpress.android.ui.sitecreation.SiteCreationStep.INTENTS +import org.wordpress.android.ui.sitecreation.SiteCreationStep.PROGRESS import org.wordpress.android.ui.sitecreation.SiteCreationStep.SITE_DESIGNS import org.wordpress.android.ui.sitecreation.SiteCreationStep.SITE_NAME import org.wordpress.android.ui.sitecreation.SiteCreationStep.SITE_PREVIEW @@ -42,6 +43,8 @@ import org.wordpress.android.ui.sitecreation.misc.CreateSiteState import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocalDb +import org.wordpress.android.ui.sitecreation.progress.ProgressScreenListener +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressFragment import org.wordpress.android.ui.sitecreation.sitename.SiteCreationSiteNameFragment import org.wordpress.android.ui.sitecreation.sitename.SiteCreationSiteNameViewModel import org.wordpress.android.ui.sitecreation.sitename.SiteNameScreenListener @@ -63,6 +66,7 @@ class SiteCreationActivity : LocaleAwareActivity(), IntentsScreenListener, SiteNameScreenListener, DomainsScreenListener, + ProgressScreenListener, SitePreviewScreenListener, OnHelpClickedListener, BasicDialogPositiveClickInterface, @@ -210,7 +214,9 @@ class SiteCreationActivity : LocaleAwareActivity(), mainViewModel.onDomainsScreenFinished(domain) } - override fun onSiteCreationCompleted() = mainViewModel.onSiteCreationCompleted() + override fun onSiteCreationCompleted(state: CreateSiteState) = mainViewModel.onSiteCreationCompleted(state) + + override fun onProgressScreenDismissed(state: CreateSiteState) = mainViewModel.onProgressOrPreviewFinished(state) override fun onPreviewScreenDismissed(state: CreateSiteState) = mainViewModel.onProgressOrPreviewFinished(state) @@ -229,7 +235,8 @@ class SiteCreationActivity : LocaleAwareActivity(), HomePagePickerFragment.newInstance(target.wizardState.siteIntent) } DOMAINS -> SiteCreationDomainsFragment.newInstance(screenTitle) - SITE_PREVIEW -> SiteCreationPreviewFragment.newInstance(screenTitle, target.wizardState) + PROGRESS -> SiteCreationProgressFragment.newInstance(target.wizardState) + SITE_PREVIEW -> SiteCreationPreviewFragment.newInstance(screenTitle, target.wizardState, mainViewModel.result) } slideInFragment(fragment, target.wizardStep.toString()) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index c5f6ca9348be..674bb4a399b4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -84,6 +84,7 @@ class SiteCreationMainVM @Inject constructor( private var siteCreationCompleted = false private lateinit var siteCreationState: SiteCreationState + lateinit var result: CreateSiteState internal var preloadingJob: Job? = null @@ -250,8 +251,10 @@ class SiteCreationMainVM @Inject constructor( } } - fun onSiteCreationCompleted() { + fun onSiteCreationCompleted(state: CreateSiteState) { + result = state siteCreationCompleted = true + wizardManager.showNextStep() } /** diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationStep.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationStep.kt index c46b0dfda43d..6a2e52a4fead 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationStep.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationStep.kt @@ -2,6 +2,7 @@ package org.wordpress.android.ui.sitecreation import org.wordpress.android.ui.sitecreation.SiteCreationStep.DOMAINS import org.wordpress.android.ui.sitecreation.SiteCreationStep.INTENTS +import org.wordpress.android.ui.sitecreation.SiteCreationStep.PROGRESS import org.wordpress.android.ui.sitecreation.SiteCreationStep.SITE_DESIGNS import org.wordpress.android.ui.sitecreation.SiteCreationStep.SITE_NAME import org.wordpress.android.ui.sitecreation.SiteCreationStep.SITE_PREVIEW @@ -12,7 +13,7 @@ import javax.inject.Inject import javax.inject.Singleton enum class SiteCreationStep : WizardStep { - SITE_DESIGNS, DOMAINS, SITE_PREVIEW, INTENTS, SITE_NAME; + SITE_DESIGNS, DOMAINS, PROGRESS, SITE_PREVIEW, INTENTS, SITE_NAME; } @Singleton @@ -24,8 +25,8 @@ class SiteCreationStepsProvider @Inject constructor( private val isIntentsEnabled get() = siteIntentQuestionFeatureConfig.isEnabled() fun getSteps(): List = when { - isSiteNameEnabled -> listOf(INTENTS, SITE_NAME, SITE_DESIGNS, SITE_PREVIEW) - isIntentsEnabled -> listOf(INTENTS, SITE_DESIGNS, DOMAINS, SITE_PREVIEW) - else -> listOf(SITE_DESIGNS, DOMAINS, SITE_PREVIEW) + isSiteNameEnabled -> listOf(INTENTS, SITE_NAME, SITE_DESIGNS, PROGRESS, SITE_PREVIEW) + isIntentsEnabled -> listOf(INTENTS, SITE_DESIGNS, DOMAINS, PROGRESS, SITE_PREVIEW) + else -> listOf(SITE_DESIGNS, DOMAINS, PROGRESS, SITE_PREVIEW) } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 5fe292dd6c46..681b1d2c8e91 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -1,7 +1,5 @@ package org.wordpress.android.ui.sitecreation.previews -import android.animation.Animator -import android.animation.AnimatorListenerAdapter import android.animation.AnimatorSet import android.animation.ObjectAnimator import android.content.Context @@ -19,32 +17,26 @@ import androidx.fragment.app.viewModels import dagger.hilt.android.AndroidEntryPoint import org.wordpress.android.R import org.wordpress.android.WordPress -import org.wordpress.android.databinding.FullscreenErrorWithRetryBinding import org.wordpress.android.databinding.SiteCreationFormScreenBinding import org.wordpress.android.databinding.SiteCreationPreviewScreenBinding import org.wordpress.android.databinding.SiteCreationPreviewScreenDefaultBinding -import org.wordpress.android.databinding.SiteCreationProgressCreatingSiteBinding import org.wordpress.android.ui.accounts.HelpActivity import org.wordpress.android.ui.sitecreation.SiteCreationBaseFormFragment import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewData import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewFullscreenErrorUiState -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewFullscreenProgressUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewLoadingShimmerState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewWebErrorUiState -import org.wordpress.android.ui.sitecreation.services.SiteCreationService +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState import org.wordpress.android.ui.utils.UiHelpers -import org.wordpress.android.util.AniUtils -import org.wordpress.android.util.AppLog -import org.wordpress.android.util.AutoForeground.ServiceEventConnection import org.wordpress.android.util.ErrorManagedWebViewClient.ErrorManagedWebViewClientListener import org.wordpress.android.util.URLFilteredWebViewClient import org.wordpress.android.widgets.NestedWebView import javax.inject.Inject private const val ARG_DATA = "arg_site_creation_data" +private const val ARG_RESULT = "arg_site_creation_result" private const val SLIDE_IN_ANIMATION_DURATION = 450L @AndroidEntryPoint @@ -53,12 +45,6 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), @Inject internal lateinit var uiHelpers: UiHelpers - /** - * We need to connect to the service, so the service knows when the app is in the background. The service - * automatically shows system notifications when site creation is in progress and the app is in the background. - */ - private var serviceEventConnection: ServiceEventConnection? = null - private var animatorSet: AnimatorSet? = null private val isLandscape get() = resources.configuration.orientation == ORIENTATION_LANDSCAPE private lateinit var binding: SiteCreationPreviewScreenBinding @@ -70,30 +56,24 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), check(context is OnHelpClickedListener) { "Parent activity must implement OnHelpClickedListener." } } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - if (savedInstanceState == null) { - // we need to manually clear the SiteCreationService state so we don't for example receive sticky events - // from the previous run of the SiteCreation flow. - SiteCreationService.clearSiteCreationServiceState() - } - } - @Suppress("DEPRECATION", "OVERRIDE_DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - init(savedInstanceState) + init() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - init(savedInstanceState) + init() } - private fun init(savedInstanceState: Bundle?) { + private fun init() { (requireActivity() as AppCompatActivity).supportActionBar?.hide() - viewModel.start(requireArguments()[ARG_DATA] as SiteCreationState, savedInstanceState) + viewModel.start( + requireArguments()[ARG_DATA] as SiteCreationState, + requireArguments()[ARG_RESULT] as CreateSiteState, + ) } override fun getContentLayout() = R.layout.site_creation_preview_screen @@ -111,10 +91,8 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), binding.siteCreationPreviewScreenDefault.run { observeState() observePreview(siteCreationPreviewWebViewContainer.sitePreviewWebView) - observeSiteCreationService(requireActivity() as SitePreviewScreenListener) observeHelpClicks(requireActivity() as OnHelpClickedListener) observeDismissClicks(requireActivity() as SitePreviewScreenListener) - fullscreenErrorWithRetry.setOnClickListeners() okButton.setOnClickListener { viewModel.onOkButtonClicked() } } } @@ -125,9 +103,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), when (val ui = this@run) { is SitePreviewContentUiState -> updateContentLayout(ui.data) is SitePreviewWebErrorUiState -> updateContentLayout(ui.data) - is SitePreviewLoadingShimmerState -> updateContentLayout(ui.data) - is SitePreviewFullscreenProgressUiState -> siteCreationProgressCreatingSite.updateLoadingLayout(ui) - is SitePreviewFullscreenErrorUiState -> fullscreenErrorWithRetry.updateErrorLayout(ui) + is SitePreviewLoadingShimmerState -> updateContentLayout(ui.data, isFirstContent = true) } uiHelpers.updateVisibility(contentLayout, contentLayoutVisibility) uiHelpers.updateVisibility(fullscreenErrorWithRetry.errorLayout, fullscreenErrorLayoutVisibility) @@ -150,24 +126,9 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } } - private fun observeSiteCreationService(listener: SitePreviewScreenListener) { - viewModel.startCreateSiteService.observe(this) { startServiceData -> - startServiceData?.let { - SiteCreationService.createSite( - requireNotNull(activity), - startServiceData.previousState, - startServiceData.serviceData - ) - } - } - viewModel.onSiteCreationCompleted.observe(this) { - listener.onSiteCreationCompleted() - } - } - private fun observeHelpClicks(listener: OnHelpClickedListener) { viewModel.onHelpClicked.observe(this) { - listener.onHelpClicked(HelpActivity.Origin.SITE_CREATION_CREATING) + listener.onHelpClicked(HelpActivity.Origin.SITE_CREATION_CREATED) } } @@ -175,27 +136,12 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), viewModel.onOkButtonClicked.observe(this) { createSiteState -> createSiteState?.let { listener.onPreviewScreenDismissed(it) } } - viewModel.onCancelWizardClicked.observe(this) { createSiteState -> - createSiteState?.let { listener.onPreviewScreenDismissed(it) } - } - } - - private fun FullscreenErrorWithRetryBinding.setOnClickListeners() { - errorRetry.setOnClickListener { viewModel.retry() } - cancelWizardButton.setOnClickListener { viewModel.onCancelWizardClicked() } - contactSupport.setOnClickListener { viewModel.onHelpClicked() } } - private fun FullscreenErrorWithRetryBinding.updateErrorLayout(errorUiState: SitePreviewFullscreenErrorUiState) { - errorUiState.apply { - uiHelpers.setTextOrHide(errorTitle, titleResId) - uiHelpers.setTextOrHide(errorSubtitle, subtitleResId) - uiHelpers.updateVisibility(contactSupport, errorUiState.showContactSupport) - uiHelpers.updateVisibility(cancelWizardButton, errorUiState.showCancelWizardButton) - } - } - - private fun SiteCreationPreviewScreenDefaultBinding.updateContentLayout(sitePreviewData: SitePreviewData) { + private fun SiteCreationPreviewScreenDefaultBinding.updateContentLayout( + sitePreviewData: SitePreviewData, + isFirstContent: Boolean = false, + ) { sitePreviewData.apply { siteCreationPreviewWebViewContainer.sitePreviewWebUrlTitle.text = createSpannableUrl( requireNotNull(activity), @@ -204,58 +150,9 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), domainIndices ) } - if (contentLayout.visibility == View.GONE) { + if (isFirstContent) { animateContentTransition() - view?.announceForAccessibility( - getString(R.string.new_site_creation_preview_title) + - getString(R.string.new_site_creation_site_preview_content_description) - ) - } - } - - private fun SiteCreationProgressCreatingSiteBinding.updateLoadingLayout( - progressUiState: SitePreviewFullscreenProgressUiState - ) { - progressUiState.apply { - val newText = uiHelpers.getTextOfUiString(progressText.context, loadingTextResId) - AppLog.d(AppLog.T.MAIN, "Changing text - animation: $animate") - if (animate) { - updateLoadingTextWithFadeAnimation(newText) - } else { - progressText.text = newText - } - } - } - - private fun SiteCreationProgressCreatingSiteBinding.updateLoadingTextWithFadeAnimation(newText: CharSequence) { - val animationDuration = AniUtils.Duration.SHORT - val fadeOut = AniUtils.getFadeOutAnim( - progressTextLayout, - animationDuration, - View.VISIBLE - ) - val fadeIn = AniUtils.getFadeInAnim( - progressTextLayout, - animationDuration - ) - - // update the text when the view isn't visible - fadeIn.addListener(object : AnimatorListenerAdapter() { - override fun onAnimationStart(animation: Animator) { - progressText.text = newText - } - - override fun onAnimationEnd(animation: Animator?) { - super.onAnimationEnd(animation) - animatorSet = null - } - }) - // Start the fade-in animation right after the view fades out - fadeIn.startDelay = animationDuration.toMillis(progressTextLayout.context) - - animatorSet = AnimatorSet().apply { - playSequentially(fadeOut, fadeIn) - start() + view?.announceForAccessibility(getString(R.string.new_site_creation_site_preview_content_description)) } } @@ -357,38 +254,18 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), private fun createFadeInAnimator(view: View) = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f) - override fun onResume() { - super.onResume() - serviceEventConnection = ServiceEventConnection(context, SiteCreationService::class.java, viewModel) - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - viewModel.writeToBundle(outState) - } - - override fun onPause() { - super.onPause() - serviceEventConnection?.disconnect(context, viewModel) - } - - override fun onStop() { - super.onStop() - if (animatorSet?.isRunning == true) { - animatorSet?.cancel() - } - } - companion object { const val TAG = "site_creation_preview_fragment_tag" fun newInstance( screenTitle: String, siteCreationData: SiteCreationState, + createSiteState: CreateSiteState, ) = SiteCreationPreviewFragment().apply { arguments = Bundle().apply { putString(EXTRA_SCREEN_TITLE, screenTitle) putParcelable(ARG_DATA, siteCreationData) + putParcelable(ARG_RESULT, createSiteState) } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt index 34deeaf027f0..5eadb73e92cc 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt @@ -1,8 +1,7 @@ package org.wordpress.android.ui.sitecreation.previews -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState interface SitePreviewScreenListener { fun onPreviewScreenDismissed(state: CreateSiteState) - fun onSiteCreationCompleted() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 7238b618e1e3..2600afd0dc9b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -1,8 +1,5 @@ package org.wordpress.android.ui.sitecreation.previews -import android.annotation.SuppressLint -import android.os.Bundle -import android.os.Parcelable import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -10,44 +7,21 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import kotlinx.parcelize.Parcelize -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode -import org.wordpress.android.R -import org.wordpress.android.fluxc.Dispatcher -import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.sitecreation.SiteCreationState -import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR -import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.UNKNOWN +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocalDb import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewFullscreenErrorUiState.SitePreviewConnectionErrorUiState -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewFullscreenErrorUiState.SitePreviewGenericErrorUiState -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewFullscreenProgressUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewLoadingShimmerState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewWebErrorUiState -import org.wordpress.android.ui.sitecreation.services.FetchWpComSiteUseCase import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceData import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.FAILURE -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.IDLE -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.SUCCESS import org.wordpress.android.ui.sitecreation.usecases.isWordPressComSubDomain -import org.wordpress.android.ui.utils.UiString -import org.wordpress.android.ui.utils.UiString.UiStringRes import org.wordpress.android.util.AppLog import org.wordpress.android.util.AppLog.T -import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.util.UrlUtilsWrapper import org.wordpress.android.viewmodel.SingleLiveEvent import javax.inject.Inject @@ -55,24 +29,10 @@ import javax.inject.Named import kotlin.coroutines.CoroutineContext const val KEY_CREATE_SITE_STATE = "CREATE_SITE_STATE" -private const val CONNECTION_ERROR_DELAY_TO_SHOW_LOADING_STATE = 1000L -private const val DELAY_TO_SHOW_WEB_VIEW_LOADING_SHIMMER = 1000L const val LOADING_STATE_TEXT_ANIMATION_DELAY = 2000L -private const val ERROR_CONTEXT = "site_preview" - -private val loadingTexts = listOf( - UiStringRes(R.string.new_site_creation_creating_site_loading_1), - UiStringRes(R.string.new_site_creation_creating_site_loading_2), - UiStringRes(R.string.new_site_creation_creating_site_loading_3), - UiStringRes(R.string.new_site_creation_creating_site_loading_4) -) @HiltViewModel class SitePreviewViewModel @Inject constructor( - private val dispatcher: Dispatcher, - private val siteStore: SiteStore, - private val fetchWpComSiteUseCase: FetchWpComSiteUseCase, - private val networkUtils: NetworkUtilsWrapper, private val urlUtils: UrlUtilsWrapper, private val tracker: SiteCreationTracker, @Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, @@ -83,14 +43,10 @@ class SitePreviewViewModel @Inject constructor( get() = bgDispatcher + job private var isStarted = false private var webviewFullyLoadedTracked = false - private var loadingAnimationJob: Job? = null private lateinit var siteCreationState: SiteCreationState private var urlWithoutScheme: String? = null - private var siteTitle: String? = null - private var lastReceivedServiceState: SiteCreationServiceState? = null - private var serviceStateForRetry: SiteCreationServiceState? = null - private var createSiteState: CreateSiteState = SiteNotCreated + private lateinit var createSiteState: CreateSiteState private val _uiState: MutableLiveData = MutableLiveData() val uiState: LiveData = _uiState @@ -98,94 +54,24 @@ class SitePreviewViewModel @Inject constructor( private val _preloadPreview: MutableLiveData = MutableLiveData() val preloadPreview: LiveData = _preloadPreview - private val _startCreateSiteService: SingleLiveEvent = SingleLiveEvent() - val startCreateSiteService: LiveData = _startCreateSiteService - private val _onHelpClicked = SingleLiveEvent() val onHelpClicked: LiveData = _onHelpClicked - private val _onCancelWizardClicked = SingleLiveEvent() - val onCancelWizardClicked: LiveData = _onCancelWizardClicked - private val _onOkButtonClicked = SingleLiveEvent() val onOkButtonClicked: LiveData = _onOkButtonClicked - private val _onSiteCreationCompleted = SingleLiveEvent() - val onSiteCreationCompleted: LiveData = _onSiteCreationCompleted - - init { - dispatcher.register(fetchWpComSiteUseCase) - } - override fun onCleared() { super.onCleared() - dispatcher.unregister(fetchWpComSiteUseCase) job.cancel() - loadingAnimationJob?.cancel() - } - - fun writeToBundle(outState: Bundle) { - outState.putParcelable(KEY_CREATE_SITE_STATE, createSiteState) } - fun start(siteCreationState: SiteCreationState, savedState: Bundle?) { - if (isStarted) { - return - } + fun start(siteCreationState: SiteCreationState, createSiteState: CreateSiteState) { + if (isStarted) return isStarted = true this.siteCreationState = siteCreationState - urlWithoutScheme = siteCreationState.domain?.domainName - siteTitle = siteCreationState.siteName - - val restoredState = savedState?.getParcelable(KEY_CREATE_SITE_STATE) - - init(restoredState ?: SiteNotCreated) - } - - private fun init(state: CreateSiteState) { - createSiteState = state - when (state) { - SiteNotCreated -> { - showFullscreenProgress() - startCreateSiteService() - } - is SiteNotInLocalDb -> { - showFullscreenProgress() - startPreLoadingWebView() - fetchNewlyCreatedSiteModel(state.remoteSiteId) - } - is SiteCreationCompleted -> { - startPreLoadingWebView(skipDelay = true) - } - } - } - - private fun startCreateSiteService(previousState: SiteCreationServiceState? = null) { - if (networkUtils.isNetworkAvailable()) { - siteCreationState.apply { - // A non-null [segmentId] may invalidate the [siteDesign] selection - // https://github.com/wordpress-mobile/WordPress-Android/issues/13749 - val segmentIdentifier = if (siteDesign != null) null else segmentId - val serviceData = SiteCreationServiceData( - segmentIdentifier, - siteDesign, - urlWithoutScheme, - siteTitle - ) - _startCreateSiteService.value = SitePreviewStartServiceData(serviceData, previousState) - } - } else { - showFullscreenErrorWithDelay() - } - } - - fun retry() { - showFullscreenProgress() - startCreateSiteService(serviceStateForRetry) - } - - fun onHelpClicked() { - _onHelpClicked.call() + this.urlWithoutScheme = siteCreationState.domain?.domainName + this.createSiteState = createSiteState + startPreLoadingWebView() } fun onHelpClicked() = _onHelpClicked.call() @@ -195,78 +81,9 @@ class SitePreviewViewModel @Inject constructor( _onOkButtonClicked.value = createSiteState } - private fun showFullscreenErrorWithDelay() { - showFullscreenProgress() - launch(mainDispatcher) { - // We show the loading indicator for a bit so the user has some feedback when they press retry - delay(CONNECTION_ERROR_DELAY_TO_SHOW_LOADING_STATE) - tracker.trackErrorShown(ERROR_CONTEXT, INTERNET_UNAVAILABLE_ERROR) - updateUiState(SitePreviewConnectionErrorUiState) - } - } - - /** - * The service automatically shows system notifications when site creation is in progress and the app is in - * the background. We need to connect to the `AutoForeground` service from the View(Fragment), as only the View - * knows when the app is in the background. Required parameter for `ServiceEventConnection` is also - * the observer/listener of the `SiteCreationServiceState` (VM in our case), therefore we can't simply register - * to the EventBus from the ViewModel and we have to use `sticky` events instead. - */ - @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true) - @Suppress("unused") - fun onSiteCreationServiceStateUpdated(event: SiteCreationServiceState) { - if (lastReceivedServiceState == event) return // filter out events which we've already received - lastReceivedServiceState = event - when (event.step) { - IDLE, CREATE_SITE -> { - } // do nothing - SUCCESS -> { - val remoteSiteId = (event.payload as Pair<*, *>).first as Long - urlWithoutScheme = urlUtils.removeScheme(event.payload.second as String).trimEnd('/') - createSiteState = SiteNotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) - startPreLoadingWebView() - fetchNewlyCreatedSiteModel(remoteSiteId) - _onSiteCreationCompleted.asyncCall() - } - FAILURE -> { - serviceStateForRetry = event.payload as SiteCreationServiceState - tracker.trackErrorShown( - ERROR_CONTEXT, - UNKNOWN, - "SiteCreation service failed" - ) - updateUiStateAsync(SitePreviewGenericErrorUiState) - } - } - } - - /** - * Fetch newly created site model - supports retry with linear backoff. - */ - private fun fetchNewlyCreatedSiteModel(remoteSiteId: Long) { - launch { - val onSiteFetched = fetchWpComSiteUseCase.fetchSiteWithRetry(remoteSiteId) - createSiteState = if (!onSiteFetched.isError) { - val siteBySiteId = requireNotNull(siteStore.getSiteBySiteId(remoteSiteId)) { - "Site successfully fetched but has not been found in the local db." - } - CreateSiteState.SiteCreationCompleted(siteBySiteId.id, !siteTitle.isNullOrBlank()) - } else { - SiteNotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) - } - } - } - - private fun startPreLoadingWebView(skipDelay: Boolean = false) { + private fun startPreLoadingWebView() { tracker.trackPreviewLoading(siteCreationState.siteDesign) launch { - if (!skipDelay) { - /** - * Keep showing the full screen loading screen for 1 more second or until the webview is loaded - * whichever happens first. This will give us some more time to fetch the newly created site. - */ - delay(DELAY_TO_SHOW_WEB_VIEW_LOADING_SHIMMER) - } /** * If the webview is still not loaded after some delay, we'll show the loading shimmer animation instead * of the full screen progress, so the user is not blocked for taking actions. @@ -323,39 +140,11 @@ class SitePreviewViewModel @Inject constructor( ) } - private fun showFullscreenProgress() { - loadingAnimationJob?.cancel() - loadingAnimationJob = launch(mainDispatcher) { - var i = 0 - val listSize = loadingTexts.size - while (isActive) { - updateUiState( - SitePreviewFullscreenProgressUiState( - animate = i != 0, // the first text should appear without an animation - loadingTextResId = loadingTexts[i++ % listSize] - ) - ) - delay(LOADING_STATE_TEXT_ANIMATION_DELAY) - } - } - } - private fun updateUiState(uiState: SitePreviewUiState) { - if (uiState !is SitePreviewFullscreenProgressUiState) { - loadingAnimationJob?.cancel() - } _uiState.value = uiState } - private fun updateUiStateAsync(uiState: SitePreviewUiState) { - if (uiState !is SitePreviewFullscreenProgressUiState) { - loadingAnimationJob?.cancel() - } - _uiState.postValue(uiState) - } - sealed class SitePreviewUiState( - val fullscreenProgressLayoutVisibility: Boolean = false, val contentLayoutVisibility: Boolean = false, val webViewVisibility: Boolean = false, val webViewErrorVisibility: Boolean = false, @@ -378,27 +167,6 @@ class SitePreviewViewModel @Inject constructor( contentLayoutVisibility = true, shimmerVisibility = true ) - - data class SitePreviewFullscreenProgressUiState(val loadingTextResId: UiString, val animate: Boolean) : - SitePreviewUiState(fullscreenProgressLayoutVisibility = true) - - sealed class SitePreviewFullscreenErrorUiState constructor( - val titleResId: Int, - val subtitleResId: Int? = null, - val showContactSupport: Boolean = false, - val showCancelWizardButton: Boolean = true - ) : SitePreviewUiState( - fullscreenErrorLayoutVisibility = true - ) { - object SitePreviewGenericErrorUiState : - SitePreviewFullscreenErrorUiState( - R.string.site_creation_error_generic_title, - ) - - object SitePreviewConnectionErrorUiState : SitePreviewFullscreenErrorUiState( - R.string.no_network_message - ) - } } data class SitePreviewData( @@ -412,27 +180,4 @@ class SitePreviewViewModel @Inject constructor( val serviceData: SiteCreationServiceData, val previousState: SiteCreationServiceState? ) - - @SuppressLint("ParcelCreator") - sealed class CreateSiteState : Parcelable { - /** - * CreateSite request haven't finished yet or failed. - */ - @Parcelize - object SiteNotCreated : CreateSiteState() - - /** - * FetchSite request haven't finished yet or failed. - * Since we fetch the site without user awareness in background, the user may potentially leave the screen - * before the request is finished. - */ - @Parcelize - data class SiteNotInLocalDb(val remoteSiteId: Long, val isSiteTitleTaskComplete: Boolean) : CreateSiteState() - - /** - * The site has been successfully created and stored into local db. - */ - @Parcelize - data class SiteCreationCompleted(val localSiteId: Int, val isSiteTitleTaskComplete: Boolean) : CreateSiteState() - } } diff --git a/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml b/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml index 58d67c08010f..3489a7fa59de 100644 --- a/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml +++ b/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml @@ -10,11 +10,6 @@ layout="@layout/fullscreen_error_with_retry" tools:visibility="gone" /> - - - - Date: Tue, 7 Mar 2023 15:39:53 +0100 Subject: [PATCH 038/169] Refactor: rename `SitePreviewStartServiceData` to `StartServiceData` --- .../ui/sitecreation/progress/SiteProgressViewModel.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt index 123b3bd810fc..e77f2d42e15d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt @@ -83,8 +83,8 @@ class SiteProgressViewModel @Inject constructor( private val _uiState: MutableLiveData = MutableLiveData() val uiState: LiveData = _uiState - private val _startCreateSiteService: SingleLiveEvent = SingleLiveEvent() - val startCreateSiteService: LiveData = _startCreateSiteService + private val _startCreateSiteService: SingleLiveEvent = SingleLiveEvent() + val startCreateSiteService: LiveData = _startCreateSiteService private val _onHelpClicked = SingleLiveEvent() val onHelpClicked: LiveData = _onHelpClicked @@ -149,7 +149,7 @@ class SiteProgressViewModel @Inject constructor( urlWithoutScheme, siteTitle ) - _startCreateSiteService.value = SitePreviewStartServiceData(serviceData, previousState) + _startCreateSiteService.value = StartServiceData(serviceData, previousState) } } else { showFullscreenErrorWithDelay() @@ -290,9 +290,8 @@ class SiteProgressViewModel @Inject constructor( } } - data class SitePreviewStartServiceData( + data class StartServiceData( val serviceData: SiteCreationServiceData, val previousState: SiteCreationServiceState? ) - } From ff60dd5cf9c8fc18ae16f1b2d01afce55cc62942 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 15:42:32 +0100 Subject: [PATCH 039/169] Update: add fade-in transition to the preview fragment --- .../ui/sitecreation/SiteCreationActivity.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 75a9bfec39b1..4930a438aec4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -238,7 +238,7 @@ class SiteCreationActivity : LocaleAwareActivity(), PROGRESS -> SiteCreationProgressFragment.newInstance(target.wizardState) SITE_PREVIEW -> SiteCreationPreviewFragment.newInstance(screenTitle, target.wizardState, mainViewModel.result) } - slideInFragment(fragment, target.wizardStep.toString()) + slideInFragment(fragment, target.wizardStep.toString(), target.wizardStep != SITE_PREVIEW) } private fun getScreenTitle(step: SiteCreationStep): String { @@ -253,14 +253,20 @@ class SiteCreationActivity : LocaleAwareActivity(), } } - private fun slideInFragment(fragment: Fragment, tag: String) { + private fun slideInFragment(fragment: Fragment, tag: String, animate: Boolean = true) { val fragmentTransaction = supportFragmentManager.beginTransaction() if (supportFragmentManager.findFragmentById(R.id.fragment_container) != null) { // add to back stack and animate all screen except of the first one - fragmentTransaction.addToBackStack(null).setCustomAnimations( - R.anim.activity_slide_in_from_right, R.anim.activity_slide_out_to_left, - R.anim.activity_slide_in_from_left, R.anim.activity_slide_out_to_right - ) + fragmentTransaction.addToBackStack(null).apply { + if (animate) { + setCustomAnimations( + R.anim.activity_slide_in_from_right, R.anim.activity_slide_out_to_left, + R.anim.activity_slide_in_from_left, R.anim.activity_slide_out_to_right + ) + } else { + setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) + } + } } fragmentTransaction.replace(R.id.fragment_container, fragment, tag) fragmentTransaction.commit() From cdeba934a0d40c07f1ce207fd6eefa993f990160 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 15:45:17 +0100 Subject: [PATCH 040/169] Refactor: rename `slideInFragment` to `showFragment` with `slideIn` bool --- .../android/ui/sitecreation/SiteCreationActivity.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 4930a438aec4..63276ea08634 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -188,7 +188,7 @@ class SiteCreationActivity : LocaleAwareActivity(), mainViewModel.showJetpackOverlay.observeEvent(this) { if (mainViewModel.siteCreationDisabled) - slideInFragment(fragment, JetpackFeatureFullScreenOverlayFragment.TAG) + showFragment(fragment, JetpackFeatureFullScreenOverlayFragment.TAG) else fragment.show(supportFragmentManager, JetpackFeatureFullScreenOverlayFragment.TAG) } } @@ -238,7 +238,7 @@ class SiteCreationActivity : LocaleAwareActivity(), PROGRESS -> SiteCreationProgressFragment.newInstance(target.wizardState) SITE_PREVIEW -> SiteCreationPreviewFragment.newInstance(screenTitle, target.wizardState, mainViewModel.result) } - slideInFragment(fragment, target.wizardStep.toString(), target.wizardStep != SITE_PREVIEW) + showFragment(fragment, target.wizardStep.toString(), target.wizardStep != SITE_PREVIEW) } private fun getScreenTitle(step: SiteCreationStep): String { @@ -253,12 +253,12 @@ class SiteCreationActivity : LocaleAwareActivity(), } } - private fun slideInFragment(fragment: Fragment, tag: String, animate: Boolean = true) { + private fun showFragment(fragment: Fragment, tag: String, slideIn: Boolean = true) { val fragmentTransaction = supportFragmentManager.beginTransaction() if (supportFragmentManager.findFragmentById(R.id.fragment_container) != null) { // add to back stack and animate all screen except of the first one fragmentTransaction.addToBackStack(null).apply { - if (animate) { + if (slideIn) { setCustomAnimations( R.anim.activity_slide_in_from_right, R.anim.activity_slide_out_to_left, R.anim.activity_slide_in_from_left, R.anim.activity_slide_out_to_right From 9fbf07836bbe8665e042310bbc4fbc27d4b83fc2 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 15:51:49 +0100 Subject: [PATCH 041/169] Test: fix references to CreateSiteState --- .../android/ui/sitecreation/SiteCreationMainVMTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 2f72f5999ad2..48f94b2048b5 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -32,10 +32,10 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.domains.DomainModel +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState.SiteCreationCompleted import org.wordpress.android.ui.sitecreation.usecases.FetchHomePageLayoutsUseCase import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.util.config.SiteCreationDomainPurchasingFeatureConfig @@ -140,7 +140,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun wizardFinishedInvokedOnSitePreviewCompleted() { - val state = SiteCreationCompleted(LOCAL_SITE_ID, false) + val state = SiteCreationCompleted(LOCAL_SITE_ID, false, DOMAIN.domainName) viewModel.onProgressOrPreviewFinished(state) val captor = ArgumentCaptor.forClass(CreateSiteState::class.java) @@ -192,7 +192,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun flowExitedOnBackPressedWhenLastStepAndSiteCreationCompleted() { whenever(wizardManager.isLastStep()).thenReturn(true) - viewModel.onSiteCreationCompleted() + viewModel.onSiteCreationCompleted(mock()) viewModel.onBackPressed() verify(wizardExitedObserver).onChanged(anyOrNull()) } From 303b241403f3a406e585290550dc9e93e7b1f680 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 18:37:14 +0100 Subject: [PATCH 042/169] Test: new logic in main view-model --- .../ui/sitecreation/SiteCreationActivity.kt | 6 ++++- .../ui/sitecreation/SiteCreationMainVM.kt | 5 ++-- .../ui/sitecreation/SiteCreationMainVMTest.kt | 24 +++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 63276ea08634..24c07ad3c047 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -236,7 +236,11 @@ class SiteCreationActivity : LocaleAwareActivity(), } DOMAINS -> SiteCreationDomainsFragment.newInstance(screenTitle) PROGRESS -> SiteCreationProgressFragment.newInstance(target.wizardState) - SITE_PREVIEW -> SiteCreationPreviewFragment.newInstance(screenTitle, target.wizardState, mainViewModel.result) + SITE_PREVIEW -> SiteCreationPreviewFragment.newInstance( + screenTitle, + target.wizardState, + mainViewModel.createSiteResult, + ) } showFragment(fragment, target.wizardStep.toString(), target.wizardStep != SITE_PREVIEW) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 674bb4a399b4..4d8f6584f870 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -25,6 +25,7 @@ import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.misc.CreateSiteState +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated import org.wordpress.android.ui.sitecreation.usecases.FetchHomePageLayoutsUseCase import org.wordpress.android.ui.utils.UiString.UiStringRes import org.wordpress.android.util.AppLog @@ -84,7 +85,7 @@ class SiteCreationMainVM @Inject constructor( private var siteCreationCompleted = false private lateinit var siteCreationState: SiteCreationState - lateinit var result: CreateSiteState + var createSiteResult: CreateSiteState = SiteNotCreated internal var preloadingJob: Job? = null @@ -252,7 +253,7 @@ class SiteCreationMainVM @Inject constructor( } fun onSiteCreationCompleted(state: CreateSiteState) { - result = state + createSiteResult = state siteCreationCompleted = true wizardManager.showNextStep() } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 48f94b2048b5..f60f2eac8166 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -34,6 +34,7 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.CreateSiteState import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.usecases.FetchHomePageLayoutsUseCase @@ -329,6 +330,29 @@ class SiteCreationMainVMTest : BaseUnitTest() { verify(tracker).trackSiteCreationDomainPurchasingExperimentVariation(isA()) } + @Test + fun `initial createSiteResult is SiteNotCreated`() { + assertThat(viewModel.createSiteResult).isEqualTo(SiteNotCreated) + } + + @Test + fun `createSiteResult is updated by onSiteCreationCompleted`() { + val expectedState = SiteCreationCompleted(LOCAL_SITE_ID, false, DOMAIN.domainName) + + viewModel.onSiteCreationCompleted(expectedState) + + assertThat(viewModel.createSiteResult).isEqualTo(expectedState) + } + + @Test + fun `next step is shown by onSiteCreationCompleted`() { + val expectedState = SiteCreationCompleted(LOCAL_SITE_ID, false, DOMAIN.domainName) + + viewModel.onSiteCreationCompleted(expectedState) + + verify(wizardManager).showNextStep() + } + private fun currentWizardState(vm: SiteCreationMainVM) = vm.navigationTargetObservable.lastEvent!!.wizardState From f72cb82dd3162fa612c4053b9842ab28a76dbdc2 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 18:38:59 +0100 Subject: [PATCH 043/169] Refactor: remove unused `SitePreviewStartServiceData` --- .../ui/sitecreation/previews/SitePreviewViewModel.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 2600afd0dc9b..0cea2862ab9a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -17,8 +17,6 @@ import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewLoadingShimmerState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewWebErrorUiState -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceData -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState import org.wordpress.android.ui.sitecreation.usecases.isWordPressComSubDomain import org.wordpress.android.util.AppLog import org.wordpress.android.util.AppLog.T @@ -175,9 +173,4 @@ class SitePreviewViewModel @Inject constructor( val domainIndices: Pair, val subDomainIndices: Pair ) - - data class SitePreviewStartServiceData( - val serviceData: SiteCreationServiceData, - val previousState: SiteCreationServiceState? - ) } From c47dcd09683e3d87eee69d0d83b0a14b08444661 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 18:43:04 +0100 Subject: [PATCH 044/169] Test: clean up preview unit tests after split --- .../previews/SitePreviewViewModelTest.kt | 293 +----------------- 1 file changed, 9 insertions(+), 284 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index 818f8b1b33ef..7b97afcec82c 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -1,76 +1,36 @@ package org.wordpress.android.ui.sitecreation.previews -import android.os.Bundle import androidx.lifecycle.Observer -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceTimeBy -import kotlinx.coroutines.test.advanceUntilIdle import org.assertj.core.api.Assertions.assertThat import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.eq -import org.mockito.kotlin.notNull -import org.mockito.kotlin.verify +import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest -import org.wordpress.android.fluxc.Dispatcher -import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.fluxc.store.SiteStore -import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged -import org.wordpress.android.fluxc.store.SiteStore.SiteError -import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType.GENERIC_ERROR import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.domains.DomainModel +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState.SiteCreationCompleted -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState.SiteNotCreated -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.CreateSiteState.SiteNotInLocalDb -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewStartServiceData import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewFullscreenErrorUiState.SitePreviewConnectionErrorUiState -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewFullscreenErrorUiState.SitePreviewGenericErrorUiState -import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewFullscreenProgressUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewWebErrorUiState -import org.wordpress.android.ui.sitecreation.services.FetchWpComSiteUseCase -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.FAILURE -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.SUCCESS import org.wordpress.android.ui.sitecreation.theme.defaultTemplateSlug -import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.util.UrlUtilsWrapper private const val SUB_DOMAIN = "test" private const val URL = "$SUB_DOMAIN.wordpress.com" private val DOMAIN = DomainModel(URL, true, "", 1) -private const val REMOTE_SITE_ID = 1L -private const val LOCAL_SITE_ID = 2 private val SITE_CREATION_STATE = SiteCreationState(segmentId = 1, siteDesign = defaultTemplateSlug, domain = DOMAIN) @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) class SitePreviewViewModelTest : BaseUnitTest() { - @Mock - private lateinit var dispatcher: Dispatcher - - @Mock - private lateinit var siteStore: SiteStore - - @Mock - private lateinit var bundle: Bundle - - @Mock - private lateinit var fetchWpComUseCase: FetchWpComSiteUseCase - - @Mock - private lateinit var networkUtils: NetworkUtilsWrapper @Mock private lateinit var urlUtils: UrlUtilsWrapper @@ -81,15 +41,9 @@ class SitePreviewViewModelTest : BaseUnitTest() { @Mock private lateinit var uiStateObserver: Observer - @Mock - private lateinit var startServiceObserver: Observer - @Mock private lateinit var onHelpedClickedObserver: Observer - @Mock - private lateinit var onCancelWizardClickedObserver: Observer - @Mock private lateinit var onOkClickedObserver: Observer @@ -101,137 +55,17 @@ class SitePreviewViewModelTest : BaseUnitTest() { @Before fun setUp() { viewModel = SitePreviewViewModel( - dispatcher, - siteStore, - fetchWpComUseCase, - networkUtils, urlUtils, tracker, testDispatcher(), testDispatcher() ) viewModel.uiState.observeForever(uiStateObserver) - viewModel.startCreateSiteService.observeForever(startServiceObserver) viewModel.onHelpClicked.observeForever(onHelpedClickedObserver) - viewModel.onCancelWizardClicked.observeForever(onCancelWizardClickedObserver) viewModel.onOkButtonClicked.observeForever(onOkClickedObserver) viewModel.preloadPreview.observeForever(preloadPreviewObserver) - whenever(networkUtils.isNetworkAvailable()).thenReturn(true) whenever(urlUtils.extractSubDomain(URL)).thenReturn(SUB_DOMAIN) whenever(urlUtils.addUrlSchemeIfNeeded(URL, true)).thenReturn(URL) - whenever(urlUtils.removeScheme(URL)).thenReturn(URL) - whenever(siteStore.getSiteBySiteId(REMOTE_SITE_ID)).thenReturn(createLocalDbSiteModelId()) - } - - private fun testWithSuccessResponse(block: suspend CoroutineScope.() -> T) { - test { - whenever(fetchWpComUseCase.fetchSiteWithRetry(REMOTE_SITE_ID)) - .thenReturn(OnSiteChanged(1)) - block() - } - } - - private fun testWithErrorResponse(block: suspend CoroutineScope.() -> T) { - test { - val onSiteChanged = OnSiteChanged(0) - onSiteChanged.error = SiteError(GENERIC_ERROR) - whenever(fetchWpComUseCase.fetchSiteWithRetry(REMOTE_SITE_ID)) - .thenReturn(onSiteChanged) - block() - } - } - - @Test - fun `progress shown on start`() = test { - initViewModel() - - assertThat(viewModel.uiState.value).isInstanceOf(SitePreviewFullscreenProgressUiState::class.java) - viewModel.onSiteCreationServiceStateUpdated(createServiceSuccessState()) // complete flow - } - - @Test - @Ignore("This test runs indefinitely without completing due to the way it is structured to test the animate field.") - fun `ProgressUiState's animate field is false only for first emitted event`() = test { - initViewModel() - assertThat((viewModel.uiState.value as SitePreviewFullscreenProgressUiState).animate).isFalse() - - (1..100).forEach { - advanceTimeBy(LOADING_STATE_TEXT_ANIMATION_DELAY) - assertThat((viewModel.uiState.value as SitePreviewFullscreenProgressUiState).animate).isTrue() - } - } - - @Test - @Ignore("This test runs indefinitely without completing due to the way it is structured to test the loading state.") - fun `ProgressUiState's text changes every LOADING_STATE_TEXT_ANIMATION_DELAY seconds`() = test { - initViewModel() - viewModel.onSiteCreationServiceStateUpdated(createServiceSuccessState()) // complete flow - - (1..100).forEach { - val lastTextId = (viewModel.uiState.value as SitePreviewFullscreenProgressUiState).loadingTextResId - advanceTimeBy(LOADING_STATE_TEXT_ANIMATION_DELAY) - assertThat((viewModel.uiState.value as SitePreviewFullscreenProgressUiState).loadingTextResId) - .isNotEqualTo(lastTextId) - } - } - - @Test - fun `service started on start`() = test { - initViewModel() - - assertThat(viewModel.startCreateSiteService.value).isNotNull - viewModel.onSiteCreationServiceStateUpdated(createServiceSuccessState()) // complete flow - } - - @Test - fun `error shown on start when internet access not available`() = test { - whenever(networkUtils.isNetworkAvailable()).thenReturn(false) - initViewModel() - advanceUntilIdle() // skip delays - assertThat(viewModel.uiState.value).isInstanceOf(SitePreviewConnectionErrorUiState::class.java) - } - - @Test - fun `error shown on service failure`() { - initViewModel() - viewModel.onSiteCreationServiceStateUpdated(createServiceFailureState()) - assertThat(viewModel.uiState.value).isInstanceOf(SitePreviewGenericErrorUiState::class.java) - } - - @Test - fun `displaying error screen cancels the progress animation job`() = test { - initViewModel() - viewModel.onSiteCreationServiceStateUpdated(createServiceFailureState()) - (1..100).forEach { - advanceTimeBy(LOADING_STATE_TEXT_ANIMATION_DELAY) - assertThat(viewModel.uiState.value).isInstanceOf(SitePreviewGenericErrorUiState::class.java) - } - } - - @Test - fun `service started on retry`() { - initViewModel() - viewModel.onSiteCreationServiceStateUpdated(createServiceFailureState()) - viewModel.retry() - assertThat(viewModel.startCreateSiteService.value).isNotNull - } - - @Test - fun `on Help click is propagated`() { - viewModel.onHelpClicked() - verify(onHelpedClickedObserver).onChanged(null) - } - - @Test - fun `on WizardCanceled click is propagated`() { - viewModel.onCancelWizardClicked() - assertThat(viewModel.onCancelWizardClicked.value).isEqualTo(SiteNotCreated) - } - - @Test - fun `on OK click is propagated`() { - viewModel.onOkButtonClicked() - assertThat(viewModel.onOkButtonClicked.value).isEqualTo(SiteNotCreated) } @Test @@ -258,126 +92,17 @@ class SitePreviewViewModelTest : BaseUnitTest() { assertThat(viewModel.uiState.value).isInstanceOf(SitePreviewWebErrorUiState::class.java) } - @Test - fun `start pre-loading WebView on service success`() = testWithSuccessResponse { - initViewModel() - viewModel.onSiteCreationServiceStateUpdated(createServiceSuccessState()) - assertThat(viewModel.preloadPreview.value).isEqualTo(URL) - } - - @Test - fun `fetch newly created SiteModel on service success`() = testWithSuccessResponse { - initViewModel() - viewModel.onSiteCreationServiceStateUpdated(createServiceSuccessState()) - verify(fetchWpComUseCase).fetchSiteWithRetry(REMOTE_SITE_ID) - } - - @Test - fun `CreateSiteState is SiteNotCreated on init`() { - initViewModel() - assertThat(getCreateSiteState()).isEqualTo(SiteNotCreated) - } - - @Test - fun `CreateSiteState is SiteCreationCompleted on fetchFromRemote success`() = testWithSuccessResponse { - initViewModel() - viewModel.onSiteCreationServiceStateUpdated(createServiceSuccessState()) - assertThat(getCreateSiteState()).isEqualTo(SiteCreationCompleted(LOCAL_SITE_ID, false)) - } - - @Test - fun `CreateSiteState is NotInLocalDb on fetchFromRemote failure`() = testWithErrorResponse { - initViewModel() - viewModel.onSiteCreationServiceStateUpdated(createServiceSuccessState()) - assertThat(getCreateSiteState()).isEqualTo(SiteNotInLocalDb(REMOTE_SITE_ID, false)) - } - - @Test - fun `CreateSiteState is saved into bundle`() { - initViewModel(null) - - viewModel.writeToBundle(bundle) - - verify(bundle).putParcelable(eq(KEY_CREATE_SITE_STATE), notNull()) - } - - @Test - fun `show fullscreen progress when restoring from SiteNotCreated state`() = testWithSuccessResponse { - whenever(bundle.getParcelable(KEY_CREATE_SITE_STATE)).thenReturn(SiteNotCreated) - initViewModel(bundle) - - assertThat(viewModel.uiState.value).isInstanceOf(SitePreviewFullscreenProgressUiState::class.java) - viewModel.onSiteCreationServiceStateUpdated(createServiceSuccessState()) // complete flow - } - - @Test - fun `service started when restoring from SiteNotCreated state`() { - whenever(bundle.getParcelable(KEY_CREATE_SITE_STATE)).thenReturn(SiteNotCreated) - initViewModel(bundle) - - assertThat(viewModel.startCreateSiteService.value).isNotNull - } - - @Test - fun `show fullscreen progress when restoring from SiteNotInLocalDb state`() = testWithSuccessResponse { - whenever(bundle.getParcelable(KEY_CREATE_SITE_STATE)).thenReturn(SiteNotCreated) - initViewModel(bundle) - - assertThat(viewModel.uiState.value).isInstanceOf(SitePreviewFullscreenProgressUiState::class.java) - viewModel.onSiteCreationServiceStateUpdated(createServiceSuccessState()) // complete flow - } - - @Test - fun `start pre-loading WebView when restoring from SiteNotInLocalDb state`() = testWithSuccessResponse { - whenever(bundle.getParcelable(KEY_CREATE_SITE_STATE)) - .thenReturn(SiteNotInLocalDb(REMOTE_SITE_ID, false)) - initViewModel(bundle) - - assertThat(viewModel.uiState.value).isInstanceOf(SitePreviewFullscreenProgressUiState::class.java) - } - - @Test - fun `fetch newly created SiteModel when restoring from SiteNotInLocalDb state`() = testWithSuccessResponse { - whenever(bundle.getParcelable(KEY_CREATE_SITE_STATE)) - .thenReturn(SiteNotInLocalDb(REMOTE_SITE_ID, false)) - initViewModel(bundle) - - verify(fetchWpComUseCase).fetchSiteWithRetry(REMOTE_SITE_ID) - } - @Test fun `start pre-loading WebView when restoring from SiteCreationCompleted state`() { - whenever(bundle.getParcelable(KEY_CREATE_SITE_STATE)) - .thenReturn(SiteCreationCompleted(LOCAL_SITE_ID, false)) - initViewModel(bundle) + initViewModel(createSiteState = SiteCreationCompleted(2, false, URL)) assertThat(viewModel.preloadPreview.value).isEqualTo(URL) } - private fun initViewModel(savedState: Bundle? = null) { - viewModel.start(SITE_CREATION_STATE, savedState) - } - - private fun createServiceFailureState(): SiteCreationServiceState { - val stateBeforeFailure = SiteCreationServiceState(CREATE_SITE) - return SiteCreationServiceState(FAILURE, stateBeforeFailure) - } - - private fun createServiceSuccessState(): SiteCreationServiceState { - return SiteCreationServiceState(SUCCESS, Pair(REMOTE_SITE_ID, URL)) - } - - private fun createLocalDbSiteModelId(): SiteModel { - val localDbSiteModel = SiteModel() - localDbSiteModel.id = LOCAL_SITE_ID - return localDbSiteModel - } - - /** - * `createSiteState` is a private property -> get its value using `onOkButtonClicked` - */ - private fun getCreateSiteState(): CreateSiteState? { - viewModel.onOkButtonClicked() - return viewModel.onOkButtonClicked.value + private fun initViewModel( + siteCreationState: SiteCreationState = SITE_CREATION_STATE, + createSiteState: CreateSiteState = mock(), + ) { + viewModel.start(siteCreationState, createSiteState) } } From 272e67d869ca6254421429765b34be2d955e0905 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 7 Mar 2023 22:49:26 +0100 Subject: [PATCH 045/169] Refactor: cleanup loading texts loop --- .../ui/sitecreation/progress/SiteProgressViewModel.kt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt index e77f2d42e15d..73f4066976c0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt @@ -231,22 +231,16 @@ class SiteProgressViewModel @Inject constructor( private fun runLoadingAnimationUi() { loadingAnimationJob?.cancel() loadingAnimationJob = launch(mainDispatcher) { - var i = 0 - val listSize = loadingTexts.size - repeat(listSize) { + loadingTexts.forEachIndexed { i, uiString -> updateUiState( SiteProgressLoadingUiState( animate = i != 0, // the first text should appear without an animation - loadingTextResId = loadingTexts[i++ % listSize] + loadingTextResId = uiString ) ) delay(LOADING_STATE_TEXT_ANIMATION_DELAY) } - check(createSiteState !is SiteNotCreated) { - "Site should have been created by now." - } - _onSiteCreationCompleted.postValue(createSiteState) } } From 11040f0f27e41f84c2004f5a63535a6d0dbbe051 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 8 Mar 2023 13:26:26 +0100 Subject: [PATCH 046/169] Refactor: remove braces from if statements to cancel loading job --- .../ui/sitecreation/progress/SiteProgressViewModel.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt index 73f4066976c0..7d2afbf7b2e0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt @@ -246,16 +246,12 @@ class SiteProgressViewModel @Inject constructor( } private fun updateUiState(uiState: SiteProgressUiState) { - if (uiState !is SiteProgressLoadingUiState) { - loadingAnimationJob?.cancel() - } + if (uiState !is SiteProgressLoadingUiState) loadingAnimationJob?.cancel() _uiState.value = uiState } private fun updateUiStateAsync(uiState: SiteProgressUiState) { - if (uiState !is SiteProgressLoadingUiState) { - loadingAnimationJob?.cancel() - } + if (uiState !is SiteProgressLoadingUiState) loadingAnimationJob?.cancel() _uiState.postValue(uiState) } From 7a9ee5a1e6c33ed3123b8afc503378d4b6f9b709 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 8 Mar 2023 13:26:40 +0100 Subject: [PATCH 047/169] Refactor: replace if else with takeIf --- .../android/ui/sitecreation/progress/SiteProgressViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt index 7d2afbf7b2e0..3593fac3124b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt @@ -142,7 +142,7 @@ class SiteProgressViewModel @Inject constructor( siteCreationState.apply { // A non-null [segmentId] may invalidate the [siteDesign] selection // https://github.com/wordpress-mobile/WordPress-Android/issues/13749 - val segmentIdentifier = if (siteDesign != null) null else segmentId + val segmentIdentifier = segmentId.takeIf { siteDesign != null } val serviceData = SiteCreationServiceData( segmentIdentifier, siteDesign, From 23b2eaec115b0ec926a58cfbbf7101a302069d1e Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 8 Mar 2023 13:26:53 +0100 Subject: [PATCH 048/169] Refactor: reorder imports --- .../ui/sitecreation/progress/SiteProgressViewModel.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt index 3593fac3124b..0d4cc83ee682 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt @@ -19,12 +19,12 @@ import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.CreateSiteState -import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR -import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.UNKNOWN -import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocalDb +import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR +import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.UNKNOWN +import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState.SiteProgressConnectionErrorUiState import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState.SiteProgressGenericErrorUiState import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressLoadingUiState From edae4f16988b428b9a047983fac092d91bcfd28e Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Fri, 10 Mar 2023 23:30:37 +0200 Subject: [PATCH 049/169] Update: emit completion only when site creation succeeds --- .../ui/sitecreation/progress/SiteProgressViewModel.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt index 0d4cc83ee682..6b69098de11c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt @@ -92,8 +92,8 @@ class SiteProgressViewModel @Inject constructor( private val _onCancelWizardClicked = SingleLiveEvent() val onCancelWizardClicked: LiveData = _onCancelWizardClicked - private val _onSiteCreationCompleted = SingleLiveEvent() - val onSiteCreationCompleted: LiveData = _onSiteCreationCompleted + private val _onSiteCreationCompleted = SingleLiveEvent() + val onSiteCreationCompleted: LiveData = _onSiteCreationCompleted init { dispatcher.register(fetchWpComSiteUseCase) @@ -197,8 +197,6 @@ class SiteProgressViewModel @Inject constructor( createSiteState = SiteNotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) launch { createSiteState = fetchNewlyCreatedSiteModel(remoteSiteId) - // move @ end of animation with if - // _onSiteCreationCompleted.postValue(createSiteState) } } FAILURE -> { @@ -240,8 +238,7 @@ class SiteProgressViewModel @Inject constructor( ) delay(LOADING_STATE_TEXT_ANIMATION_DELAY) } - - _onSiteCreationCompleted.postValue(createSiteState) + (createSiteState as? SiteCreationCompleted)?.let { _onSiteCreationCompleted.postValue(it) } } } From 335ca3b4b3141b7411c25afce1de2517e3538034 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Fri, 10 Mar 2023 23:31:37 +0200 Subject: [PATCH 050/169] Test: add unit tests for the splitted and updated logic in the progress vm --- .../progress/SiteProgressViewModelTest.kt | 244 ++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt new file mode 100644 index 000000000000..f0837c2d4715 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -0,0 +1,244 @@ +package org.wordpress.android.ui.sitecreation.progress + +import android.os.Bundle +import androidx.lifecycle.Observer +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.advanceTimeBy +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.atMost +import org.mockito.kotlin.check +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.isNull +import org.mockito.kotlin.mock +import org.mockito.kotlin.notNull +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.wordpress.android.BaseUnitTest +import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.store.SiteStore +import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged +import org.wordpress.android.ui.sitecreation.SiteCreationState +import org.wordpress.android.ui.sitecreation.domains.DomainModel +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated +import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocalDb +import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker +import org.wordpress.android.ui.sitecreation.previews.KEY_CREATE_SITE_STATE +import org.wordpress.android.ui.sitecreation.previews.LOADING_STATE_TEXT_ANIMATION_DELAY +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState.SiteProgressConnectionErrorUiState +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState.SiteProgressGenericErrorUiState +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressLoadingUiState +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.StartServiceData +import org.wordpress.android.ui.sitecreation.services.FetchWpComSiteUseCase +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.FAILURE +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.SUCCESS +import org.wordpress.android.ui.sitecreation.theme.defaultTemplateSlug +import org.wordpress.android.util.NetworkUtilsWrapper +import org.wordpress.android.util.UrlUtilsWrapper +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertNotNull + +private const val URL = "test.wordpress.com" +private const val REMOTE_SITE_ID = 1L +private val SITE_NOT_IN_LOCAL_DB = SiteNotInLocalDb(REMOTE_SITE_ID, false) +private val SERVICE_STATE_SUCCESS = SiteCreationServiceState(SUCCESS, Pair(REMOTE_SITE_ID, URL)) +private val SERVICE_STATE_ERROR = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) +private val RESPONSE_SUCCESS = OnSiteChanged(1) + +@ExperimentalCoroutinesApi +@RunWith(MockitoJUnitRunner::class) +class SiteProgressViewModelTest : BaseUnitTest() { + private var dispatcher = mock() + private var siteStore = mock() + private var fetchWpComSiteUseCase = mock() + private var networkUtils = mock() + private var urlUtils = mock() + private var tracker = mock() + + private val uiStateObserver = mock>() + private val startServiceObserver = mock>() + private val onHelpedClickedObserver = mock>() + private val onCancelWizardClickedObserver = mock>() + private val onSiteCreationCompletedObserver = mock>() + + private val bundle = mock() + + private lateinit var viewModel: SiteProgressViewModel + + @Before + fun setUp() { + viewModel = SiteProgressViewModel( + dispatcher = dispatcher, + siteStore = siteStore, + fetchWpComSiteUseCase = fetchWpComSiteUseCase, + networkUtils = networkUtils, + urlUtils = urlUtils, + tracker = tracker, + bgDispatcher = testDispatcher(), + mainDispatcher = testDispatcher() + ) + viewModel.uiState.observeForever(uiStateObserver) + viewModel.startCreateSiteService.observeForever(startServiceObserver) + viewModel.onHelpClicked.observeForever(onHelpedClickedObserver) + viewModel.onCancelWizardClicked.observeForever(onCancelWizardClickedObserver) + viewModel.onSiteCreationCompleted.observeForever(onSiteCreationCompletedObserver) + + whenever(networkUtils.isNetworkAvailable()).thenReturn(true) + whenever(urlUtils.removeScheme(URL)).thenReturn(URL) + whenever(siteStore.getSiteBySiteId(REMOTE_SITE_ID)).thenReturn(SiteModel().apply { id = 1; url = URL }) + } + + @Test + fun `on start shows progress`() = test { + startViewModel() + assertIs(viewModel.uiState.value) + } + + @Test + fun `on start shows progress when restoring SiteNotCreated`() = testWithSuccessResponse { + startViewModel(SiteNotCreated) + assertIs(viewModel.uiState.value) + } + + @Test + fun `on start shows progress when restoring SiteNotInLocalDb`() = testWithSuccessResponse { + startViewModel(SITE_NOT_IN_LOCAL_DB) + assertIs(viewModel.uiState.value) + } + + @Test + fun `on start emits service event`() = test { + startViewModel() + assertNotNull(viewModel.startCreateSiteService.value) + } + + @Test + fun `on start emits service event when restoring from SiteNotCreated`() { + startViewModel(SiteNotCreated) + assertNotNull(viewModel.startCreateSiteService.value) + } + + @Test + fun `on start shows error when network is not available`() = test { + whenever(networkUtils.isNetworkAvailable()).thenReturn(false) + startViewModel() + advanceUntilIdle() + assertIs(viewModel.uiState.value) + } + + @Test + fun `on start fetches site by remote id when restoring SiteNotInLocalDb`() = test { + startViewModel(SITE_NOT_IN_LOCAL_DB) + verify(fetchWpComSiteUseCase).fetchSiteWithRetry(REMOTE_SITE_ID) + } + + @Test + fun `on start shows first loading text without animation`() = test { + startViewModel() + verify(uiStateObserver).onChanged(check { !it.animate }) + } + + @Test + fun `on start changes the loading text with delayed animation`() = test { + startViewModel() + advanceTimeBy(LOADING_STATE_TEXT_ANIMATION_DELAY) + verify(uiStateObserver).onChanged(check { it.animate }) + } + + @Test + fun `on start changes the loading text with delayed animation only 4 times`() = test { + startViewModel() + val captor = argumentCaptor() + (1..9).forEach { + verify(uiStateObserver, atMost(it)).onChanged(captor.capture()) + advanceTimeBy(LOADING_STATE_TEXT_ANIMATION_DELAY) + } + assertThat(captor.allValues.distinctBy { it.loadingTextResId }).hasSize(4) + } + + @Test + fun `on retry click emits service event with the previous result`() { + startViewModel() + viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_ERROR) + viewModel.retry() + assertEquals(viewModel.startCreateSiteService.value?.previousState, SERVICE_STATE_ERROR.payload) + } + + @Test + fun `on help click is propagate`() { + startViewModel() + viewModel.onHelpClicked() + verify(onHelpedClickedObserver).onChanged(isNull()) + } + + @Test + fun `on cancel wizard click is propagated`() { + viewModel.onCancelWizardClicked() + assertEquals(viewModel.onCancelWizardClicked.value, SiteNotCreated) + } + + @Test + fun `on write to bundle saves the state`() { + startViewModel() + viewModel.writeToBundle(bundle) + verify(bundle).putParcelable(eq(KEY_CREATE_SITE_STATE), notNull()) + } + + @Test + fun `on service success fetches site by remote id`() = testWithSuccessResponse { + startViewModel() + viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_SUCCESS) + verify(fetchWpComSiteUseCase).fetchSiteWithRetry(REMOTE_SITE_ID) + } + + @Test + fun `on service success will emit completion event after loading texts animation`() = testWithSuccessResponse { + startViewModel() + viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_SUCCESS) + advanceUntilIdle() + verify(onSiteCreationCompletedObserver).onChanged(any()) + } + + @Test + fun `on service failure shows error`() { + startViewModel() + viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_ERROR) + assertIs(viewModel.uiState.value) + } + + // region Helpers + + private fun testWithSuccessResponse(block: suspend CoroutineScope.() -> Unit) = test { + whenever(fetchWpComSiteUseCase.fetchSiteWithRetry(REMOTE_SITE_ID)).thenReturn(RESPONSE_SUCCESS) + block() + } + + private fun startViewModel(restoredState: CreateSiteState? = null) { + viewModel.start( + SiteCreationState( + segmentId = 1, + siteDesign = defaultTemplateSlug, + domain = DomainModel(URL, true, "", 1) + ), + bundle.apply { + restoredState?.let { whenever(getParcelable(KEY_CREATE_SITE_STATE)) doReturn it } + } + ) + } + + // endregion +} From 1d73cdfa6a9055d6d6e06b37335f8192ffed17f3 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 15:20:17 +0200 Subject: [PATCH 051/169] Revert: emit completion only when site creation succeeds --- .../progress/SiteProgressViewModel.kt | 6 ++-- .../progress/SiteProgressViewModelTest.kt | 28 +++++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt index 6b69098de11c..3de91ee9a8a4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt @@ -92,8 +92,8 @@ class SiteProgressViewModel @Inject constructor( private val _onCancelWizardClicked = SingleLiveEvent() val onCancelWizardClicked: LiveData = _onCancelWizardClicked - private val _onSiteCreationCompleted = SingleLiveEvent() - val onSiteCreationCompleted: LiveData = _onSiteCreationCompleted + private val _onSiteCreationCompleted = SingleLiveEvent() + val onSiteCreationCompleted: LiveData = _onSiteCreationCompleted init { dispatcher.register(fetchWpComSiteUseCase) @@ -238,7 +238,7 @@ class SiteProgressViewModel @Inject constructor( ) delay(LOADING_STATE_TEXT_ANIMATION_DELAY) } - (createSiteState as? SiteCreationCompleted)?.let { _onSiteCreationCompleted.postValue(it) } + _onSiteCreationCompleted.postValue(createSiteState) } } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt index f0837c2d4715..febde05ea9e3 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -26,10 +26,11 @@ import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged +import org.wordpress.android.fluxc.store.SiteStore.SiteError +import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.CreateSiteState -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocalDb import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker @@ -57,7 +58,8 @@ private const val REMOTE_SITE_ID = 1L private val SITE_NOT_IN_LOCAL_DB = SiteNotInLocalDb(REMOTE_SITE_ID, false) private val SERVICE_STATE_SUCCESS = SiteCreationServiceState(SUCCESS, Pair(REMOTE_SITE_ID, URL)) private val SERVICE_STATE_ERROR = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) -private val RESPONSE_SUCCESS = OnSiteChanged(1) +private val errorResponse = OnSiteChanged(1) +private val successResponse = OnSiteChanged(0).apply { error = SiteError(SiteErrorType.GENERIC_ERROR) } @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) @@ -73,7 +75,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { private val startServiceObserver = mock>() private val onHelpedClickedObserver = mock>() private val onCancelWizardClickedObserver = mock>() - private val onSiteCreationCompletedObserver = mock>() + private val onSiteCreationCompletedObserver = mock>() private val bundle = mock() @@ -109,13 +111,13 @@ class SiteProgressViewModelTest : BaseUnitTest() { } @Test - fun `on start shows progress when restoring SiteNotCreated`() = testWithSuccessResponse { + fun `on start shows progress when restoring SiteNotCreated`() = testWith(successResponse) { startViewModel(SiteNotCreated) assertIs(viewModel.uiState.value) } @Test - fun `on start shows progress when restoring SiteNotInLocalDb`() = testWithSuccessResponse { + fun `on start shows progress when restoring SiteNotInLocalDb`() = testWith(errorResponse) { startViewModel(SITE_NOT_IN_LOCAL_DB) assertIs(viewModel.uiState.value) } @@ -199,14 +201,22 @@ class SiteProgressViewModelTest : BaseUnitTest() { } @Test - fun `on service success fetches site by remote id`() = testWithSuccessResponse { + fun `on service success fetches site by remote id`() = testWith(successResponse) { startViewModel() viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_SUCCESS) verify(fetchWpComSiteUseCase).fetchSiteWithRetry(REMOTE_SITE_ID) } @Test - fun `on service success will emit completion event after loading texts animation`() = testWithSuccessResponse { + fun `on service success will emit completion event when animations end`() = testWith(successResponse) { + startViewModel() + viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_SUCCESS) + advanceUntilIdle() + verify(onSiteCreationCompletedObserver).onChanged(any()) + } + + @Test + fun `on service failure will emit completion event when animations end`() = testWith(errorResponse) { startViewModel() viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_SUCCESS) advanceUntilIdle() @@ -222,8 +232,8 @@ class SiteProgressViewModelTest : BaseUnitTest() { // region Helpers - private fun testWithSuccessResponse(block: suspend CoroutineScope.() -> Unit) = test { - whenever(fetchWpComSiteUseCase.fetchSiteWithRetry(REMOTE_SITE_ID)).thenReturn(RESPONSE_SUCCESS) + private fun testWith(response: OnSiteChanged, block: suspend CoroutineScope.() -> Unit) = test { + whenever(fetchWpComSiteUseCase.fetchSiteWithRetry(REMOTE_SITE_ID)).thenReturn(response) block() } From 74415596ae024d86728c0e258411fe4edda9c905 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 15:25:44 +0200 Subject: [PATCH 052/169] Refactor: rename local test val's to camelCase --- .../progress/SiteProgressViewModelTest.kt | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt index febde05ea9e3..a6eca7309873 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -53,11 +53,11 @@ import kotlin.test.assertEquals import kotlin.test.assertIs import kotlin.test.assertNotNull -private const val URL = "test.wordpress.com" -private const val REMOTE_SITE_ID = 1L -private val SITE_NOT_IN_LOCAL_DB = SiteNotInLocalDb(REMOTE_SITE_ID, false) -private val SERVICE_STATE_SUCCESS = SiteCreationServiceState(SUCCESS, Pair(REMOTE_SITE_ID, URL)) -private val SERVICE_STATE_ERROR = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) +private const val url = "test.wordpress.com" +private const val siteRemoteId = 1L +private val siteNotInLocalDb = SiteNotInLocalDb(siteRemoteId, false) +private val successServiceState = SiteCreationServiceState(SUCCESS, Pair(siteRemoteId, url)) +private val errorServiceState = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) private val errorResponse = OnSiteChanged(1) private val successResponse = OnSiteChanged(0).apply { error = SiteError(SiteErrorType.GENERIC_ERROR) } @@ -100,8 +100,8 @@ class SiteProgressViewModelTest : BaseUnitTest() { viewModel.onSiteCreationCompleted.observeForever(onSiteCreationCompletedObserver) whenever(networkUtils.isNetworkAvailable()).thenReturn(true) - whenever(urlUtils.removeScheme(URL)).thenReturn(URL) - whenever(siteStore.getSiteBySiteId(REMOTE_SITE_ID)).thenReturn(SiteModel().apply { id = 1; url = URL }) + whenever(urlUtils.removeScheme(url)).thenReturn(url) + whenever(siteStore.getSiteBySiteId(siteRemoteId)).thenReturn(SiteModel().apply { id = 1; url = url }) } @Test @@ -118,7 +118,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on start shows progress when restoring SiteNotInLocalDb`() = testWith(errorResponse) { - startViewModel(SITE_NOT_IN_LOCAL_DB) + startViewModel(siteNotInLocalDb) assertIs(viewModel.uiState.value) } @@ -144,8 +144,8 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on start fetches site by remote id when restoring SiteNotInLocalDb`() = test { - startViewModel(SITE_NOT_IN_LOCAL_DB) - verify(fetchWpComSiteUseCase).fetchSiteWithRetry(REMOTE_SITE_ID) + startViewModel(siteNotInLocalDb) + verify(fetchWpComSiteUseCase).fetchSiteWithRetry(siteRemoteId) } @Test @@ -175,9 +175,9 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on retry click emits service event with the previous result`() { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_ERROR) + viewModel.onSiteCreationServiceStateUpdated(errorServiceState) viewModel.retry() - assertEquals(viewModel.startCreateSiteService.value?.previousState, SERVICE_STATE_ERROR.payload) + assertEquals(viewModel.startCreateSiteService.value?.previousState, errorServiceState.payload) } @Test @@ -203,14 +203,14 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on service success fetches site by remote id`() = testWith(successResponse) { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_SUCCESS) - verify(fetchWpComSiteUseCase).fetchSiteWithRetry(REMOTE_SITE_ID) + viewModel.onSiteCreationServiceStateUpdated(successServiceState) + verify(fetchWpComSiteUseCase).fetchSiteWithRetry(siteRemoteId) } @Test fun `on service success will emit completion event when animations end`() = testWith(successResponse) { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_SUCCESS) + viewModel.onSiteCreationServiceStateUpdated(successServiceState) advanceUntilIdle() verify(onSiteCreationCompletedObserver).onChanged(any()) } @@ -218,7 +218,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on service failure will emit completion event when animations end`() = testWith(errorResponse) { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_SUCCESS) + viewModel.onSiteCreationServiceStateUpdated(successServiceState) advanceUntilIdle() verify(onSiteCreationCompletedObserver).onChanged(any()) } @@ -226,14 +226,14 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on service failure shows error`() { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(SERVICE_STATE_ERROR) + viewModel.onSiteCreationServiceStateUpdated(errorServiceState) assertIs(viewModel.uiState.value) } // region Helpers private fun testWith(response: OnSiteChanged, block: suspend CoroutineScope.() -> Unit) = test { - whenever(fetchWpComSiteUseCase.fetchSiteWithRetry(REMOTE_SITE_ID)).thenReturn(response) + whenever(fetchWpComSiteUseCase.fetchSiteWithRetry(siteRemoteId)).thenReturn(response) block() } @@ -242,7 +242,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { SiteCreationState( segmentId = 1, siteDesign = defaultTemplateSlug, - domain = DomainModel(URL, true, "", 1) + domain = DomainModel(url, true, "", 1) ), bundle.apply { restoredState?.let { whenever(getParcelable(KEY_CREATE_SITE_STATE)) doReturn it } From cb14b4c27a6ea97a62da1267666f0573a6b474dc Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 15:29:30 +0200 Subject: [PATCH 053/169] Refactor: rename inner ui state classes --- .../progress/SiteCreationProgressFragment.kt | 12 +++++----- .../progress/SiteProgressViewModel.kt | 24 +++++++++---------- .../progress/SiteProgressViewModelTest.kt | 18 +++++++------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt index 00c7955a0ba2..829bef54bc23 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt @@ -18,8 +18,8 @@ import org.wordpress.android.databinding.SiteCreationProgressScreenBinding import org.wordpress.android.ui.accounts.HelpActivity import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressLoadingUiState +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Loading import org.wordpress.android.ui.sitecreation.services.SiteCreationService import org.wordpress.android.ui.utils.UiHelpers import org.wordpress.android.util.AniUtils @@ -86,8 +86,8 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc viewModel.uiState.observe(viewLifecycleOwner) { uiState -> uiState?.run { when (val ui = this@run) { - is SiteProgressLoadingUiState -> siteCreationProgressCreatingSite.updateLoadingLayout(ui) - is SiteProgressErrorUiState -> fullscreenErrorWithRetry.updateErrorLayout(ui) + is Loading -> siteCreationProgressCreatingSite.updateLoadingLayout(ui) + is Error -> fullscreenErrorWithRetry.updateErrorLayout(ui) } siteCreationProgressCreatingSite.progressLayout.isVisible = progressLayoutVisibility fullscreenErrorWithRetry.errorLayout.isVisible = errorLayoutVisibility @@ -125,7 +125,7 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc contactSupport.setOnClickListener { viewModel.onHelpClicked() } } - private fun FullscreenErrorWithRetryBinding.updateErrorLayout(errorUiState: SiteProgressErrorUiState) { + private fun FullscreenErrorWithRetryBinding.updateErrorLayout(errorUiState: Error) { errorUiState.run { uiHelpers.setTextOrHide(errorTitle, titleResId) uiHelpers.setTextOrHide(errorSubtitle, subtitleResId) @@ -135,7 +135,7 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc } private fun SiteCreationProgressCreatingSiteBinding.updateLoadingLayout( - progressUiState: SiteProgressLoadingUiState + progressUiState: Loading ) { progressUiState.apply { val newText = uiHelpers.getTextOfUiString(progressText.context, loadingTextResId) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt index 3de91ee9a8a4..54fba13f1728 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt @@ -25,9 +25,9 @@ import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocal import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.UNKNOWN import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState.SiteProgressConnectionErrorUiState -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState.SiteProgressGenericErrorUiState -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressLoadingUiState +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.ConnectionError +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.GenericError +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Loading import org.wordpress.android.ui.sitecreation.services.FetchWpComSiteUseCase import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceData import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState @@ -173,7 +173,7 @@ class SiteProgressViewModel @Inject constructor( // We show the loading indicator for a bit so the user has some feedback when they press retry delay(CONNECTION_ERROR_DELAY_TO_SHOW_LOADING_STATE) tracker.trackErrorShown(ERROR_CONTEXT, INTERNET_UNAVAILABLE_ERROR) - updateUiState(SiteProgressConnectionErrorUiState) + updateUiState(ConnectionError) } } @@ -206,7 +206,7 @@ class SiteProgressViewModel @Inject constructor( UNKNOWN, "SiteCreation service failed" ) - updateUiStateAsync(SiteProgressGenericErrorUiState) + updateUiStateAsync(GenericError) } } } @@ -231,7 +231,7 @@ class SiteProgressViewModel @Inject constructor( loadingAnimationJob = launch(mainDispatcher) { loadingTexts.forEachIndexed { i, uiString -> updateUiState( - SiteProgressLoadingUiState( + Loading( animate = i != 0, // the first text should appear without an animation loadingTextResId = uiString ) @@ -243,12 +243,12 @@ class SiteProgressViewModel @Inject constructor( } private fun updateUiState(uiState: SiteProgressUiState) { - if (uiState !is SiteProgressLoadingUiState) loadingAnimationJob?.cancel() + if (uiState !is Loading) loadingAnimationJob?.cancel() _uiState.value = uiState } private fun updateUiStateAsync(uiState: SiteProgressUiState) { - if (uiState !is SiteProgressLoadingUiState) loadingAnimationJob?.cancel() + if (uiState !is Loading) loadingAnimationJob?.cancel() _uiState.postValue(uiState) } @@ -256,22 +256,22 @@ class SiteProgressViewModel @Inject constructor( val progressLayoutVisibility: Boolean = false, val errorLayoutVisibility: Boolean = false ) { - data class SiteProgressLoadingUiState(val loadingTextResId: UiString, val animate: Boolean) : + data class Loading(val loadingTextResId: UiString, val animate: Boolean) : SiteProgressUiState(progressLayoutVisibility = true) - sealed class SiteProgressErrorUiState constructor( + sealed class Error constructor( val titleResId: Int, val subtitleResId: Int? = null, val showContactSupport: Boolean = false, val showCancelWizardButton: Boolean = true ) : SiteProgressUiState(errorLayoutVisibility = true) { - object SiteProgressGenericErrorUiState : SiteProgressErrorUiState( + object GenericError : Error( R.string.site_creation_error_generic_title, R.string.site_creation_error_generic_subtitle, showContactSupport = true ) - object SiteProgressConnectionErrorUiState : SiteProgressErrorUiState( + object ConnectionError : Error( R.string.no_network_message ) } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt index a6eca7309873..ea21b01e1f67 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -37,9 +37,9 @@ import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.KEY_CREATE_SITE_STATE import org.wordpress.android.ui.sitecreation.previews.LOADING_STATE_TEXT_ANIMATION_DELAY import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState.SiteProgressConnectionErrorUiState -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressErrorUiState.SiteProgressGenericErrorUiState -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.SiteProgressLoadingUiState +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.ConnectionError +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.GenericError +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Loading import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.StartServiceData import org.wordpress.android.ui.sitecreation.services.FetchWpComSiteUseCase import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState @@ -119,7 +119,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on start shows progress when restoring SiteNotInLocalDb`() = testWith(errorResponse) { startViewModel(siteNotInLocalDb) - assertIs(viewModel.uiState.value) + assertIs(viewModel.uiState.value) } @Test @@ -139,7 +139,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { whenever(networkUtils.isNetworkAvailable()).thenReturn(false) startViewModel() advanceUntilIdle() - assertIs(viewModel.uiState.value) + assertIs(viewModel.uiState.value) } @Test @@ -151,20 +151,20 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on start shows first loading text without animation`() = test { startViewModel() - verify(uiStateObserver).onChanged(check { !it.animate }) + verify(uiStateObserver).onChanged(check { !it.animate }) } @Test fun `on start changes the loading text with delayed animation`() = test { startViewModel() advanceTimeBy(LOADING_STATE_TEXT_ANIMATION_DELAY) - verify(uiStateObserver).onChanged(check { it.animate }) + verify(uiStateObserver).onChanged(check { it.animate }) } @Test fun `on start changes the loading text with delayed animation only 4 times`() = test { startViewModel() - val captor = argumentCaptor() + val captor = argumentCaptor() (1..9).forEach { verify(uiStateObserver, atMost(it)).onChanged(captor.capture()) advanceTimeBy(LOADING_STATE_TEXT_ANIMATION_DELAY) @@ -227,7 +227,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { fun `on service failure shows error`() { startViewModel() viewModel.onSiteCreationServiceStateUpdated(errorServiceState) - assertIs(viewModel.uiState.value) + assertIs(viewModel.uiState.value) } // region Helpers From 37d11cf6208c268849d815243d92056fae6db352 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 15:47:58 +0200 Subject: [PATCH 054/169] Refactor: rename url to siteUrl to fix issue --- .../progress/SiteProgressViewModelTest.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt index ea21b01e1f67..f3ed60c5030e 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -53,13 +53,13 @@ import kotlin.test.assertEquals import kotlin.test.assertIs import kotlin.test.assertNotNull -private const val url = "test.wordpress.com" +private const val siteUrl = "test.wordpress.com" private const val siteRemoteId = 1L private val siteNotInLocalDb = SiteNotInLocalDb(siteRemoteId, false) -private val successServiceState = SiteCreationServiceState(SUCCESS, Pair(siteRemoteId, url)) +private val successServiceState = SiteCreationServiceState(SUCCESS, Pair(siteRemoteId, siteUrl)) private val errorServiceState = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) -private val errorResponse = OnSiteChanged(1) -private val successResponse = OnSiteChanged(0).apply { error = SiteError(SiteErrorType.GENERIC_ERROR) } +private val successResponse = OnSiteChanged(1) +private val errorResponse = OnSiteChanged(0).apply { error = SiteError(SiteErrorType.GENERIC_ERROR) } @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) @@ -100,8 +100,8 @@ class SiteProgressViewModelTest : BaseUnitTest() { viewModel.onSiteCreationCompleted.observeForever(onSiteCreationCompletedObserver) whenever(networkUtils.isNetworkAvailable()).thenReturn(true) - whenever(urlUtils.removeScheme(url)).thenReturn(url) - whenever(siteStore.getSiteBySiteId(siteRemoteId)).thenReturn(SiteModel().apply { id = 1; url = url }) + whenever(urlUtils.removeScheme(siteUrl)).thenReturn(siteUrl) + whenever(siteStore.getSiteBySiteId(siteRemoteId)).thenReturn(SiteModel().apply { id = 1; url = siteUrl }) } @Test @@ -242,7 +242,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { SiteCreationState( segmentId = 1, siteDesign = defaultTemplateSlug, - domain = DomainModel(url, true, "", 1) + domain = DomainModel(siteUrl, true, "", 1) ), bundle.apply { restoredState?.let { whenever(getParcelable(KEY_CREATE_SITE_STATE)) doReturn it } From 1bf056228ea840c9e6cb26143649459bd1177d49 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 15:50:09 +0200 Subject: [PATCH 055/169] Fix: mock response to prevent silent error in test --- .../ui/sitecreation/progress/SiteProgressViewModelTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt index f3ed60c5030e..caf2c1b80f3d 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -143,7 +143,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { } @Test - fun `on start fetches site by remote id when restoring SiteNotInLocalDb`() = test { + fun `on start fetches site by remote id when restoring SiteNotInLocalDb`() = testWith(successResponse) { startViewModel(siteNotInLocalDb) verify(fetchWpComSiteUseCase).fetchSiteWithRetry(siteRemoteId) } From 59d572387ae7526570a54f44f892dc193c33e146 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 16:10:13 +0200 Subject: [PATCH 056/169] Refactor: Rename CreateSiteState to SiteCreationResult moved to main vm --- .../ui/sitecreation/SiteCreationActivity.kt | 39 ++++++++------- .../ui/sitecreation/SiteCreationMainVM.kt | 34 +++++++++---- .../ui/sitecreation/misc/CreateSiteState.kt | 30 ----------- .../previews/SiteCreationPreviewFragment.kt | 18 +++---- .../previews/SitePreviewScreenListener.kt | 4 +- .../previews/SitePreviewViewModel.kt | 14 +++--- .../progress/ProgressScreenListener.kt | 6 +-- .../progress/SiteCreationProgressFragment.kt | 4 +- .../progress/SiteProgressViewModel.kt | 50 +++++++++---------- .../ui/sitecreation/SiteCreationMainVMTest.kt | 19 ++++--- .../previews/SitePreviewViewModelTest.kt | 12 ++--- .../progress/SiteProgressViewModelTest.kt | 22 ++++---- 12 files changed, 118 insertions(+), 134 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitecreation/misc/CreateSiteState.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 24c07ad3c047..3f79fb8e6a3d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -26,6 +26,9 @@ import org.wordpress.android.ui.posts.BasicFragmentDialog.BasicDialogPositiveCli import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleEmpty import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.SiteCreationStep.DOMAINS import org.wordpress.android.ui.sitecreation.SiteCreationStep.INTENTS import org.wordpress.android.ui.sitecreation.SiteCreationStep.PROGRESS @@ -39,10 +42,6 @@ import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.previews.SiteCreationPreviewFragment import org.wordpress.android.ui.sitecreation.previews.SitePreviewScreenListener -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocalDb import org.wordpress.android.ui.sitecreation.progress.ProgressScreenListener import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressFragment import org.wordpress.android.ui.sitecreation.sitename.SiteCreationSiteNameFragment @@ -81,8 +80,10 @@ class SiteCreationActivity : LocaleAwareActivity(), private val siteCreationIntentsViewModel: SiteCreationIntentsViewModel by viewModels() private val siteCreationSiteNameViewModel: SiteCreationSiteNameViewModel by viewModels() private val jetpackFullScreenViewModel: JetpackFeatureFullScreenOverlayViewModel by viewModels() - @Inject internal lateinit var jetpackFeatureRemovalOverlayUtil: JetpackFeatureRemovalOverlayUtil - @Inject internal lateinit var activityLauncherWrapper: ActivityLauncherWrapper + @Inject + internal lateinit var jetpackFeatureRemovalOverlayUtil: JetpackFeatureRemovalOverlayUtil + @Inject + internal lateinit var activityLauncherWrapper: ActivityLauncherWrapper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -107,16 +108,16 @@ class SiteCreationActivity : LocaleAwareActivity(), val intent = Intent() val (siteCreated, localSiteId, titleTaskComplete) = when (createSiteState) { // site creation flow was canceled - is SiteNotCreated -> Triple(false, null, false) - is SiteNotInLocalDb -> { + is NotCreated -> Triple(false, null, false) + is NotInLocalDb -> { // Site was created, but we haven't been able to fetch it, let `SitePickerActivity` handle // this with a Snackbar message. intent.putExtra(SitePickerActivity.KEY_SITE_CREATED_BUT_NOT_FETCHED, true) Triple(true, null, createSiteState.isSiteTitleTaskComplete) } - is SiteCreationCompleted -> Triple( - true, createSiteState.localSiteId, - createSiteState.isSiteTitleTaskComplete + is Completed -> Triple( + true, createSiteState.localSiteId, + createSiteState.isSiteTitleTaskComplete ) } intent.putExtra(SitePickerActivity.KEY_SITE_LOCAL_ID, localSiteId) @@ -167,10 +168,10 @@ class SiteCreationActivity : LocaleAwareActivity(), private fun observeOverlayEvents() { val fragment = JetpackFeatureFullScreenOverlayFragment - .newInstance( - isSiteCreationOverlay = true, - siteCreationSource = getSiteCreationSource() - ) + .newInstance( + isSiteCreationOverlay = true, + siteCreationSource = getSiteCreationSource() + ) jetpackFullScreenViewModel.action.observe(this) { action -> if (mainViewModel.siteCreationDisabled) finish() @@ -214,11 +215,11 @@ class SiteCreationActivity : LocaleAwareActivity(), mainViewModel.onDomainsScreenFinished(domain) } - override fun onSiteCreationCompleted(state: CreateSiteState) = mainViewModel.onSiteCreationCompleted(state) + override fun onProgressCompleted(result: SiteCreationResult) = mainViewModel.onSiteCreationCompleted(result) - override fun onProgressScreenDismissed(state: CreateSiteState) = mainViewModel.onProgressOrPreviewFinished(state) + override fun onProgressStopped(result: SiteCreationResult) = mainViewModel.onProgressOrPreviewFinished(result) - override fun onPreviewScreenDismissed(state: CreateSiteState) = mainViewModel.onProgressOrPreviewFinished(state) + override fun onPreviewScreenClosed(result: SiteCreationResult) = mainViewModel.onProgressOrPreviewFinished(result) override fun onHelpClicked(origin: Origin) { ActivityLauncher.viewHelp(this, origin, null, null) @@ -239,7 +240,7 @@ class SiteCreationActivity : LocaleAwareActivity(), SITE_PREVIEW -> SiteCreationPreviewFragment.newInstance( screenTitle, target.wizardState, - mainViewModel.createSiteResult, + mainViewModel.result, ) } showFragment(fragment, target.wizardStep.toString(), target.wizardStep != SITE_PREVIEW) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 4d8f6584f870..e2395ec69d67 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -21,11 +21,10 @@ import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleEmpty import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated import org.wordpress.android.ui.sitecreation.usecases.FetchHomePageLayoutsUseCase import org.wordpress.android.ui.utils.UiString.UiStringRes import org.wordpress.android.util.AppLog @@ -54,11 +53,26 @@ data class SiteCreationState( val siteName: String? = null, val segmentId: Long? = null, val siteDesign: String? = null, - val domain: DomainModel? = null + val domain: DomainModel? = null, ) : WizardState, Parcelable typealias NavigationTarget = WizardNavigationTarget +sealed class SiteCreationResult : Parcelable { + @Parcelize + object NotCreated : SiteCreationResult() + + @Parcelize + data class NotInLocalDb(val remoteSiteId: Long, val isSiteTitleTaskComplete: Boolean) : SiteCreationResult() + + @Parcelize + data class Completed( + val localSiteId: Int, + val isSiteTitleTaskComplete: Boolean, + val url: String, + ) : SiteCreationResult() +} + @HiltViewModel class SiteCreationMainVM @Inject constructor( private val tracker: SiteCreationTracker, @@ -85,7 +99,7 @@ class SiteCreationMainVM @Inject constructor( private var siteCreationCompleted = false private lateinit var siteCreationState: SiteCreationState - var createSiteResult: CreateSiteState = SiteNotCreated + var result: SiteCreationResult = NotCreated internal var preloadingJob: Job? = null @@ -101,8 +115,8 @@ class SiteCreationMainVM @Inject constructor( private val _dialogAction = SingleLiveEvent() val dialogActionObservable: LiveData = _dialogAction - private val _wizardFinishedObservable = SingleLiveEvent() - val wizardFinishedObservable: LiveData = _wizardFinishedObservable + private val _wizardFinishedObservable = SingleLiveEvent() + val wizardFinishedObservable: LiveData = _wizardFinishedObservable private val _exitFlowObservable = SingleLiveEvent() val exitFlowObservable: LiveData = _exitFlowObservable @@ -252,8 +266,8 @@ class SiteCreationMainVM @Inject constructor( } } - fun onSiteCreationCompleted(state: CreateSiteState) { - createSiteResult = state + fun onSiteCreationCompleted(result: SiteCreationResult) { + this.result = result siteCreationCompleted = true wizardManager.showNextStep() } @@ -268,8 +282,8 @@ class SiteCreationMainVM @Inject constructor( _exitFlowObservable.call() } - fun onProgressOrPreviewFinished(createSiteState: CreateSiteState) { - _wizardFinishedObservable.value = createSiteState + fun onProgressOrPreviewFinished(result: SiteCreationResult) { + _wizardFinishedObservable.value = result } fun onPositiveDialogButtonClicked(instanceTag: String) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/misc/CreateSiteState.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/misc/CreateSiteState.kt deleted file mode 100644 index 42bfde743cb1..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/misc/CreateSiteState.kt +++ /dev/null @@ -1,30 +0,0 @@ -package org.wordpress.android.ui.sitecreation.misc - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -sealed class CreateSiteState : Parcelable { - /** - * CreateSite request haven't finished yet or failed. - */ - @Parcelize - object SiteNotCreated : CreateSiteState() - - /** - * FetchSite request haven't finished yet or failed. - * Since we fetch the site without user awareness in background, the user may potentially leave the screen - * before the request is finished. - */ - @Parcelize - data class SiteNotInLocalDb(val remoteSiteId: Long, val isSiteTitleTaskComplete: Boolean) : CreateSiteState() - - /** - * The site has been successfully created and stored into local db. - */ - @Parcelize - data class SiteCreationCompleted( - val localSiteId: Int, - val isSiteTitleTaskComplete: Boolean, - val url: String, - ) : CreateSiteState() -} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 681b1d2c8e91..b19397a4883f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -28,14 +28,14 @@ import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SiteP import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewLoadingShimmerState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewWebErrorUiState -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState +import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.utils.UiHelpers import org.wordpress.android.util.ErrorManagedWebViewClient.ErrorManagedWebViewClientListener import org.wordpress.android.util.URLFilteredWebViewClient import org.wordpress.android.widgets.NestedWebView import javax.inject.Inject -private const val ARG_DATA = "arg_site_creation_data" +private const val ARG_STATE = "arg_site_creation_state" private const val ARG_RESULT = "arg_site_creation_result" private const val SLIDE_IN_ANIMATION_DURATION = 450L @@ -71,8 +71,8 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), (requireActivity() as AppCompatActivity).supportActionBar?.hide() viewModel.start( - requireArguments()[ARG_DATA] as SiteCreationState, - requireArguments()[ARG_RESULT] as CreateSiteState, + requireArguments()[ARG_STATE] as SiteCreationState, + requireArguments()[ARG_RESULT] as SiteCreationResult, ) } @@ -134,7 +134,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), private fun observeDismissClicks(listener: SitePreviewScreenListener) { viewModel.onOkButtonClicked.observe(this) { createSiteState -> - createSiteState?.let { listener.onPreviewScreenDismissed(it) } + createSiteState?.let { listener.onPreviewScreenClosed(it) } } } @@ -259,13 +259,13 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), fun newInstance( screenTitle: String, - siteCreationData: SiteCreationState, - createSiteState: CreateSiteState, + siteCreationState: SiteCreationState, + creationResult: SiteCreationResult, ) = SiteCreationPreviewFragment().apply { arguments = Bundle().apply { putString(EXTRA_SCREEN_TITLE, screenTitle) - putParcelable(ARG_DATA, siteCreationData) - putParcelable(ARG_RESULT, createSiteState) + putParcelable(ARG_STATE, siteCreationState) + putParcelable(ARG_RESULT, creationResult) } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt index 5eadb73e92cc..dd2e8cd6fae8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt @@ -1,7 +1,7 @@ package org.wordpress.android.ui.sitecreation.previews -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState +import org.wordpress.android.ui.sitecreation.SiteCreationResult interface SitePreviewScreenListener { - fun onPreviewScreenDismissed(state: CreateSiteState) + fun onPreviewScreenClosed(result: SiteCreationResult) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 0cea2862ab9a..1e5c7db8f99f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -12,7 +12,7 @@ import kotlinx.coroutines.withContext import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.sitecreation.SiteCreationState -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState +import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewLoadingShimmerState @@ -44,7 +44,7 @@ class SitePreviewViewModel @Inject constructor( private lateinit var siteCreationState: SiteCreationState private var urlWithoutScheme: String? = null - private lateinit var createSiteState: CreateSiteState + private lateinit var result: SiteCreationResult private val _uiState: MutableLiveData = MutableLiveData() val uiState: LiveData = _uiState @@ -55,20 +55,20 @@ class SitePreviewViewModel @Inject constructor( private val _onHelpClicked = SingleLiveEvent() val onHelpClicked: LiveData = _onHelpClicked - private val _onOkButtonClicked = SingleLiveEvent() - val onOkButtonClicked: LiveData = _onOkButtonClicked + private val _onOkButtonClicked = SingleLiveEvent() + val onOkButtonClicked: LiveData = _onOkButtonClicked override fun onCleared() { super.onCleared() job.cancel() } - fun start(siteCreationState: SiteCreationState, createSiteState: CreateSiteState) { + fun start(siteCreationState: SiteCreationState, result: SiteCreationResult) { if (isStarted) return isStarted = true this.siteCreationState = siteCreationState this.urlWithoutScheme = siteCreationState.domain?.domainName - this.createSiteState = createSiteState + this.result = result startPreLoadingWebView() } @@ -76,7 +76,7 @@ class SitePreviewViewModel @Inject constructor( fun onOkButtonClicked() { tracker.trackPreviewOkButtonTapped() - _onOkButtonClicked.value = createSiteState + _onOkButtonClicked.value = result } private fun startPreLoadingWebView() { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt index f15de359f261..68efc6f18b6d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt @@ -1,8 +1,8 @@ package org.wordpress.android.ui.sitecreation.progress -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState +import org.wordpress.android.ui.sitecreation.SiteCreationResult interface ProgressScreenListener { - fun onProgressScreenDismissed(state: CreateSiteState) - fun onSiteCreationCompleted(state: CreateSiteState) + fun onProgressStopped(result: SiteCreationResult) + fun onProgressCompleted(result: SiteCreationResult) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt index 829bef54bc23..69411d20fc4c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt @@ -103,13 +103,13 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc } viewModel.onSiteCreationCompleted.observe(viewLifecycleOwner) { view?.announceForAccessibility(getString(R.string.new_site_creation_preview_title)) - listener.onSiteCreationCompleted(it) + listener.onProgressCompleted(it) } } private fun observeDismissClicks(listener: ProgressScreenListener) { viewModel.onCancelWizardClicked.observe(viewLifecycleOwner) { createSiteState -> - createSiteState?.let { listener.onProgressScreenDismissed(it) } + createSiteState?.let { listener.onProgressStopped(it) } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt index 54fba13f1728..8670430e9ead 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt @@ -18,10 +18,10 @@ import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.sitecreation.SiteCreationState -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocalDb +import org.wordpress.android.ui.sitecreation.SiteCreationResult +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.UNKNOWN import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker @@ -78,7 +78,7 @@ class SiteProgressViewModel @Inject constructor( private var siteTitle: String? = null private var lastReceivedServiceState: SiteCreationServiceState? = null private var serviceStateForRetry: SiteCreationServiceState? = null - private var createSiteState: CreateSiteState = SiteNotCreated + private var result: SiteCreationResult = NotCreated private val _uiState: MutableLiveData = MutableLiveData() val uiState: LiveData = _uiState @@ -89,11 +89,11 @@ class SiteProgressViewModel @Inject constructor( private val _onHelpClicked = SingleLiveEvent() val onHelpClicked: LiveData = _onHelpClicked - private val _onCancelWizardClicked = SingleLiveEvent() - val onCancelWizardClicked: LiveData = _onCancelWizardClicked + private val _onCancelWizardClicked = SingleLiveEvent() + val onCancelWizardClicked: LiveData = _onCancelWizardClicked - private val _onSiteCreationCompleted = SingleLiveEvent() - val onSiteCreationCompleted: LiveData = _onSiteCreationCompleted + private val _onSiteCreationCompleted = SingleLiveEvent() + val onSiteCreationCompleted: LiveData = _onSiteCreationCompleted init { dispatcher.register(fetchWpComSiteUseCase) @@ -106,7 +106,7 @@ class SiteProgressViewModel @Inject constructor( loadingAnimationJob?.cancel() } - fun writeToBundle(outState: Bundle) = outState.putParcelable(KEY_CREATE_SITE_STATE, createSiteState) + fun writeToBundle(outState: Bundle) = outState.putParcelable(KEY_CREATE_SITE_STATE, result) fun start(siteCreationState: SiteCreationState, savedState: Bundle?) { if (isStarted) return @@ -115,25 +115,25 @@ class SiteProgressViewModel @Inject constructor( urlWithoutScheme = siteCreationState.domain?.domainName siteTitle = siteCreationState.siteName - val restoredState = savedState?.getParcelable(KEY_CREATE_SITE_STATE) + val restoredState = savedState?.getParcelable(KEY_CREATE_SITE_STATE) - init(restoredState ?: SiteNotCreated) + init(restoredState ?: NotCreated) } - private fun init(state: CreateSiteState) { - createSiteState = state + private fun init(state: SiteCreationResult) { + result = state when (state) { - SiteNotCreated -> { + NotCreated -> { runLoadingAnimationUi() startCreateSiteService() } - is SiteNotInLocalDb -> { + is NotInLocalDb -> { runLoadingAnimationUi() launch { - createSiteState = fetchNewlyCreatedSiteModel(state.remoteSiteId) + result = fetchNewlyCreatedSiteModel(state.remoteSiteId) } } - is SiteCreationCompleted -> Unit + is Completed -> Unit } } @@ -164,7 +164,7 @@ class SiteProgressViewModel @Inject constructor( fun onHelpClicked() = _onHelpClicked.call() fun onCancelWizardClicked() { - _onCancelWizardClicked.value = createSiteState + _onCancelWizardClicked.value = result } private fun showFullscreenErrorWithDelay() { @@ -194,9 +194,9 @@ class SiteProgressViewModel @Inject constructor( SUCCESS -> { val remoteSiteId = (event.payload as Pair<*, *>).first as Long urlWithoutScheme = urlUtils.removeScheme(event.payload.second as String).trimEnd('/') - createSiteState = SiteNotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) + result = NotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) launch { - createSiteState = fetchNewlyCreatedSiteModel(remoteSiteId) + result = fetchNewlyCreatedSiteModel(remoteSiteId) } } FAILURE -> { @@ -214,15 +214,15 @@ class SiteProgressViewModel @Inject constructor( /** * Fetch newly created site model - supports retry with linear backoff. */ - private suspend fun fetchNewlyCreatedSiteModel(remoteSiteId: Long): CreateSiteState { + private suspend fun fetchNewlyCreatedSiteModel(remoteSiteId: Long): SiteCreationResult { val onSiteFetched = fetchWpComSiteUseCase.fetchSiteWithRetry(remoteSiteId) return if (!onSiteFetched.isError) { val siteBySiteId = requireNotNull(siteStore.getSiteBySiteId(remoteSiteId)) { "Site successfully fetched but has not been found in the local db." } - SiteCreationCompleted(siteBySiteId.id, !siteTitle.isNullOrBlank(), siteBySiteId.url) + Completed(siteBySiteId.id, !siteTitle.isNullOrBlank(), siteBySiteId.url) } else { - SiteNotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) + NotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) } } @@ -238,7 +238,7 @@ class SiteProgressViewModel @Inject constructor( ) delay(LOADING_STATE_TEXT_ANIMATION_DELAY) } - _onSiteCreationCompleted.postValue(createSiteState) + _onSiteCreationCompleted.postValue(result) } } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index f60f2eac8166..022c64d498fb 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -32,9 +32,8 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.domains.DomainModel -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.usecases.FetchHomePageLayoutsUseCase @@ -64,7 +63,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { lateinit var navigationTargetObserver: Observer @Mock - lateinit var wizardFinishedObserver: Observer + lateinit var wizardFinishedObserver: Observer @Mock lateinit var wizardExitedObserver: Observer @@ -141,10 +140,10 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun wizardFinishedInvokedOnSitePreviewCompleted() { - val state = SiteCreationCompleted(LOCAL_SITE_ID, false, DOMAIN.domainName) + val state = Completed(LOCAL_SITE_ID, false, DOMAIN.domainName) viewModel.onProgressOrPreviewFinished(state) - val captor = ArgumentCaptor.forClass(CreateSiteState::class.java) + val captor = ArgumentCaptor.forClass(SiteCreationResult::class.java) verify(wizardFinishedObserver).onChanged(captor.capture()) assertThat(captor.value).isEqualTo(state) @@ -332,21 +331,21 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun `initial createSiteResult is SiteNotCreated`() { - assertThat(viewModel.createSiteResult).isEqualTo(SiteNotCreated) + assertThat(viewModel.result1).isEqualTo(NotCreated) } @Test fun `createSiteResult is updated by onSiteCreationCompleted`() { - val expectedState = SiteCreationCompleted(LOCAL_SITE_ID, false, DOMAIN.domainName) + val expectedState = Completed(LOCAL_SITE_ID, false, DOMAIN.domainName) viewModel.onSiteCreationCompleted(expectedState) - assertThat(viewModel.createSiteResult).isEqualTo(expectedState) + assertThat(viewModel.result1).isEqualTo(expectedState) } @Test fun `next step is shown by onSiteCreationCompleted`() { - val expectedState = SiteCreationCompleted(LOCAL_SITE_ID, false, DOMAIN.domainName) + val expectedState = Completed(LOCAL_SITE_ID, false, DOMAIN.domainName) viewModel.onSiteCreationCompleted(expectedState) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index 7b97afcec82c..fa5e0340749d 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -14,8 +14,8 @@ import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.domains.DomainModel -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteCreationCompleted +import org.wordpress.android.ui.sitecreation.SiteCreationResult +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState @@ -45,7 +45,7 @@ class SitePreviewViewModelTest : BaseUnitTest() { private lateinit var onHelpedClickedObserver: Observer @Mock - private lateinit var onOkClickedObserver: Observer + private lateinit var onOkClickedObserver: Observer @Mock private lateinit var preloadPreviewObserver: Observer @@ -94,15 +94,15 @@ class SitePreviewViewModelTest : BaseUnitTest() { @Test fun `start pre-loading WebView when restoring from SiteCreationCompleted state`() { - initViewModel(createSiteState = SiteCreationCompleted(2, false, URL)) + initViewModel(result = Completed(2, false, URL)) assertThat(viewModel.preloadPreview.value).isEqualTo(URL) } private fun initViewModel( siteCreationState: SiteCreationState = SITE_CREATION_STATE, - createSiteState: CreateSiteState = mock(), + result: SiteCreationResult = mock(), ) { - viewModel.start(siteCreationState, createSiteState) + viewModel.start(siteCreationState, result) } } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt index caf2c1b80f3d..b2e948ed47c8 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -30,9 +30,9 @@ import org.wordpress.android.fluxc.store.SiteStore.SiteError import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.domains.DomainModel -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotCreated -import org.wordpress.android.ui.sitecreation.misc.CreateSiteState.SiteNotInLocalDb +import org.wordpress.android.ui.sitecreation.SiteCreationResult +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.KEY_CREATE_SITE_STATE import org.wordpress.android.ui.sitecreation.previews.LOADING_STATE_TEXT_ANIMATION_DELAY @@ -55,7 +55,7 @@ import kotlin.test.assertNotNull private const val siteUrl = "test.wordpress.com" private const val siteRemoteId = 1L -private val siteNotInLocalDb = SiteNotInLocalDb(siteRemoteId, false) +private val siteNotInLocalDb = NotInLocalDb(siteRemoteId, false) private val successServiceState = SiteCreationServiceState(SUCCESS, Pair(siteRemoteId, siteUrl)) private val errorServiceState = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) private val successResponse = OnSiteChanged(1) @@ -74,8 +74,8 @@ class SiteProgressViewModelTest : BaseUnitTest() { private val uiStateObserver = mock>() private val startServiceObserver = mock>() private val onHelpedClickedObserver = mock>() - private val onCancelWizardClickedObserver = mock>() - private val onSiteCreationCompletedObserver = mock>() + private val onCancelWizardClickedObserver = mock>() + private val onSiteCreationCompletedObserver = mock>() private val bundle = mock() @@ -112,7 +112,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on start shows progress when restoring SiteNotCreated`() = testWith(successResponse) { - startViewModel(SiteNotCreated) + startViewModel(NotCreated) assertIs(viewModel.uiState.value) } @@ -130,7 +130,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on start emits service event when restoring from SiteNotCreated`() { - startViewModel(SiteNotCreated) + startViewModel(NotCreated) assertNotNull(viewModel.startCreateSiteService.value) } @@ -190,7 +190,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on cancel wizard click is propagated`() { viewModel.onCancelWizardClicked() - assertEquals(viewModel.onCancelWizardClicked.value, SiteNotCreated) + assertEquals(viewModel.onCancelWizardClicked.value, NotCreated) } @Test @@ -237,7 +237,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { block() } - private fun startViewModel(restoredState: CreateSiteState? = null) { + private fun startViewModel(restoredState: SiteCreationResult? = null) { viewModel.start( SiteCreationState( segmentId = 1, @@ -245,7 +245,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { domain = DomainModel(siteUrl, true, "", 1) ), bundle.apply { - restoredState?.let { whenever(getParcelable(KEY_CREATE_SITE_STATE)) doReturn it } + restoredState?.let { whenever(getParcelable(KEY_CREATE_SITE_STATE)) doReturn it } } ) } From 2029b3d27094d352bd89737e6723fa33093d507e Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 21:36:21 +0100 Subject: [PATCH 057/169] Refactor: move result to SiteCreationState --- .../android/ui/sitecreation/SiteCreationActivity.kt | 3 +-- .../android/ui/sitecreation/SiteCreationMainVM.kt | 8 ++++---- .../previews/SiteCreationPreviewFragment.kt | 11 ++--------- .../previews/SitePreviewScreenListener.kt | 4 +--- .../ui/sitecreation/previews/SitePreviewViewModel.kt | 11 ++++------- 5 files changed, 12 insertions(+), 25 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 3f79fb8e6a3d..8a4c9750150e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -219,7 +219,7 @@ class SiteCreationActivity : LocaleAwareActivity(), override fun onProgressStopped(result: SiteCreationResult) = mainViewModel.onProgressOrPreviewFinished(result) - override fun onPreviewScreenClosed(result: SiteCreationResult) = mainViewModel.onProgressOrPreviewFinished(result) + override fun onPreviewScreenClosed() = mainViewModel.onProgressOrPreviewFinished() override fun onHelpClicked(origin: Origin) { ActivityLauncher.viewHelp(this, origin, null, null) @@ -240,7 +240,6 @@ class SiteCreationActivity : LocaleAwareActivity(), SITE_PREVIEW -> SiteCreationPreviewFragment.newInstance( screenTitle, target.wizardState, - mainViewModel.result, ) } showFragment(fragment, target.wizardStep.toString(), target.wizardStep != SITE_PREVIEW) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index e2395ec69d67..66e70dedece0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -54,6 +54,7 @@ data class SiteCreationState( val segmentId: Long? = null, val siteDesign: String? = null, val domain: DomainModel? = null, + val result: SiteCreationResult = NotCreated, ) : WizardState, Parcelable typealias NavigationTarget = WizardNavigationTarget @@ -99,7 +100,6 @@ class SiteCreationMainVM @Inject constructor( private var siteCreationCompleted = false private lateinit var siteCreationState: SiteCreationState - var result: SiteCreationResult = NotCreated internal var preloadingJob: Job? = null @@ -267,7 +267,7 @@ class SiteCreationMainVM @Inject constructor( } fun onSiteCreationCompleted(result: SiteCreationResult) { - this.result = result + siteCreationState = siteCreationState.copy(result = result) siteCreationCompleted = true wizardManager.showNextStep() } @@ -282,8 +282,8 @@ class SiteCreationMainVM @Inject constructor( _exitFlowObservable.call() } - fun onProgressOrPreviewFinished(result: SiteCreationResult) { - _wizardFinishedObservable.value = result + fun onProgressOrPreviewFinished(result: SiteCreationResult? = null) { + _wizardFinishedObservable.value = result ?: siteCreationState.result } fun onPositiveDialogButtonClicked(instanceTag: String) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index b19397a4883f..83bd56dc12fb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -28,7 +28,6 @@ import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SiteP import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewLoadingShimmerState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewWebErrorUiState -import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.utils.UiHelpers import org.wordpress.android.util.ErrorManagedWebViewClient.ErrorManagedWebViewClientListener import org.wordpress.android.util.URLFilteredWebViewClient @@ -36,7 +35,6 @@ import org.wordpress.android.widgets.NestedWebView import javax.inject.Inject private const val ARG_STATE = "arg_site_creation_state" -private const val ARG_RESULT = "arg_site_creation_result" private const val SLIDE_IN_ANIMATION_DURATION = 450L @AndroidEntryPoint @@ -70,10 +68,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), private fun init() { (requireActivity() as AppCompatActivity).supportActionBar?.hide() - viewModel.start( - requireArguments()[ARG_STATE] as SiteCreationState, - requireArguments()[ARG_RESULT] as SiteCreationResult, - ) + viewModel.start(requireArguments()[ARG_STATE] as SiteCreationState) } override fun getContentLayout() = R.layout.site_creation_preview_screen @@ -134,7 +129,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), private fun observeDismissClicks(listener: SitePreviewScreenListener) { viewModel.onOkButtonClicked.observe(this) { createSiteState -> - createSiteState?.let { listener.onPreviewScreenClosed(it) } + createSiteState?.let { listener.onPreviewScreenClosed() } } } @@ -260,12 +255,10 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), fun newInstance( screenTitle: String, siteCreationState: SiteCreationState, - creationResult: SiteCreationResult, ) = SiteCreationPreviewFragment().apply { arguments = Bundle().apply { putString(EXTRA_SCREEN_TITLE, screenTitle) putParcelable(ARG_STATE, siteCreationState) - putParcelable(ARG_RESULT, creationResult) } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt index dd2e8cd6fae8..cced69180e31 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt @@ -1,7 +1,5 @@ package org.wordpress.android.ui.sitecreation.previews -import org.wordpress.android.ui.sitecreation.SiteCreationResult - interface SitePreviewScreenListener { - fun onPreviewScreenClosed(result: SiteCreationResult) + fun onPreviewScreenClosed() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 1e5c7db8f99f..78016d0df37c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -12,7 +12,6 @@ import kotlinx.coroutines.withContext import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.sitecreation.SiteCreationState -import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewLoadingShimmerState @@ -44,7 +43,6 @@ class SitePreviewViewModel @Inject constructor( private lateinit var siteCreationState: SiteCreationState private var urlWithoutScheme: String? = null - private lateinit var result: SiteCreationResult private val _uiState: MutableLiveData = MutableLiveData() val uiState: LiveData = _uiState @@ -55,20 +53,19 @@ class SitePreviewViewModel @Inject constructor( private val _onHelpClicked = SingleLiveEvent() val onHelpClicked: LiveData = _onHelpClicked - private val _onOkButtonClicked = SingleLiveEvent() - val onOkButtonClicked: LiveData = _onOkButtonClicked + private val _onOkButtonClicked = SingleLiveEvent() + val onOkButtonClicked: LiveData = _onOkButtonClicked override fun onCleared() { super.onCleared() job.cancel() } - fun start(siteCreationState: SiteCreationState, result: SiteCreationResult) { + fun start(siteCreationState: SiteCreationState) { if (isStarted) return isStarted = true this.siteCreationState = siteCreationState this.urlWithoutScheme = siteCreationState.domain?.domainName - this.result = result startPreLoadingWebView() } @@ -76,7 +73,7 @@ class SitePreviewViewModel @Inject constructor( fun onOkButtonClicked() { tracker.trackPreviewOkButtonTapped() - _onOkButtonClicked.value = result + _onOkButtonClicked.call() } private fun startPreLoadingWebView() { From 1a035b9d3c7dc32807d820cdabddb62731ac9a79 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 21:42:03 +0100 Subject: [PATCH 058/169] Refactor: convert SiteCreationState class to interface --- .../ui/sitecreation/SiteCreationMainVM.kt | 8 ++-- .../ui/sitecreation/SiteCreationMainVMTest.kt | 48 +++++++++---------- .../previews/SitePreviewViewModelTest.kt | 32 +++++++------ 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 66e70dedece0..65099a20b2f4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -59,19 +59,19 @@ data class SiteCreationState( typealias NavigationTarget = WizardNavigationTarget -sealed class SiteCreationResult : Parcelable { +sealed interface SiteCreationResult : Parcelable { @Parcelize - object NotCreated : SiteCreationResult() + object NotCreated : SiteCreationResult @Parcelize - data class NotInLocalDb(val remoteSiteId: Long, val isSiteTitleTaskComplete: Boolean) : SiteCreationResult() + data class NotInLocalDb(val remoteSiteId: Long, val isSiteTitleTaskComplete: Boolean) : SiteCreationResult @Parcelize data class Completed( val localSiteId: Int, val isSiteTitleTaskComplete: Boolean, val url: String, - ) : SiteCreationResult() + ) : SiteCreationResult } @HiltViewModel diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 022c64d498fb..ec52b25bf712 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -7,14 +7,15 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argThat +import org.mockito.kotlin.argWhere import org.mockito.kotlin.atLeastOnce import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.eq import org.mockito.kotlin.isA import org.mockito.kotlin.mock import org.mockito.kotlin.never @@ -32,8 +33,6 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.domains.DomainModel -import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed -import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.usecases.FetchHomePageLayoutsUseCase @@ -139,14 +138,20 @@ class SiteCreationMainVMTest : BaseUnitTest() { } @Test - fun wizardFinishedInvokedOnSitePreviewCompleted() { - val state = Completed(LOCAL_SITE_ID, false, DOMAIN.domainName) - viewModel.onProgressOrPreviewFinished(state) + fun `on preview emits completion result to wizardFinishedObservable`() { + val result = SiteCreationResult.Completed(LOCAL_SITE_ID, false, DOMAIN.domainName) + viewModel.onSiteCreationCompleted(result) - val captor = ArgumentCaptor.forClass(SiteCreationResult::class.java) - verify(wizardFinishedObserver).onChanged(captor.capture()) + viewModel.onProgressOrPreviewFinished() - assertThat(captor.value).isEqualTo(state) + verify(wizardFinishedObserver).onChanged(eq(result)) + } + + @Test + fun `on progress finished emits result to wizardFinishedObservable`() { + val result = SiteCreationResult.Completed(LOCAL_SITE_ID, false, DOMAIN.domainName) + viewModel.onProgressOrPreviewFinished(result) + verify(wizardFinishedObserver).onChanged(eq(result)) } @Test @@ -309,6 +314,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { verify(tracker, never()).trackSiteCreationDomainPurchasingExperimentVariation(any()) } + @Test fun `given domain purchasing experiment on, when start in control variation, then experiment is tracked`() { whenever(domainPurchasingFeatureConfig.isEnabledState()).thenReturn(true) @@ -330,30 +336,24 @@ class SiteCreationMainVMTest : BaseUnitTest() { } @Test - fun `initial createSiteResult is SiteNotCreated`() { - assertThat(viewModel.result1).isEqualTo(NotCreated) - } + fun `on site creation completed propagates result to state`() { + val expected = mock() - @Test - fun `createSiteResult is updated by onSiteCreationCompleted`() { - val expectedState = Completed(LOCAL_SITE_ID, false, DOMAIN.domainName) + viewModel.onSiteCreationCompleted(expected) - viewModel.onSiteCreationCompleted(expectedState) + val bundle = mock() + viewModel.writeToBundle(bundle) // used this to assert on the private siteCreationState field + verify(bundle).putParcelable(eq(KEY_SITE_CREATION_STATE), argWhere { it.result == expected }) - assertThat(viewModel.result1).isEqualTo(expectedState) } @Test - fun `next step is shown by onSiteCreationCompleted`() { - val expectedState = Completed(LOCAL_SITE_ID, false, DOMAIN.domainName) - - viewModel.onSiteCreationCompleted(expectedState) - + fun `on site creation completed shows next step`() { + viewModel.onSiteCreationCompleted(mock()) verify(wizardManager).showNextStep() } - private fun currentWizardState(vm: SiteCreationMainVM) = - vm.navigationTargetObservable.lastEvent!!.wizardState + private fun currentWizardState(vm: SiteCreationMainVM) = vm.navigationTargetObservable.lastEvent!!.wizardState private fun getNewViewModel() = SiteCreationMainVM( tracker, diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index fa5e0340749d..3291d1b08981 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -9,12 +9,12 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.mock +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.domains.DomainModel -import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState @@ -45,7 +45,7 @@ class SitePreviewViewModelTest : BaseUnitTest() { private lateinit var onHelpedClickedObserver: Observer @Mock - private lateinit var onOkClickedObserver: Observer + private lateinit var onOkClickedObserver: Observer @Mock private lateinit var preloadPreviewObserver: Observer @@ -70,16 +70,16 @@ class SitePreviewViewModelTest : BaseUnitTest() { @Test fun `show content on UrlLoaded`() { - initViewModel() + startViewModel() viewModel.onUrlLoaded() assertThat(viewModel.uiState.value).isInstanceOf(SitePreviewContentUiState::class.java) } @Test fun `displaying content cancels the progress animation job`() = test { - initViewModel() + startViewModel() viewModel.onUrlLoaded() - (1..100).forEach { + repeat(100) { advanceTimeBy(LOADING_STATE_TEXT_ANIMATION_DELAY) assertThat(viewModel.uiState.value).isInstanceOf(SitePreviewContentUiState::class.java) } @@ -87,22 +87,26 @@ class SitePreviewViewModelTest : BaseUnitTest() { @Test fun `show webview empty screen on WebViewError`() { - initViewModel() + startViewModel() viewModel.onWebViewError() assertThat(viewModel.uiState.value).isInstanceOf(SitePreviewWebErrorUiState::class.java) } @Test - fun `start pre-loading WebView when restoring from SiteCreationCompleted state`() { - initViewModel(result = Completed(2, false, URL)) + fun `on start preloads the preview when result is Completed`() { + startViewModel(SITE_CREATION_STATE.copy(result = Completed(2, false, URL))) assertThat(viewModel.preloadPreview.value).isEqualTo(URL) } - private fun initViewModel( - siteCreationState: SiteCreationState = SITE_CREATION_STATE, - result: SiteCreationResult = mock(), - ) { - viewModel.start(siteCreationState, result) + @Test + fun `on ok button click is propagated`() { + viewModel.onOkButtonClicked() + + verify(onOkClickedObserver).onChanged(anyOrNull()) + } + + private fun startViewModel(siteCreationState: SiteCreationState = SITE_CREATION_STATE) { + viewModel.start(siteCreationState) } } From ded2a529605097b99c89c20b02cec26c7c36f68e Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 21:51:56 +0100 Subject: [PATCH 059/169] Refactor: put params of preview fragment init on one line --- .../android/ui/sitecreation/SiteCreationActivity.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 8a4c9750150e..b67b14fcf5ae 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -237,10 +237,7 @@ class SiteCreationActivity : LocaleAwareActivity(), } DOMAINS -> SiteCreationDomainsFragment.newInstance(screenTitle) PROGRESS -> SiteCreationProgressFragment.newInstance(target.wizardState) - SITE_PREVIEW -> SiteCreationPreviewFragment.newInstance( - screenTitle, - target.wizardState, - ) + SITE_PREVIEW -> SiteCreationPreviewFragment.newInstance(screenTitle, target.wizardState) } showFragment(fragment, target.wizardStep.toString(), target.wizardStep != SITE_PREVIEW) } From b80bd1625897d2a89231e6694aba30587e399b37 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 21:57:54 +0100 Subject: [PATCH 060/169] Fix: navigation after ok click --- .../previews/SiteCreationPreviewFragment.kt | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 83bd56dc12fb..1a0079dd812b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -20,7 +20,7 @@ import org.wordpress.android.WordPress import org.wordpress.android.databinding.SiteCreationFormScreenBinding import org.wordpress.android.databinding.SiteCreationPreviewScreenBinding import org.wordpress.android.databinding.SiteCreationPreviewScreenDefaultBinding -import org.wordpress.android.ui.accounts.HelpActivity +import org.wordpress.android.ui.accounts.HelpActivity.Origin import org.wordpress.android.ui.sitecreation.SiteCreationBaseFormFragment import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener @@ -87,7 +87,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), observeState() observePreview(siteCreationPreviewWebViewContainer.sitePreviewWebView) observeHelpClicks(requireActivity() as OnHelpClickedListener) - observeDismissClicks(requireActivity() as SitePreviewScreenListener) + observeOkClicks(requireActivity() as SitePreviewScreenListener) okButton.setOnClickListener { viewModel.onOkButtonClicked() } } } @@ -122,15 +122,11 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } private fun observeHelpClicks(listener: OnHelpClickedListener) { - viewModel.onHelpClicked.observe(this) { - listener.onHelpClicked(HelpActivity.Origin.SITE_CREATION_CREATED) - } + viewModel.onHelpClicked.observe(this) { listener.onHelpClicked(Origin.SITE_CREATION_CREATED) } } - private fun observeDismissClicks(listener: SitePreviewScreenListener) { - viewModel.onOkButtonClicked.observe(this) { createSiteState -> - createSiteState?.let { listener.onPreviewScreenClosed() } - } + private fun observeOkClicks(listener: SitePreviewScreenListener) { + viewModel.onOkButtonClicked.observe(this) { listener.onPreviewScreenClosed() } } private fun SiteCreationPreviewScreenDefaultBinding.updateContentLayout( From a1a455b48982b95ee6204211acd4ad1a1b026f85 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 22:00:18 +0100 Subject: [PATCH 061/169] Refactor: rename vars and params related to state to use the same word --- .../sitecreation/progress/SiteCreationProgressFragment.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt index 69411d20fc4c..e2cc4975fb1f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt @@ -79,7 +79,7 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc private fun init(savedInstanceState: Bundle?) { (requireActivity() as AppCompatActivity).supportActionBar?.hide() - viewModel.start(requireArguments()[ARG_DATA] as SiteCreationState, savedInstanceState) + viewModel.start(requireArguments()[ARG_STATE] as SiteCreationState, savedInstanceState) } private fun SiteCreationProgressScreenBinding.observeState() { @@ -204,12 +204,12 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc companion object { const val TAG = "site_creation_progress_fragment_tag" - private const val ARG_DATA = "arg_site_creation_data" + private const val ARG_STATE = "arg_site_creation_state" - fun newInstance(siteCreationData: SiteCreationState) = SiteCreationProgressFragment() + fun newInstance(siteCreationState: SiteCreationState) = SiteCreationProgressFragment() .apply { arguments = Bundle().apply { - putParcelable(ARG_DATA, siteCreationData) + putParcelable(ARG_STATE, siteCreationState) } } } From 02716b368d8b27ed1a6fa0b78aa26b7141c5b83d Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 22:12:24 +0100 Subject: [PATCH 062/169] Refactor: remove unneeded siteCreationCompleted bool field --- .../android/ui/sitecreation/SiteCreationMainVM.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 65099a20b2f4..88a206d0e281 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -21,6 +21,7 @@ import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleEmpty import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource @@ -44,7 +45,6 @@ import javax.inject.Inject const val TAG_WARNING_DIALOG = "back_pressed_warning_dialog" const val KEY_CURRENT_STEP = "key_current_step" -const val KEY_SITE_CREATION_COMPLETED = "key_site_creation_completed" const val KEY_SITE_CREATION_STATE = "key_site_creation_state" @Parcelize @@ -97,7 +97,6 @@ class SiteCreationMainVM @Inject constructor( var siteCreationDisabled: Boolean = false private var isStarted = false - private var siteCreationCompleted = false private lateinit var siteCreationState: SiteCreationState @@ -142,7 +141,6 @@ class SiteCreationMainVM @Inject constructor( else showSiteCreationNextStep() } else { - siteCreationCompleted = savedInstanceState.getBoolean(KEY_SITE_CREATION_COMPLETED, false) siteCreationState = requireNotNull(savedInstanceState.getParcelable(KEY_SITE_CREATION_STATE)) val currentStepIndex = savedInstanceState.getInt(KEY_CURRENT_STEP) wizardManager.setCurrentStepIndex(currentStepIndex) @@ -184,7 +182,6 @@ class SiteCreationMainVM @Inject constructor( } fun writeToBundle(outState: Bundle) { - outState.putBoolean(KEY_SITE_CREATION_COMPLETED, siteCreationCompleted) outState.putInt(KEY_CURRENT_STEP, wizardManager.currentStep) outState.putParcelable(KEY_SITE_CREATION_STATE, siteCreationState) } @@ -216,7 +213,7 @@ class SiteCreationMainVM @Inject constructor( fun onBackPressed() { return if (wizardManager.isLastStep()) { - if (siteCreationCompleted) { + if (siteCreationState.result is Completed) { exitFlow(false) } else { _dialogAction.value = DialogHolder( @@ -268,7 +265,6 @@ class SiteCreationMainVM @Inject constructor( fun onSiteCreationCompleted(result: SiteCreationResult) { siteCreationState = siteCreationState.copy(result = result) - siteCreationCompleted = true wizardManager.showNextStep() } From ae1c52c0ebf5f53697ca53067fc26414c69d0e53 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 22:17:26 +0100 Subject: [PATCH 063/169] Test: adapt test after removing field for completion --- .../wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index ec52b25bf712..d1b894c75902 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -197,7 +197,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun flowExitedOnBackPressedWhenLastStepAndSiteCreationCompleted() { whenever(wizardManager.isLastStep()).thenReturn(true) - viewModel.onSiteCreationCompleted(mock()) + viewModel.onSiteCreationCompleted(mock()) viewModel.onBackPressed() verify(wizardExitedObserver).onChanged(anyOrNull()) } From 4725d082c86a9c59209c3890249859a653324c2d Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 22:36:21 +0100 Subject: [PATCH 064/169] Refactor: use requireArguments to get screen title --- .../ui/sitecreation/domains/SiteCreationDomainsFragment.kt | 5 +---- .../ui/sitecreation/previews/SiteCreationPreviewFragment.kt | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt index 63f0fac932e1..e912a9e1ac43 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt @@ -49,10 +49,7 @@ class SiteCreationDomainsFragment : SiteCreationBaseFormFragment() { return R.layout.site_creation_domains_screen } - @Suppress("UseCheckOrError") - override val screenTitle: String - get() = arguments?.getString(EXTRA_SCREEN_TITLE) - ?: throw IllegalStateException("Required argument screen title is missing.") + override val screenTitle get() = requireArguments()[EXTRA_SCREEN_TITLE] as String override fun setBindingViewStubListener(parentBinding: SiteCreationFormScreenBinding) { parentBinding.siteCreationFormContentStub.setOnInflateListener { _, inflated -> diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 1a0079dd812b..a232520dc160 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -21,6 +21,7 @@ import org.wordpress.android.databinding.SiteCreationFormScreenBinding import org.wordpress.android.databinding.SiteCreationPreviewScreenBinding import org.wordpress.android.databinding.SiteCreationPreviewScreenDefaultBinding import org.wordpress.android.ui.accounts.HelpActivity.Origin +import org.wordpress.android.ui.sitecreation.SiteCreationActivity.Companion.ARG_STATE import org.wordpress.android.ui.sitecreation.SiteCreationBaseFormFragment import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener @@ -34,7 +35,6 @@ import org.wordpress.android.util.URLFilteredWebViewClient import org.wordpress.android.widgets.NestedWebView import javax.inject.Inject -private const val ARG_STATE = "arg_site_creation_state" private const val SLIDE_IN_ANIMATION_DURATION = 450L @AndroidEntryPoint @@ -73,8 +73,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), override fun getContentLayout() = R.layout.site_creation_preview_screen - override val screenTitle: String - get() = requireNotNull(arguments?.getString(EXTRA_SCREEN_TITLE)) { "Missing required argument 'screenTitle'." } + override val screenTitle get() = requireArguments()[EXTRA_SCREEN_TITLE] as String override fun setBindingViewStubListener(parentBinding: SiteCreationFormScreenBinding) { parentBinding.siteCreationFormContentStub.setOnInflateListener { _, inflated -> From e144461d37f44c429c73b691fb77f67be0dded32 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 12 Mar 2023 23:45:54 +0100 Subject: [PATCH 065/169] Refactor: hoist ARG_STATE to activity --- .../wordpress/android/ui/sitecreation/SiteCreationActivity.kt | 1 + .../ui/sitecreation/progress/SiteCreationProgressFragment.kt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index b67b14fcf5ae..e4fe78ce7682 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -295,5 +295,6 @@ class SiteCreationActivity : LocaleAwareActivity(), companion object { const val ARG_CREATE_SITE_SOURCE = "ARG_CREATE_SITE_SOURCE" + const val ARG_STATE = "ARG_SITE_CREATION_STATE" } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt index e2cc4975fb1f..c1062d3ce97a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt @@ -16,6 +16,7 @@ import org.wordpress.android.databinding.FullscreenErrorWithRetryBinding import org.wordpress.android.databinding.SiteCreationProgressCreatingSiteBinding import org.wordpress.android.databinding.SiteCreationProgressScreenBinding import org.wordpress.android.ui.accounts.HelpActivity +import org.wordpress.android.ui.sitecreation.SiteCreationActivity.Companion.ARG_STATE import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error @@ -204,7 +205,6 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc companion object { const val TAG = "site_creation_progress_fragment_tag" - private const val ARG_STATE = "arg_site_creation_state" fun newInstance(siteCreationState: SiteCreationState) = SiteCreationProgressFragment() .apply { From 999fd9dabe56ccb889786a3fbbd7c5a375bc06fc Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 00:29:37 +0100 Subject: [PATCH 066/169] Refactor: replace progress screen listener with observer in activity vm --- .../ui/sitecreation/SiteCreationActivity.kt | 15 ++++++++------- .../progress/ProgressScreenListener.kt | 8 -------- .../progress/SiteCreationProgressFragment.kt | 17 ++++------------- ...odel.kt => SiteCreationProgressViewModel.kt} | 0 4 files changed, 12 insertions(+), 28 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt rename WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/{SiteProgressViewModel.kt => SiteCreationProgressViewModel.kt} (100%) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index e4fe78ce7682..e658b6d9a6eb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -42,8 +42,8 @@ import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.previews.SiteCreationPreviewFragment import org.wordpress.android.ui.sitecreation.previews.SitePreviewScreenListener -import org.wordpress.android.ui.sitecreation.progress.ProgressScreenListener import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressFragment +import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel import org.wordpress.android.ui.sitecreation.sitename.SiteCreationSiteNameFragment import org.wordpress.android.ui.sitecreation.sitename.SiteCreationSiteNameViewModel import org.wordpress.android.ui.sitecreation.sitename.SiteNameScreenListener @@ -65,7 +65,6 @@ class SiteCreationActivity : LocaleAwareActivity(), IntentsScreenListener, SiteNameScreenListener, DomainsScreenListener, - ProgressScreenListener, SitePreviewScreenListener, OnHelpClickedListener, BasicDialogPositiveClickInterface, @@ -80,6 +79,7 @@ class SiteCreationActivity : LocaleAwareActivity(), private val siteCreationIntentsViewModel: SiteCreationIntentsViewModel by viewModels() private val siteCreationSiteNameViewModel: SiteCreationSiteNameViewModel by viewModels() private val jetpackFullScreenViewModel: JetpackFeatureFullScreenOverlayViewModel by viewModels() + private val progressViewModel: SiteProgressViewModel by viewModels() @Inject internal lateinit var jetpackFeatureRemovalOverlayUtil: JetpackFeatureRemovalOverlayUtil @Inject @@ -162,7 +162,12 @@ class SiteCreationActivity : LocaleAwareActivity(), hppViewModel.onDesignActionPressed.observe(this, Observer { design -> mainViewModel.onSiteDesignSelected(design.template) }) - + progressViewModel.onCancelWizardClicked.observe(this) { result -> + mainViewModel.onProgressOrPreviewFinished(result) + } + progressViewModel.onSiteCreationCompleted.observe(this) { result -> + mainViewModel.onSiteCreationCompleted(result) + } observeOverlayEvents() } @@ -215,10 +220,6 @@ class SiteCreationActivity : LocaleAwareActivity(), mainViewModel.onDomainsScreenFinished(domain) } - override fun onProgressCompleted(result: SiteCreationResult) = mainViewModel.onSiteCreationCompleted(result) - - override fun onProgressStopped(result: SiteCreationResult) = mainViewModel.onProgressOrPreviewFinished(result) - override fun onPreviewScreenClosed() = mainViewModel.onProgressOrPreviewFinished() override fun onHelpClicked(origin: Origin) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt deleted file mode 100644 index 68efc6f18b6d..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/ProgressScreenListener.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.wordpress.android.ui.sitecreation.progress - -import org.wordpress.android.ui.sitecreation.SiteCreationResult - -interface ProgressScreenListener { - fun onProgressStopped(result: SiteCreationResult) - fun onProgressCompleted(result: SiteCreationResult) -} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt index c1062d3ce97a..8f788a3158db 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt @@ -9,7 +9,7 @@ import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels +import androidx.fragment.app.activityViewModels import dagger.hilt.android.AndroidEntryPoint import org.wordpress.android.R import org.wordpress.android.databinding.FullscreenErrorWithRetryBinding @@ -41,11 +41,10 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc private var animatorSet: AnimatorSet? = null private lateinit var binding: SiteCreationProgressScreenBinding - private val viewModel: SiteProgressViewModel by viewModels() + private val viewModel: SiteProgressViewModel by activityViewModels() override fun onAttach(context: Context) { super.onAttach(context) - check(context is ProgressScreenListener) { "Parent activity must implement ProgressScreenListener." } check(context is OnHelpClickedListener) { "Parent activity must implement OnHelpClickedListener." } } @@ -69,8 +68,7 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc binding = SiteCreationProgressScreenBinding.bind(view).apply { observeState() observeHelpClicks(requireActivity() as OnHelpClickedListener) - observeDismissClicks(requireActivity() as ProgressScreenListener) - observeSiteCreationService(requireActivity() as ProgressScreenListener) + observeSiteCreationService() fullscreenErrorWithRetry.setOnClickListeners() } @@ -96,7 +94,7 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc } } - private fun observeSiteCreationService(listener: ProgressScreenListener) { + private fun observeSiteCreationService() { viewModel.startCreateSiteService.observe(viewLifecycleOwner) { startServiceData -> startServiceData?.let { SiteCreationService.createSite(requireNotNull(activity), it.previousState, it.serviceData) @@ -104,13 +102,6 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc } viewModel.onSiteCreationCompleted.observe(viewLifecycleOwner) { view?.announceForAccessibility(getString(R.string.new_site_creation_preview_title)) - listener.onProgressCompleted(it) - } - } - - private fun observeDismissClicks(listener: ProgressScreenListener) { - viewModel.onCancelWizardClicked.observe(viewLifecycleOwner) { createSiteState -> - createSiteState?.let { listener.onProgressStopped(it) } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt similarity index 100% rename from WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt From 23d555438be66db694471f9789d69a088206617b Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 00:35:34 +0100 Subject: [PATCH 067/169] Refactor: replace progress screen listener with observer in activity vm --- .../android/ui/sitecreation/SiteCreationActivity.kt | 9 +++++---- .../previews/SiteCreationPreviewFragment.kt | 10 ++-------- .../sitecreation/previews/SitePreviewScreenListener.kt | 5 ----- 3 files changed, 7 insertions(+), 17 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index e658b6d9a6eb..25a66addaa0f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -41,7 +41,7 @@ import org.wordpress.android.ui.sitecreation.domains.SiteCreationDomainsFragment import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.previews.SiteCreationPreviewFragment -import org.wordpress.android.ui.sitecreation.previews.SitePreviewScreenListener +import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressFragment import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel import org.wordpress.android.ui.sitecreation.sitename.SiteCreationSiteNameFragment @@ -65,7 +65,6 @@ class SiteCreationActivity : LocaleAwareActivity(), IntentsScreenListener, SiteNameScreenListener, DomainsScreenListener, - SitePreviewScreenListener, OnHelpClickedListener, BasicDialogPositiveClickInterface, BasicDialogNegativeClickInterface { @@ -80,6 +79,7 @@ class SiteCreationActivity : LocaleAwareActivity(), private val siteCreationSiteNameViewModel: SiteCreationSiteNameViewModel by viewModels() private val jetpackFullScreenViewModel: JetpackFeatureFullScreenOverlayViewModel by viewModels() private val progressViewModel: SiteProgressViewModel by viewModels() + private val previewViewModel: SitePreviewViewModel by viewModels() @Inject internal lateinit var jetpackFeatureRemovalOverlayUtil: JetpackFeatureRemovalOverlayUtil @Inject @@ -168,6 +168,9 @@ class SiteCreationActivity : LocaleAwareActivity(), progressViewModel.onSiteCreationCompleted.observe(this) { result -> mainViewModel.onSiteCreationCompleted(result) } + previewViewModel.onOkButtonClicked.observe(this) { + mainViewModel.onProgressOrPreviewFinished() + } observeOverlayEvents() } @@ -220,8 +223,6 @@ class SiteCreationActivity : LocaleAwareActivity(), mainViewModel.onDomainsScreenFinished(domain) } - override fun onPreviewScreenClosed() = mainViewModel.onProgressOrPreviewFinished() - override fun onHelpClicked(origin: Origin) { ActivityLauncher.viewHelp(this, origin, null, null) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index a232520dc160..2d7b9fa67106 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -13,7 +13,7 @@ import android.view.View.OnLayoutChangeListener import android.view.animation.DecelerateInterpolator import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat -import androidx.fragment.app.viewModels +import androidx.fragment.app.activityViewModels import dagger.hilt.android.AndroidEntryPoint import org.wordpress.android.R import org.wordpress.android.WordPress @@ -46,11 +46,10 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), private val isLandscape get() = resources.configuration.orientation == ORIENTATION_LANDSCAPE private lateinit var binding: SiteCreationPreviewScreenBinding - private val viewModel: SitePreviewViewModel by viewModels() + private val viewModel: SitePreviewViewModel by activityViewModels() override fun onAttach(context: Context) { super.onAttach(context) - check(context is SitePreviewScreenListener) { "Parent activity must implement SitePreviewScreenListener." } check(context is OnHelpClickedListener) { "Parent activity must implement OnHelpClickedListener." } } @@ -86,7 +85,6 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), observeState() observePreview(siteCreationPreviewWebViewContainer.sitePreviewWebView) observeHelpClicks(requireActivity() as OnHelpClickedListener) - observeOkClicks(requireActivity() as SitePreviewScreenListener) okButton.setOnClickListener { viewModel.onOkButtonClicked() } } } @@ -124,10 +122,6 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), viewModel.onHelpClicked.observe(this) { listener.onHelpClicked(Origin.SITE_CREATION_CREATED) } } - private fun observeOkClicks(listener: SitePreviewScreenListener) { - viewModel.onOkButtonClicked.observe(this) { listener.onPreviewScreenClosed() } - } - private fun SiteCreationPreviewScreenDefaultBinding.updateContentLayout( sitePreviewData: SitePreviewData, isFirstContent: Boolean = false, diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt deleted file mode 100644 index cced69180e31..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewScreenListener.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.wordpress.android.ui.sitecreation.previews - -interface SitePreviewScreenListener { - fun onPreviewScreenClosed() -} From 806b67cbbe6fb6dbb2acbbb963586402dd33258f Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 04:55:26 +0100 Subject: [PATCH 068/169] Fix: lint errors for checkstyle --- .../wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt | 1 - .../android/ui/sitecreation/previews/SitePreviewViewModelTest.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index d1b894c75902..2ba6d738dc5f 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -344,7 +344,6 @@ class SiteCreationMainVMTest : BaseUnitTest() { val bundle = mock() viewModel.writeToBundle(bundle) // used this to assert on the private siteCreationState field verify(bundle).putParcelable(eq(KEY_SITE_CREATION_STATE), argWhere { it.result == expected }) - } @Test diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index 3291d1b08981..727c7091fe53 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -31,7 +31,6 @@ private val SITE_CREATION_STATE = SiteCreationState(segmentId = 1, siteDesign = @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) class SitePreviewViewModelTest : BaseUnitTest() { - @Mock private lateinit var urlUtils: UrlUtilsWrapper From dac0dc3cf893bb5403daa8d445f0307b36ac426c Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 04:58:33 +0100 Subject: [PATCH 069/169] Fix: lint errors for detekt --- .../progress/SiteProgressViewModelTest.kt | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt index b2e948ed47c8..ff11420837c1 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -53,13 +53,13 @@ import kotlin.test.assertEquals import kotlin.test.assertIs import kotlin.test.assertNotNull -private const val siteUrl = "test.wordpress.com" -private const val siteRemoteId = 1L -private val siteNotInLocalDb = NotInLocalDb(siteRemoteId, false) -private val successServiceState = SiteCreationServiceState(SUCCESS, Pair(siteRemoteId, siteUrl)) -private val errorServiceState = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) -private val successResponse = OnSiteChanged(1) -private val errorResponse = OnSiteChanged(0).apply { error = SiteError(SiteErrorType.GENERIC_ERROR) } +private const val URL = "test.wordpress.com" +private const val SITE_REMOTE_ID = 1L +private val RESULT_NOT_IN_LOCAL_DB = NotInLocalDb(SITE_REMOTE_ID, false) +private val SUCCESS_SERVICE_STATE = SiteCreationServiceState(SUCCESS, Pair(SITE_REMOTE_ID, URL)) +private val ERROR_SERVICE_STATE = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) +private val SUCCESS_RESPONSE = OnSiteChanged(1) +private val ERROR_RESPONSE = OnSiteChanged(0).apply { error = SiteError(SiteErrorType.GENERIC_ERROR) } @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) @@ -100,8 +100,8 @@ class SiteProgressViewModelTest : BaseUnitTest() { viewModel.onSiteCreationCompleted.observeForever(onSiteCreationCompletedObserver) whenever(networkUtils.isNetworkAvailable()).thenReturn(true) - whenever(urlUtils.removeScheme(siteUrl)).thenReturn(siteUrl) - whenever(siteStore.getSiteBySiteId(siteRemoteId)).thenReturn(SiteModel().apply { id = 1; url = siteUrl }) + whenever(urlUtils.removeScheme(URL)).thenReturn(URL) + whenever(siteStore.getSiteBySiteId(SITE_REMOTE_ID)).thenReturn(SiteModel().apply { id = 1; url = URL }) } @Test @@ -111,14 +111,14 @@ class SiteProgressViewModelTest : BaseUnitTest() { } @Test - fun `on start shows progress when restoring SiteNotCreated`() = testWith(successResponse) { + fun `on start shows progress when restoring SiteNotCreated`() = testWith(SUCCESS_RESPONSE) { startViewModel(NotCreated) assertIs(viewModel.uiState.value) } @Test - fun `on start shows progress when restoring SiteNotInLocalDb`() = testWith(errorResponse) { - startViewModel(siteNotInLocalDb) + fun `on start shows progress when restoring SiteNotInLocalDb`() = testWith(ERROR_RESPONSE) { + startViewModel(RESULT_NOT_IN_LOCAL_DB) assertIs(viewModel.uiState.value) } @@ -143,9 +143,9 @@ class SiteProgressViewModelTest : BaseUnitTest() { } @Test - fun `on start fetches site by remote id when restoring SiteNotInLocalDb`() = testWith(successResponse) { - startViewModel(siteNotInLocalDb) - verify(fetchWpComSiteUseCase).fetchSiteWithRetry(siteRemoteId) + fun `on start fetches site by remote id when restoring SiteNotInLocalDb`() = testWith(SUCCESS_RESPONSE) { + startViewModel(RESULT_NOT_IN_LOCAL_DB) + verify(fetchWpComSiteUseCase).fetchSiteWithRetry(SITE_REMOTE_ID) } @Test @@ -175,9 +175,9 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on retry click emits service event with the previous result`() { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(errorServiceState) + viewModel.onSiteCreationServiceStateUpdated(ERROR_SERVICE_STATE) viewModel.retry() - assertEquals(viewModel.startCreateSiteService.value?.previousState, errorServiceState.payload) + assertEquals(viewModel.startCreateSiteService.value?.previousState, ERROR_SERVICE_STATE.payload) } @Test @@ -201,24 +201,24 @@ class SiteProgressViewModelTest : BaseUnitTest() { } @Test - fun `on service success fetches site by remote id`() = testWith(successResponse) { + fun `on service success fetches site by remote id`() = testWith(SUCCESS_RESPONSE) { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(successServiceState) - verify(fetchWpComSiteUseCase).fetchSiteWithRetry(siteRemoteId) + viewModel.onSiteCreationServiceStateUpdated(SUCCESS_SERVICE_STATE) + verify(fetchWpComSiteUseCase).fetchSiteWithRetry(SITE_REMOTE_ID) } @Test - fun `on service success will emit completion event when animations end`() = testWith(successResponse) { + fun `on service success will emit completion event when animations end`() = testWith(SUCCESS_RESPONSE) { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(successServiceState) + viewModel.onSiteCreationServiceStateUpdated(SUCCESS_SERVICE_STATE) advanceUntilIdle() verify(onSiteCreationCompletedObserver).onChanged(any()) } @Test - fun `on service failure will emit completion event when animations end`() = testWith(errorResponse) { + fun `on service failure will emit completion event when animations end`() = testWith(ERROR_RESPONSE) { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(successServiceState) + viewModel.onSiteCreationServiceStateUpdated(SUCCESS_SERVICE_STATE) advanceUntilIdle() verify(onSiteCreationCompletedObserver).onChanged(any()) } @@ -226,14 +226,14 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on service failure shows error`() { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(errorServiceState) + viewModel.onSiteCreationServiceStateUpdated(ERROR_SERVICE_STATE) assertIs(viewModel.uiState.value) } // region Helpers private fun testWith(response: OnSiteChanged, block: suspend CoroutineScope.() -> Unit) = test { - whenever(fetchWpComSiteUseCase.fetchSiteWithRetry(siteRemoteId)).thenReturn(response) + whenever(fetchWpComSiteUseCase.fetchSiteWithRetry(SITE_REMOTE_ID)).thenReturn(response) block() } @@ -242,7 +242,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { SiteCreationState( segmentId = 1, siteDesign = defaultTemplateSlug, - domain = DomainModel(siteUrl, true, "", 1) + domain = DomainModel(URL, true, "", 1) ), bundle.apply { restoredState?.let { whenever(getParcelable(KEY_CREATE_SITE_STATE)) doReturn it } From 0fb5910344acead38b6cfc0e7e7e0f6dc4d3074d Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 10:15:45 +0100 Subject: [PATCH 070/169] Refactor: remove unneeded help click code from preview step --- .../wordpress/android/ui/accounts/HelpActivity.kt | 1 - .../previews/SiteCreationPreviewFragment.kt | 14 +------------- .../sitecreation/previews/SitePreviewViewModel.kt | 5 ----- .../previews/SitePreviewViewModelTest.kt | 4 ---- 4 files changed, 1 insertion(+), 23 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/HelpActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/accounts/HelpActivity.kt index 941e633b3696..5e31c8ee9575 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/HelpActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/HelpActivity.kt @@ -354,7 +354,6 @@ class HelpActivity : LocaleAwareActivity() { SIGNUP_MAGIC_LINK("origin:signup-magic-link"), SIGNUP_CONFIRMATION("origin:signup-confirmation"), SITE_CREATION_CREATING("origin:site-create-creating"), - SITE_CREATION_CREATED("origin:site-create-created"), SITE_CREATION_SEGMENTS("origin:site-create-site-segments"), SITE_CREATION_VERTICALS("origin:site-create-site-verticals"), SITE_CREATION_DOMAINS("origin:site-create-domains"), diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 2d7b9fa67106..5b68ed308f66 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -20,11 +20,9 @@ import org.wordpress.android.WordPress import org.wordpress.android.databinding.SiteCreationFormScreenBinding import org.wordpress.android.databinding.SiteCreationPreviewScreenBinding import org.wordpress.android.databinding.SiteCreationPreviewScreenDefaultBinding -import org.wordpress.android.ui.accounts.HelpActivity.Origin import org.wordpress.android.ui.sitecreation.SiteCreationActivity.Companion.ARG_STATE import org.wordpress.android.ui.sitecreation.SiteCreationBaseFormFragment import org.wordpress.android.ui.sitecreation.SiteCreationState -import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewData import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewLoadingShimmerState @@ -48,11 +46,6 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), private lateinit var binding: SiteCreationPreviewScreenBinding private val viewModel: SitePreviewViewModel by activityViewModels() - override fun onAttach(context: Context) { - super.onAttach(context) - check(context is OnHelpClickedListener) { "Parent activity must implement OnHelpClickedListener." } - } - @Suppress("DEPRECATION", "OVERRIDE_DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) @@ -84,7 +77,6 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), binding.siteCreationPreviewScreenDefault.run { observeState() observePreview(siteCreationPreviewWebViewContainer.sitePreviewWebView) - observeHelpClicks(requireActivity() as OnHelpClickedListener) okButton.setOnClickListener { viewModel.onOkButtonClicked() } } } @@ -118,10 +110,6 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), } } - private fun observeHelpClicks(listener: OnHelpClickedListener) { - viewModel.onHelpClicked.observe(this) { listener.onHelpClicked(Origin.SITE_CREATION_CREATED) } - } - private fun SiteCreationPreviewScreenDefaultBinding.updateContentLayout( sitePreviewData: SitePreviewData, isFirstContent: Boolean = false, @@ -176,7 +164,7 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), override fun onWebViewReceivedError() = viewModel.onWebViewError() - override fun onHelp() = viewModel.onHelpClicked() + override fun onHelp() = Unit // noop private fun SiteCreationPreviewScreenDefaultBinding.animateContentTransition() { contentLayout.addOnLayoutChangeListener( diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 78016d0df37c..4e24d4f8f31f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -50,9 +50,6 @@ class SitePreviewViewModel @Inject constructor( private val _preloadPreview: MutableLiveData = MutableLiveData() val preloadPreview: LiveData = _preloadPreview - private val _onHelpClicked = SingleLiveEvent() - val onHelpClicked: LiveData = _onHelpClicked - private val _onOkButtonClicked = SingleLiveEvent() val onOkButtonClicked: LiveData = _onOkButtonClicked @@ -69,8 +66,6 @@ class SitePreviewViewModel @Inject constructor( startPreLoadingWebView() } - fun onHelpClicked() = _onHelpClicked.call() - fun onOkButtonClicked() { tracker.trackPreviewOkButtonTapped() _onOkButtonClicked.call() diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index 727c7091fe53..1afbb9c37ecc 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -40,9 +40,6 @@ class SitePreviewViewModelTest : BaseUnitTest() { @Mock private lateinit var uiStateObserver: Observer - @Mock - private lateinit var onHelpedClickedObserver: Observer - @Mock private lateinit var onOkClickedObserver: Observer @@ -60,7 +57,6 @@ class SitePreviewViewModelTest : BaseUnitTest() { testDispatcher() ) viewModel.uiState.observeForever(uiStateObserver) - viewModel.onHelpClicked.observeForever(onHelpedClickedObserver) viewModel.onOkButtonClicked.observeForever(onOkClickedObserver) viewModel.preloadPreview.observeForever(preloadPreviewObserver) whenever(urlUtils.extractSubDomain(URL)).thenReturn(SUB_DOMAIN) From 21e89bdf87da79591d1516df52c5e610b645573e Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 10:58:50 +0100 Subject: [PATCH 071/169] Refactor: remove error layout and content container from preview screen --- .../previews/SiteCreationPreviewFragment.kt | 2 - .../previews/SitePreviewViewModel.kt | 5 -- .../site_creation_preview_screen_default.xml | 75 +++++++---------- .../site_creation_preview_screen_default.xml | 84 ++++++++----------- 4 files changed, 69 insertions(+), 97 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 5b68ed308f66..49cfb57890ba 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -89,8 +89,6 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), is SitePreviewWebErrorUiState -> updateContentLayout(ui.data) is SitePreviewLoadingShimmerState -> updateContentLayout(ui.data, isFirstContent = true) } - uiHelpers.updateVisibility(contentLayout, contentLayoutVisibility) - uiHelpers.updateVisibility(fullscreenErrorWithRetry.errorLayout, fullscreenErrorLayoutVisibility) siteCreationPreviewWebViewContainer.apply { uiHelpers.updateVisibility(sitePreviewWebView, webViewVisibility) uiHelpers.updateVisibility(sitePreviewWebError, webViewErrorVisibility) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 4e24d4f8f31f..de0800cbc1a7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -135,26 +135,21 @@ class SitePreviewViewModel @Inject constructor( } sealed class SitePreviewUiState( - val contentLayoutVisibility: Boolean = false, val webViewVisibility: Boolean = false, val webViewErrorVisibility: Boolean = false, val shimmerVisibility: Boolean = false, - val fullscreenErrorLayoutVisibility: Boolean = false ) { data class SitePreviewContentUiState(val data: SitePreviewData) : SitePreviewUiState( - contentLayoutVisibility = true, webViewVisibility = true, webViewErrorVisibility = false ) data class SitePreviewWebErrorUiState(val data: SitePreviewData) : SitePreviewUiState( - contentLayoutVisibility = true, webViewVisibility = false, webViewErrorVisibility = true ) data class SitePreviewLoadingShimmerState(val data: SitePreviewData) : SitePreviewUiState( - contentLayoutVisibility = true, shimmerVisibility = true ) } diff --git a/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml b/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml index 3489a7fa59de..4b75692ee81d 100644 --- a/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml +++ b/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml @@ -1,56 +1,45 @@ - - - - - - - - - - + android:layout_alignParentEnd="true" + android:layout_centerVertical="true" + android:clipToPadding="false" + android:gravity="center" + android:orientation="vertical" + android:paddingStart="@dimen/margin_large" + android:paddingEnd="@dimen/margin_large"> + + - + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/margin_extra_large" + android:text="@string/dialog_button_ok" + tools:ignore="InconsistentLayout" /> + + + diff --git a/WordPress/src/main/res/layout/site_creation_preview_screen_default.xml b/WordPress/src/main/res/layout/site_creation_preview_screen_default.xml index 7d8aef1b8691..97be321cc9cd 100644 --- a/WordPress/src/main/res/layout/site_creation_preview_screen_default.xml +++ b/WordPress/src/main/res/layout/site_creation_preview_screen_default.xml @@ -2,61 +2,51 @@ + android:id="@+id/site_creation_preview_header_item" + layout="@layout/site_creation_preview_header_item" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:layout_marginBottom="@dimen/margin_extra_medium_large" + android:layout_marginEnd="@dimen/margin_large" + android:layout_marginStart="@dimen/margin_large" + android:layout_marginTop="@dimen/margin_extra_medium_large" /> - - - + android:layout_height="match_parent" + android:layout_above="@+id/sitePreviewOkButtonContainer" + android:layout_below="@id/site_creation_preview_header_item" + android:layout_marginBottom="@dimen/negative_margin_medium" + android:layout_marginLeft="@dimen/site_creation_preview_web_view_side_margin" + android:layout_marginRight="@dimen/site_creation_preview_web_view_side_margin" /> - + - - - - - + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginEnd="@dimen/margin_extra_large" + android:layout_marginStart="@dimen/margin_extra_large" + android:text="@string/dialog_button_ok" /> + From 3f5507e3caa4403f226f8c7708f998717cd54c9a Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 12:32:52 +0100 Subject: [PATCH 072/169] Refactor: unwrap site creation state in preview vm --- .../previews/SitePreviewViewModel.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index de0800cbc1a7..b30a5ca7021c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -41,7 +41,9 @@ class SitePreviewViewModel @Inject constructor( private var isStarted = false private var webviewFullyLoadedTracked = false - private lateinit var siteCreationState: SiteCreationState + private var siteTitle: String? = null + private var siteDesign: String? = null + private lateinit var result: SiteCreationResult private var urlWithoutScheme: String? = null private val _uiState: MutableLiveData = MutableLiveData() @@ -61,8 +63,10 @@ class SitePreviewViewModel @Inject constructor( fun start(siteCreationState: SiteCreationState) { if (isStarted) return isStarted = true - this.siteCreationState = siteCreationState - this.urlWithoutScheme = siteCreationState.domain?.domainName + siteDesign = siteCreationState.siteDesign + urlWithoutScheme = siteCreationState.domain?.domainName + siteTitle = siteCreationState.siteName + result = siteCreationState.result startPreLoadingWebView() } @@ -72,7 +76,7 @@ class SitePreviewViewModel @Inject constructor( } private fun startPreLoadingWebView() { - tracker.trackPreviewLoading(siteCreationState.siteDesign) + tracker.trackPreviewLoading(siteDesign) launch { /** * If the webview is still not loaded after some delay, we'll show the loading shimmer animation instead @@ -80,7 +84,7 @@ class SitePreviewViewModel @Inject constructor( */ withContext(mainDispatcher) { if (uiState.value !is SitePreviewContentUiState) { - tracker.trackPreviewWebviewShown(siteCreationState.siteDesign) + tracker.trackPreviewWebviewShown(siteDesign) updateUiState(SitePreviewLoadingShimmerState(createSitePreviewData())) } } @@ -99,7 +103,7 @@ class SitePreviewViewModel @Inject constructor( fun onUrlLoaded() { if (!webviewFullyLoadedTracked) { webviewFullyLoadedTracked = true - tracker.trackPreviewWebviewFullyLoaded(siteCreationState.siteDesign) + tracker.trackPreviewWebviewFullyLoaded(siteDesign) } /** * Update the ui state if the loading or error screen is being shown. From eaa6eb463f987323fc78b2c07440139a6582008c Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 14:26:15 +0100 Subject: [PATCH 073/169] Refactor: move fetching to the preview step to improve the UX --- .../ui/sitecreation/SiteCreationActivity.kt | 4 +- .../previews/SitePreviewViewModel.kt | 49 ++++++++++++++-- .../progress/SiteCreationProgressViewModel.kt | 58 ++++--------------- 3 files changed, 56 insertions(+), 55 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 25a66addaa0f..e15309b8c33b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -168,8 +168,8 @@ class SiteCreationActivity : LocaleAwareActivity(), progressViewModel.onSiteCreationCompleted.observe(this) { result -> mainViewModel.onSiteCreationCompleted(result) } - previewViewModel.onOkButtonClicked.observe(this) { - mainViewModel.onProgressOrPreviewFinished() + previewViewModel.onOkButtonClicked.observe(this) { result -> + mainViewModel.onProgressOrPreviewFinished(result) } observeOverlayEvents() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index b30a5ca7021c..94fab01aef03 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -9,13 +9,19 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD +import org.wordpress.android.ui.sitecreation.SiteCreationResult +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewLoadingShimmerState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewWebErrorUiState +import org.wordpress.android.ui.sitecreation.services.FetchWpComSiteUseCase import org.wordpress.android.ui.sitecreation.usecases.isWordPressComSubDomain import org.wordpress.android.util.AppLog import org.wordpress.android.util.AppLog.T @@ -25,16 +31,20 @@ import javax.inject.Inject import javax.inject.Named import kotlin.coroutines.CoroutineContext -const val KEY_CREATE_SITE_STATE = "CREATE_SITE_STATE" -const val LOADING_STATE_TEXT_ANIMATION_DELAY = 2000L - @HiltViewModel class SitePreviewViewModel @Inject constructor( + private val dispatcher: Dispatcher, + private val siteStore: SiteStore, + private val fetchWpComSiteUseCase: FetchWpComSiteUseCase, private val urlUtils: UrlUtilsWrapper, private val tracker: SiteCreationTracker, @Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, @Named(UI_THREAD) private val mainDispatcher: CoroutineDispatcher ) : ViewModel(), CoroutineScope { + init { + dispatcher.register(fetchWpComSiteUseCase) + } + private val job = Job() override val coroutineContext: CoroutineContext get() = bgDispatcher + job @@ -52,11 +62,12 @@ class SitePreviewViewModel @Inject constructor( private val _preloadPreview: MutableLiveData = MutableLiveData() val preloadPreview: LiveData = _preloadPreview - private val _onOkButtonClicked = SingleLiveEvent() - val onOkButtonClicked: LiveData = _onOkButtonClicked + private val _onOkButtonClicked = SingleLiveEvent() + val onOkButtonClicked: LiveData = _onOkButtonClicked override fun onCleared() { super.onCleared() + dispatcher.unregister(fetchWpComSiteUseCase) job.cancel() } @@ -67,12 +78,13 @@ class SitePreviewViewModel @Inject constructor( urlWithoutScheme = siteCreationState.domain?.domainName siteTitle = siteCreationState.siteName result = siteCreationState.result + fetchSite() startPreLoadingWebView() } fun onOkButtonClicked() { tracker.trackPreviewOkButtonTapped() - _onOkButtonClicked.call() + _onOkButtonClicked.postValue(result) } private fun startPreLoadingWebView() { @@ -100,6 +112,31 @@ class SitePreviewViewModel @Inject constructor( } } + private fun fetchSite() { + (result as? NotInLocalDb)?.let { + launch { + fetchNewlyCreatedSiteModel(it.remoteSiteId)?.let { fetchResult -> + result = fetchResult + } + } + } ?: AppLog.e(T.SITE_CREATION, "type of siteCreationResult should be NotInLocalDb before fetching") + } + + /** + * Fetch newly created site model - supports retry with linear backoff. + */ + private suspend fun fetchNewlyCreatedSiteModel(remoteSiteId: Long): SiteCreationResult? { + val onSiteFetched = fetchWpComSiteUseCase.fetchSiteWithRetry(remoteSiteId) + return if (!onSiteFetched.isError) { + val siteBySiteId = requireNotNull(siteStore.getSiteBySiteId(remoteSiteId)) { + "Site successfully fetched but has not been found in the local db." + } + Completed(siteBySiteId.id, !siteTitle.isNullOrBlank(), siteBySiteId.url) + } else { + null + } + } + fun onUrlLoaded() { if (!webviewFullyLoadedTracked) { webviewFullyLoadedTracked = true diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index 8670430e9ead..03be87a30edb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -13,22 +13,18 @@ import kotlinx.coroutines.launch import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import org.wordpress.android.R -import org.wordpress.android.fluxc.Dispatcher -import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD -import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.SiteCreationResult -import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb +import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.UNKNOWN import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.ConnectionError import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.GenericError import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Loading -import org.wordpress.android.ui.sitecreation.services.FetchWpComSiteUseCase import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceData import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE @@ -44,7 +40,7 @@ import javax.inject.Inject import javax.inject.Named import kotlin.coroutines.CoroutineContext -const val KEY_CREATE_SITE_STATE = "CREATE_SITE_STATE" +const val KEY_RESULT = "KEY_RESULT" private const val CONNECTION_ERROR_DELAY_TO_SHOW_LOADING_STATE = 1000L const val LOADING_STATE_TEXT_ANIMATION_DELAY = 2000L private const val ERROR_CONTEXT = "site_preview" @@ -58,9 +54,6 @@ private val loadingTexts = listOf( @HiltViewModel class SiteProgressViewModel @Inject constructor( - private val dispatcher: Dispatcher, - private val siteStore: SiteStore, - private val fetchWpComSiteUseCase: FetchWpComSiteUseCase, private val networkUtils: NetworkUtilsWrapper, private val urlUtils: UrlUtilsWrapper, private val tracker: SiteCreationTracker, @@ -74,11 +67,12 @@ class SiteProgressViewModel @Inject constructor( private var loadingAnimationJob: Job? = null private lateinit var siteCreationState: SiteCreationState + private lateinit var result: SiteCreationResult + private var urlWithoutScheme: String? = null private var siteTitle: String? = null private var lastReceivedServiceState: SiteCreationServiceState? = null private var serviceStateForRetry: SiteCreationServiceState? = null - private var result: SiteCreationResult = NotCreated private val _uiState: MutableLiveData = MutableLiveData() val uiState: LiveData = _uiState @@ -95,18 +89,13 @@ class SiteProgressViewModel @Inject constructor( private val _onSiteCreationCompleted = SingleLiveEvent() val onSiteCreationCompleted: LiveData = _onSiteCreationCompleted - init { - dispatcher.register(fetchWpComSiteUseCase) - } - override fun onCleared() { super.onCleared() - dispatcher.unregister(fetchWpComSiteUseCase) job.cancel() loadingAnimationJob?.cancel() } - fun writeToBundle(outState: Bundle) = outState.putParcelable(KEY_CREATE_SITE_STATE, result) + fun writeToBundle(outState: Bundle) = outState.putParcelable(KEY_RESULT, result) fun start(siteCreationState: SiteCreationState, savedState: Bundle?) { if (isStarted) return @@ -115,25 +104,18 @@ class SiteProgressViewModel @Inject constructor( urlWithoutScheme = siteCreationState.domain?.domainName siteTitle = siteCreationState.siteName - val restoredState = savedState?.getParcelable(KEY_CREATE_SITE_STATE) - - init(restoredState ?: NotCreated) - } - - private fun init(state: SiteCreationResult) { - result = state - when (state) { + val restoredResult = savedState?.getParcelable(KEY_RESULT) + result = restoredResult ?: NotCreated + when (result) { NotCreated -> { runLoadingAnimationUi() startCreateSiteService() } is NotInLocalDb -> { runLoadingAnimationUi() - launch { - result = fetchNewlyCreatedSiteModel(state.remoteSiteId) - } + _onSiteCreationCompleted.postValue(result) } - is Completed -> Unit + else -> Unit } } @@ -195,9 +177,7 @@ class SiteProgressViewModel @Inject constructor( val remoteSiteId = (event.payload as Pair<*, *>).first as Long urlWithoutScheme = urlUtils.removeScheme(event.payload.second as String).trimEnd('/') result = NotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) - launch { - result = fetchNewlyCreatedSiteModel(remoteSiteId) - } + _onSiteCreationCompleted.postValue(result) } FAILURE -> { serviceStateForRetry = event.payload as SiteCreationServiceState @@ -211,21 +191,6 @@ class SiteProgressViewModel @Inject constructor( } } - /** - * Fetch newly created site model - supports retry with linear backoff. - */ - private suspend fun fetchNewlyCreatedSiteModel(remoteSiteId: Long): SiteCreationResult { - val onSiteFetched = fetchWpComSiteUseCase.fetchSiteWithRetry(remoteSiteId) - return if (!onSiteFetched.isError) { - val siteBySiteId = requireNotNull(siteStore.getSiteBySiteId(remoteSiteId)) { - "Site successfully fetched but has not been found in the local db." - } - Completed(siteBySiteId.id, !siteTitle.isNullOrBlank(), siteBySiteId.url) - } else { - NotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) - } - } - private fun runLoadingAnimationUi() { loadingAnimationJob?.cancel() loadingAnimationJob = launch(mainDispatcher) { @@ -238,7 +203,6 @@ class SiteProgressViewModel @Inject constructor( ) delay(LOADING_STATE_TEXT_ANIMATION_DELAY) } - _onSiteCreationCompleted.postValue(result) } } From 1574f3f5aa1ef9daedf95e93df6afcb3e9de6273 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 14:26:54 +0100 Subject: [PATCH 074/169] Test: move fetching to the preview step and introduce flow fixtures --- .../ui/sitecreation/SiteCreationFixtures.kt | 31 ++++++ .../ui/sitecreation/SiteCreationMainVMTest.kt | 13 +-- .../previews/SitePreviewViewModelTest.kt | 67 +++++++++--- .../progress/SiteProgressViewModelTest.kt | 101 ++++++------------ 4 files changed, 121 insertions(+), 91 deletions(-) create mode 100644 WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt new file mode 100644 index 000000000000..680276e59229 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -0,0 +1,31 @@ +package org.wordpress.android.ui.sitecreation + +import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged +import org.wordpress.android.fluxc.store.SiteStore.SiteError +import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType.GENERIC_ERROR +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb +import org.wordpress.android.ui.sitecreation.domains.DomainModel +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.FAILURE +import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.SUCCESS +import org.wordpress.android.ui.sitecreation.theme.defaultTemplateSlug + +const val SUB_DOMAIN = "test" +const val URL = "$SUB_DOMAIN.wordpress.com" +val DOMAIN = DomainModel(URL, true, "", 1) + +val SITE_CREATION_STATE = SiteCreationState(segmentId = 1, siteDesign = defaultTemplateSlug, domain = DOMAIN) + +const val SITE_REMOTE_ID = 1L +private const val SITE_LOCAL_ID = 1 + +val SUCCESS_RESPONSE = OnSiteChanged(1) +val ERROR_RESPONSE = OnSiteChanged(0).apply { error = SiteError(GENERIC_ERROR) } + +val RESULT_NOT_IN_LOCAL_DB = NotInLocalDb(SITE_REMOTE_ID, false) +val RESULT_COMPLETED = Completed(SITE_LOCAL_ID, false, URL) + +val SERVICE_SUCCESS = SiteCreationServiceState(SUCCESS, Pair(SITE_REMOTE_ID, URL)) +val SERVICE_ERROR = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 2ba6d738dc5f..30e677004656 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -32,7 +32,6 @@ import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleEmpty import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount -import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.usecases.FetchHomePageLayoutsUseCase @@ -44,10 +43,8 @@ import org.wordpress.android.util.wizard.WizardManager import org.wordpress.android.viewmodel.SingleLiveEvent import org.wordpress.android.viewmodel.helpers.DialogHolder -private const val LOCAL_SITE_ID = 1 private const val SEGMENT_ID = 1L private const val VERTICAL = "Test Vertical" -private val DOMAIN = DomainModel("test.domain.com", true, "$0", 1) private const val STEP_COUNT = 20 private const val FIRST_STEP_INDEX = 1 private const val LAST_STEP_INDEX = STEP_COUNT @@ -139,19 +136,17 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun `on preview emits completion result to wizardFinishedObservable`() { - val result = SiteCreationResult.Completed(LOCAL_SITE_ID, false, DOMAIN.domainName) - viewModel.onSiteCreationCompleted(result) + viewModel.onSiteCreationCompleted(RESULT_COMPLETED) viewModel.onProgressOrPreviewFinished() - verify(wizardFinishedObserver).onChanged(eq(result)) + verify(wizardFinishedObserver).onChanged(eq(RESULT_COMPLETED)) } @Test fun `on progress finished emits result to wizardFinishedObservable`() { - val result = SiteCreationResult.Completed(LOCAL_SITE_ID, false, DOMAIN.domainName) - viewModel.onProgressOrPreviewFinished(result) - verify(wizardFinishedObserver).onChanged(eq(result)) + viewModel.onProgressOrPreviewFinished(RESULT_COMPLETED) + verify(wizardFinishedObserver).onChanged(eq(RESULT_COMPLETED)) } @Test diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index 1afbb9c37ecc..b350bc3aab48 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -1,6 +1,7 @@ package org.wordpress.android.ui.sitecreation.previews import androidx.lifecycle.Observer +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceTimeBy import org.assertj.core.api.Assertions.assertThat @@ -10,27 +11,42 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.isA +import org.mockito.kotlin.mock +import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest -import org.wordpress.android.ui.sitecreation.SiteCreationState -import org.wordpress.android.ui.sitecreation.domains.DomainModel +import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.store.SiteStore +import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged +import org.wordpress.android.ui.sitecreation.ERROR_RESPONSE +import org.wordpress.android.ui.sitecreation.RESULT_COMPLETED +import org.wordpress.android.ui.sitecreation.RESULT_NOT_IN_LOCAL_DB +import org.wordpress.android.ui.sitecreation.SITE_CREATION_STATE +import org.wordpress.android.ui.sitecreation.SITE_REMOTE_ID +import org.wordpress.android.ui.sitecreation.SUB_DOMAIN +import org.wordpress.android.ui.sitecreation.SUCCESS_RESPONSE +import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed +import org.wordpress.android.ui.sitecreation.SiteCreationState +import org.wordpress.android.ui.sitecreation.URL import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewWebErrorUiState -import org.wordpress.android.ui.sitecreation.theme.defaultTemplateSlug +import org.wordpress.android.ui.sitecreation.progress.LOADING_STATE_TEXT_ANIMATION_DELAY +import org.wordpress.android.ui.sitecreation.services.FetchWpComSiteUseCase import org.wordpress.android.util.UrlUtilsWrapper -private const val SUB_DOMAIN = "test" -private const val URL = "$SUB_DOMAIN.wordpress.com" -private val DOMAIN = DomainModel(URL, true, "", 1) -private val SITE_CREATION_STATE = SiteCreationState(segmentId = 1, siteDesign = defaultTemplateSlug, domain = DOMAIN) - @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) class SitePreviewViewModelTest : BaseUnitTest() { + private var dispatcher = mock() + private var siteStore = mock() + private var fetchWpComSiteUseCase = mock() + @Mock private lateinit var urlUtils: UrlUtilsWrapper @@ -41,7 +57,7 @@ class SitePreviewViewModelTest : BaseUnitTest() { private lateinit var uiStateObserver: Observer @Mock - private lateinit var onOkClickedObserver: Observer + private lateinit var onOkClickedObserver: Observer @Mock private lateinit var preloadPreviewObserver: Observer @@ -51,6 +67,9 @@ class SitePreviewViewModelTest : BaseUnitTest() { @Before fun setUp() { viewModel = SitePreviewViewModel( + dispatcher, + siteStore, + fetchWpComSiteUseCase, urlUtils, tracker, testDispatcher(), @@ -59,8 +78,24 @@ class SitePreviewViewModelTest : BaseUnitTest() { viewModel.uiState.observeForever(uiStateObserver) viewModel.onOkButtonClicked.observeForever(onOkClickedObserver) viewModel.preloadPreview.observeForever(preloadPreviewObserver) + whenever(urlUtils.extractSubDomain(URL)).thenReturn(SUB_DOMAIN) whenever(urlUtils.addUrlSchemeIfNeeded(URL, true)).thenReturn(URL) + whenever(siteStore.getSiteBySiteId(SITE_REMOTE_ID)).thenReturn(SiteModel().apply { id = 1; url = URL }) + } + + @Test + fun `on start fetches site by remote id`() = testWith(SUCCESS_RESPONSE) { + startViewModel(SITE_CREATION_STATE.copy(result = RESULT_NOT_IN_LOCAL_DB)) + verify(fetchWpComSiteUseCase).fetchSiteWithRetry(SITE_REMOTE_ID) + } + + @Test + fun `on start does not show preview when fetching fails`() = testWith(ERROR_RESPONSE) { + startViewModel(SITE_CREATION_STATE.copy(result = RESULT_NOT_IN_LOCAL_DB)) + verify(siteStore, never()).getSiteBySiteId(SITE_REMOTE_ID) + viewModel.onOkButtonClicked() + verify(uiStateObserver, never()).onChanged(isA()) } @Test @@ -89,19 +124,27 @@ class SitePreviewViewModelTest : BaseUnitTest() { @Test fun `on start preloads the preview when result is Completed`() { - startViewModel(SITE_CREATION_STATE.copy(result = Completed(2, false, URL))) - + startViewModel(SITE_CREATION_STATE.copy(result = RESULT_COMPLETED)) assertThat(viewModel.preloadPreview.value).isEqualTo(URL) } @Test fun `on ok button click is propagated`() { + startViewModel() viewModel.onOkButtonClicked() - verify(onOkClickedObserver).onChanged(anyOrNull()) } + // region Helpers + + private fun testWith(response: OnSiteChanged, block: suspend CoroutineScope.() -> Unit) = test { + whenever(fetchWpComSiteUseCase.fetchSiteWithRetry(SITE_REMOTE_ID)).thenReturn(response) + block() + } + private fun startViewModel(siteCreationState: SiteCreationState = SITE_CREATION_STATE) { viewModel.start(siteCreationState) } + + // endregion } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt index ff11420837c1..fe6c80b18926 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -2,7 +2,6 @@ package org.wordpress.android.ui.sitecreation.progress import android.os.Bundle import androidx.lifecycle.Observer -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceTimeBy import org.assertj.core.api.Assertions.assertThat @@ -10,42 +9,32 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.atMost import org.mockito.kotlin.check -import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq +import org.mockito.kotlin.isA import org.mockito.kotlin.isNull import org.mockito.kotlin.mock import org.mockito.kotlin.notNull import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest -import org.wordpress.android.fluxc.Dispatcher -import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.fluxc.store.SiteStore -import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged -import org.wordpress.android.fluxc.store.SiteStore.SiteError -import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType -import org.wordpress.android.ui.sitecreation.SiteCreationState -import org.wordpress.android.ui.sitecreation.domains.DomainModel +import org.wordpress.android.ui.sitecreation.RESULT_NOT_IN_LOCAL_DB +import org.wordpress.android.ui.sitecreation.SERVICE_ERROR +import org.wordpress.android.ui.sitecreation.SERVICE_SUCCESS import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb +import org.wordpress.android.ui.sitecreation.SiteCreationState +import org.wordpress.android.ui.sitecreation.URL +import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker -import org.wordpress.android.ui.sitecreation.previews.KEY_CREATE_SITE_STATE -import org.wordpress.android.ui.sitecreation.previews.LOADING_STATE_TEXT_ANIMATION_DELAY import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.ConnectionError import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.GenericError import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Loading import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.StartServiceData -import org.wordpress.android.ui.sitecreation.services.FetchWpComSiteUseCase -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.FAILURE -import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.SUCCESS import org.wordpress.android.ui.sitecreation.theme.defaultTemplateSlug import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.util.UrlUtilsWrapper @@ -53,27 +42,16 @@ import kotlin.test.assertEquals import kotlin.test.assertIs import kotlin.test.assertNotNull -private const val URL = "test.wordpress.com" -private const val SITE_REMOTE_ID = 1L -private val RESULT_NOT_IN_LOCAL_DB = NotInLocalDb(SITE_REMOTE_ID, false) -private val SUCCESS_SERVICE_STATE = SiteCreationServiceState(SUCCESS, Pair(SITE_REMOTE_ID, URL)) -private val ERROR_SERVICE_STATE = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) -private val SUCCESS_RESPONSE = OnSiteChanged(1) -private val ERROR_RESPONSE = OnSiteChanged(0).apply { error = SiteError(SiteErrorType.GENERIC_ERROR) } - @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) class SiteProgressViewModelTest : BaseUnitTest() { - private var dispatcher = mock() - private var siteStore = mock() - private var fetchWpComSiteUseCase = mock() private var networkUtils = mock() private var urlUtils = mock() private var tracker = mock() private val uiStateObserver = mock>() private val startServiceObserver = mock>() - private val onHelpedClickedObserver = mock>() + private val onHelpClickedObserver = mock>() private val onCancelWizardClickedObserver = mock>() private val onSiteCreationCompletedObserver = mock>() @@ -84,9 +62,6 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Before fun setUp() { viewModel = SiteProgressViewModel( - dispatcher = dispatcher, - siteStore = siteStore, - fetchWpComSiteUseCase = fetchWpComSiteUseCase, networkUtils = networkUtils, urlUtils = urlUtils, tracker = tracker, @@ -95,13 +70,12 @@ class SiteProgressViewModelTest : BaseUnitTest() { ) viewModel.uiState.observeForever(uiStateObserver) viewModel.startCreateSiteService.observeForever(startServiceObserver) - viewModel.onHelpClicked.observeForever(onHelpedClickedObserver) + viewModel.onHelpClicked.observeForever(onHelpClickedObserver) viewModel.onCancelWizardClicked.observeForever(onCancelWizardClickedObserver) viewModel.onSiteCreationCompleted.observeForever(onSiteCreationCompletedObserver) whenever(networkUtils.isNetworkAvailable()).thenReturn(true) whenever(urlUtils.removeScheme(URL)).thenReturn(URL) - whenever(siteStore.getSiteBySiteId(SITE_REMOTE_ID)).thenReturn(SiteModel().apply { id = 1; url = URL }) } @Test @@ -111,13 +85,13 @@ class SiteProgressViewModelTest : BaseUnitTest() { } @Test - fun `on start shows progress when restoring SiteNotCreated`() = testWith(SUCCESS_RESPONSE) { + fun `on start shows progress when restoring from SiteNotCreated`() { startViewModel(NotCreated) assertIs(viewModel.uiState.value) } @Test - fun `on start shows progress when restoring SiteNotInLocalDb`() = testWith(ERROR_RESPONSE) { + fun `on start shows progress when restoring from SiteNotInLocalDb`() { startViewModel(RESULT_NOT_IN_LOCAL_DB) assertIs(viewModel.uiState.value) } @@ -134,6 +108,12 @@ class SiteProgressViewModelTest : BaseUnitTest() { assertNotNull(viewModel.startCreateSiteService.value) } + @Test + fun `on start emits completion when restoring from NotInLocalDb`() { + startViewModel(RESULT_NOT_IN_LOCAL_DB) + verify(onSiteCreationCompletedObserver).onChanged(isA()) + } + @Test fun `on start shows error when network is not available`() = test { whenever(networkUtils.isNetworkAvailable()).thenReturn(false) @@ -142,12 +122,6 @@ class SiteProgressViewModelTest : BaseUnitTest() { assertIs(viewModel.uiState.value) } - @Test - fun `on start fetches site by remote id when restoring SiteNotInLocalDb`() = testWith(SUCCESS_RESPONSE) { - startViewModel(RESULT_NOT_IN_LOCAL_DB) - verify(fetchWpComSiteUseCase).fetchSiteWithRetry(SITE_REMOTE_ID) - } - @Test fun `on start shows first loading text without animation`() = test { startViewModel() @@ -175,68 +149,55 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Test fun `on retry click emits service event with the previous result`() { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(ERROR_SERVICE_STATE) + viewModel.onSiteCreationServiceStateUpdated(SERVICE_ERROR) viewModel.retry() - assertEquals(viewModel.startCreateSiteService.value?.previousState, ERROR_SERVICE_STATE.payload) + assertEquals(viewModel.startCreateSiteService.value?.previousState, SERVICE_ERROR.payload) } @Test fun `on help click is propagate`() { startViewModel() viewModel.onHelpClicked() - verify(onHelpedClickedObserver).onChanged(isNull()) + verify(onHelpClickedObserver).onChanged(isNull()) } @Test fun `on cancel wizard click is propagated`() { + startViewModel() viewModel.onCancelWizardClicked() assertEquals(viewModel.onCancelWizardClicked.value, NotCreated) } @Test - fun `on write to bundle saves the state`() { + fun `on write to bundle saves result`() { startViewModel() viewModel.writeToBundle(bundle) - verify(bundle).putParcelable(eq(KEY_CREATE_SITE_STATE), notNull()) + verify(bundle).putParcelable(eq(KEY_RESULT), notNull()) } @Test - fun `on service success fetches site by remote id`() = testWith(SUCCESS_RESPONSE) { + fun `on service success emits completion`() { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(SUCCESS_SERVICE_STATE) - verify(fetchWpComSiteUseCase).fetchSiteWithRetry(SITE_REMOTE_ID) + viewModel.onSiteCreationServiceStateUpdated(SERVICE_SUCCESS) + verify(onSiteCreationCompletedObserver).onChanged(isA()) } @Test - fun `on service success will emit completion event when animations end`() = testWith(SUCCESS_RESPONSE) { + fun `on service failure shows generic error`() { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(SUCCESS_SERVICE_STATE) - advanceUntilIdle() - verify(onSiteCreationCompletedObserver).onChanged(any()) - } - - @Test - fun `on service failure will emit completion event when animations end`() = testWith(ERROR_RESPONSE) { - startViewModel() - viewModel.onSiteCreationServiceStateUpdated(SUCCESS_SERVICE_STATE) - advanceUntilIdle() - verify(onSiteCreationCompletedObserver).onChanged(any()) + viewModel.onSiteCreationServiceStateUpdated(SERVICE_ERROR) + verify(uiStateObserver).onChanged(eq(GenericError)) } @Test fun `on service failure shows error`() { startViewModel() - viewModel.onSiteCreationServiceStateUpdated(ERROR_SERVICE_STATE) + viewModel.onSiteCreationServiceStateUpdated(SERVICE_ERROR) assertIs(viewModel.uiState.value) } // region Helpers - private fun testWith(response: OnSiteChanged, block: suspend CoroutineScope.() -> Unit) = test { - whenever(fetchWpComSiteUseCase.fetchSiteWithRetry(SITE_REMOTE_ID)).thenReturn(response) - block() - } - private fun startViewModel(restoredState: SiteCreationResult? = null) { viewModel.start( SiteCreationState( @@ -245,7 +206,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { domain = DomainModel(URL, true, "", 1) ), bundle.apply { - restoredState?.let { whenever(getParcelable(KEY_CREATE_SITE_STATE)) doReturn it } + restoredState?.let { whenever(getParcelable(KEY_RESULT)).thenReturn(it) } } ) } From 42ea078d1342b72ba2de47111c2cca4b2d8c0ebe Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 14:37:56 +0100 Subject: [PATCH 075/169] Fix: unused imports for linting --- .../android/ui/sitecreation/previews/SitePreviewViewModelTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index b350bc3aab48..558a7ee017ea 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -29,7 +29,6 @@ import org.wordpress.android.ui.sitecreation.SITE_REMOTE_ID import org.wordpress.android.ui.sitecreation.SUB_DOMAIN import org.wordpress.android.ui.sitecreation.SUCCESS_RESPONSE import org.wordpress.android.ui.sitecreation.SiteCreationResult -import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.URL import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker From a75fbb77fcf856feb26da00dcaae471682fdad2c Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 14:43:09 +0100 Subject: [PATCH 076/169] Refactor: remove unneeded bgDispatcher --- .../progress/SiteCreationProgressViewModel.kt | 5 +---- .../sitecreation/progress/SiteProgressViewModelTest.kt | 9 ++++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index 03be87a30edb..e096167396e4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -13,7 +13,6 @@ import kotlinx.coroutines.launch import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import org.wordpress.android.R -import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated @@ -57,12 +56,10 @@ class SiteProgressViewModel @Inject constructor( private val networkUtils: NetworkUtilsWrapper, private val urlUtils: UrlUtilsWrapper, private val tracker: SiteCreationTracker, - @Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, @Named(UI_THREAD) private val mainDispatcher: CoroutineDispatcher ) : ViewModel(), CoroutineScope { private val job = Job() - override val coroutineContext: CoroutineContext - get() = bgDispatcher + job + override val coroutineContext: CoroutineContext get() = mainDispatcher + job private var isStarted = false private var loadingAnimationJob: Job? = null diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt index fe6c80b18926..83e6da098127 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -62,11 +62,10 @@ class SiteProgressViewModelTest : BaseUnitTest() { @Before fun setUp() { viewModel = SiteProgressViewModel( - networkUtils = networkUtils, - urlUtils = urlUtils, - tracker = tracker, - bgDispatcher = testDispatcher(), - mainDispatcher = testDispatcher() + networkUtils, + urlUtils, + tracker, + testDispatcher(), ) viewModel.uiState.observeForever(uiStateObserver) viewModel.startCreateSiteService.observeForever(startServiceObserver) From 74d186b9d7d0b21290a0a54d85768f22f49f1dc5 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 14:43:59 +0100 Subject: [PATCH 077/169] Refactor: move fetchSite under start --- .../previews/SitePreviewViewModel.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 94fab01aef03..7be00a62d4f0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -82,6 +82,16 @@ class SitePreviewViewModel @Inject constructor( startPreLoadingWebView() } + private fun fetchSite() { + (result as? NotInLocalDb)?.let { + launch { + fetchNewlyCreatedSiteModel(it.remoteSiteId)?.let { fetchResult -> + result = fetchResult + } + } + } ?: AppLog.e(T.SITE_CREATION, "type of siteCreationResult should be NotInLocalDb before fetching") + } + fun onOkButtonClicked() { tracker.trackPreviewOkButtonTapped() _onOkButtonClicked.postValue(result) @@ -112,16 +122,6 @@ class SitePreviewViewModel @Inject constructor( } } - private fun fetchSite() { - (result as? NotInLocalDb)?.let { - launch { - fetchNewlyCreatedSiteModel(it.remoteSiteId)?.let { fetchResult -> - result = fetchResult - } - } - } ?: AppLog.e(T.SITE_CREATION, "type of siteCreationResult should be NotInLocalDb before fetching") - } - /** * Fetch newly created site model - supports retry with linear backoff. */ From 50e50010bd48d78aef9d28ad75a482c2271eda93 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 16:48:36 +0100 Subject: [PATCH 078/169] Refactor: simplify state mutations for progress and preview --- .../ui/sitecreation/SiteCreationActivity.kt | 21 ++--- .../ui/sitecreation/SiteCreationMainVM.kt | 18 +++-- .../previews/SitePreviewViewModel.kt | 29 +++---- .../progress/SiteCreationProgressFragment.kt | 19 +---- .../progress/SiteCreationProgressViewModel.kt | 43 +++-------- .../ui/sitecreation/SiteCreationFixtures.kt | 9 ++- .../ui/sitecreation/SiteCreationMainVMTest.kt | 40 ++++------ .../previews/SitePreviewViewModelTest.kt | 2 +- .../progress/SiteProgressViewModelTest.kt | 77 +++---------------- 9 files changed, 78 insertions(+), 180 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index e15309b8c33b..670d38b2e2a7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -108,17 +108,18 @@ class SiteCreationActivity : LocaleAwareActivity(), val intent = Intent() val (siteCreated, localSiteId, titleTaskComplete) = when (createSiteState) { // site creation flow was canceled - is NotCreated -> Triple(false, null, false) + is NotCreated -> { + Triple(false, null, false) + } is NotInLocalDb -> { // Site was created, but we haven't been able to fetch it, let `SitePickerActivity` handle // this with a Snackbar message. intent.putExtra(SitePickerActivity.KEY_SITE_CREATED_BUT_NOT_FETCHED, true) Triple(true, null, createSiteState.isSiteTitleTaskComplete) } - is Completed -> Triple( - true, createSiteState.localSiteId, - createSiteState.isSiteTitleTaskComplete - ) + is Completed -> { + Triple(true, createSiteState.localSiteId, createSiteState.isSiteTitleTaskComplete) + } } intent.putExtra(SitePickerActivity.KEY_SITE_LOCAL_ID, localSiteId) intent.putExtra(SitePickerActivity.KEY_SITE_TITLE_TASK_COMPLETED, titleTaskComplete) @@ -162,14 +163,14 @@ class SiteCreationActivity : LocaleAwareActivity(), hppViewModel.onDesignActionPressed.observe(this, Observer { design -> mainViewModel.onSiteDesignSelected(design.template) }) - progressViewModel.onCancelWizardClicked.observe(this) { result -> - mainViewModel.onProgressOrPreviewFinished(result) + progressViewModel.onCancelWizardClicked.observe(this) { + mainViewModel.onWizardCancelled() } - progressViewModel.onSiteCreationCompleted.observe(this) { result -> - mainViewModel.onSiteCreationCompleted(result) + progressViewModel.onRemoteSiteCreated.observe(this) { remoteSiteId -> + mainViewModel.onProgressScreenFinished(remoteSiteId) } previewViewModel.onOkButtonClicked.observe(this) { result -> - mainViewModel.onProgressOrPreviewFinished(result) + mainViewModel.onWizardFinished(result) } observeOverlayEvents() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 88a206d0e281..15d0923b7648 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -54,6 +54,7 @@ data class SiteCreationState( val segmentId: Long? = null, val siteDesign: String? = null, val domain: DomainModel? = null, + val remoteSiteId: Long? = null, val result: SiteCreationResult = NotCreated, ) : WizardState, Parcelable @@ -263,11 +264,20 @@ class SiteCreationMainVM @Inject constructor( } } - fun onSiteCreationCompleted(result: SiteCreationResult) { - siteCreationState = siteCreationState.copy(result = result) + fun onProgressScreenFinished(remoteSiteId: Long) { + siteCreationState = siteCreationState.copy(remoteSiteId = remoteSiteId) wizardManager.showNextStep() } + fun onWizardCancelled() { + _wizardFinishedObservable.value = NotCreated + } + + fun onWizardFinished(result: SiteCreationResult) { + siteCreationState = siteCreationState.copy(result = result) + _wizardFinishedObservable.value = result + } + /** * Exits the flow and tracks an event when the user force-exits the "site creation in progress" before it completes. */ @@ -278,10 +288,6 @@ class SiteCreationMainVM @Inject constructor( _exitFlowObservable.call() } - fun onProgressOrPreviewFinished(result: SiteCreationResult? = null) { - _wizardFinishedObservable.value = result ?: siteCreationState.result - } - fun onPositiveDialogButtonClicked(instanceTag: String) { when (instanceTag) { TAG_WARNING_DIALOG -> { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 7be00a62d4f0..a93c77d8095e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -53,9 +53,11 @@ class SitePreviewViewModel @Inject constructor( private var siteTitle: String? = null private var siteDesign: String? = null - private lateinit var result: SiteCreationResult + private var remoteSiteId: Long = 0 private var urlWithoutScheme: String? = null + private lateinit var result: SiteCreationResult + private val _uiState: MutableLiveData = MutableLiveData() val uiState: LiveData = _uiState @@ -75,23 +77,15 @@ class SitePreviewViewModel @Inject constructor( if (isStarted) return isStarted = true siteDesign = siteCreationState.siteDesign - urlWithoutScheme = siteCreationState.domain?.domainName + urlWithoutScheme = requireNotNull(siteCreationState.domain) { "domain required for preview" }.domainName siteTitle = siteCreationState.siteName - result = siteCreationState.result - fetchSite() + remoteSiteId = requireNotNull(siteCreationState.remoteSiteId) { "remoteSiteId required for preview" } + launch { + result = fetchNewlyCreatedSiteModel(remoteSiteId) + } startPreLoadingWebView() } - private fun fetchSite() { - (result as? NotInLocalDb)?.let { - launch { - fetchNewlyCreatedSiteModel(it.remoteSiteId)?.let { fetchResult -> - result = fetchResult - } - } - } ?: AppLog.e(T.SITE_CREATION, "type of siteCreationResult should be NotInLocalDb before fetching") - } - fun onOkButtonClicked() { tracker.trackPreviewOkButtonTapped() _onOkButtonClicked.postValue(result) @@ -125,15 +119,16 @@ class SitePreviewViewModel @Inject constructor( /** * Fetch newly created site model - supports retry with linear backoff. */ - private suspend fun fetchNewlyCreatedSiteModel(remoteSiteId: Long): SiteCreationResult? { + private suspend fun fetchNewlyCreatedSiteModel(remoteSiteId: Long): SiteCreationResult { val onSiteFetched = fetchWpComSiteUseCase.fetchSiteWithRetry(remoteSiteId) + val isSiteTitleTaskComplete = !siteTitle.isNullOrBlank() return if (!onSiteFetched.isError) { val siteBySiteId = requireNotNull(siteStore.getSiteBySiteId(remoteSiteId)) { "Site successfully fetched but has not been found in the local db." } - Completed(siteBySiteId.id, !siteTitle.isNullOrBlank(), siteBySiteId.url) + Completed(siteBySiteId.id, isSiteTitleTaskComplete, siteBySiteId.url) } else { - null + NotInLocalDb(remoteSiteId, isSiteTitleTaskComplete) } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt index 8f788a3158db..af2bad837da7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt @@ -56,12 +56,6 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc } } - @Suppress("DEPRECATION", "OVERRIDE_DEPRECATION") - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - init(savedInstanceState) - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -72,13 +66,9 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc fullscreenErrorWithRetry.setOnClickListeners() } - init(savedInstanceState) - } - - private fun init(savedInstanceState: Bundle?) { (requireActivity() as AppCompatActivity).supportActionBar?.hide() - viewModel.start(requireArguments()[ARG_STATE] as SiteCreationState, savedInstanceState) + viewModel.start(requireArguments()[ARG_STATE] as SiteCreationState) } private fun SiteCreationProgressScreenBinding.observeState() { @@ -100,7 +90,7 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc SiteCreationService.createSite(requireNotNull(activity), it.previousState, it.serviceData) } } - viewModel.onSiteCreationCompleted.observe(viewLifecycleOwner) { + viewModel.onRemoteSiteCreated.observe(viewLifecycleOwner) { view?.announceForAccessibility(getString(R.string.new_site_creation_preview_title)) } } @@ -177,11 +167,6 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc serviceEventConnection = ServiceEventConnection(context, SiteCreationService::class.java, viewModel) } - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - viewModel.writeToBundle(outState) - } - override fun onPause() { super.onPause() serviceEventConnection?.disconnect(context, viewModel) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index e096167396e4..564f8e184a1c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -1,6 +1,5 @@ package org.wordpress.android.ui.sitecreation.progress -import android.os.Bundle import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -14,9 +13,6 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import org.wordpress.android.R import org.wordpress.android.modules.UI_THREAD -import org.wordpress.android.ui.sitecreation.SiteCreationResult -import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated -import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.UNKNOWN @@ -33,13 +29,11 @@ import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.S import org.wordpress.android.ui.utils.UiString import org.wordpress.android.ui.utils.UiString.UiStringRes import org.wordpress.android.util.NetworkUtilsWrapper -import org.wordpress.android.util.UrlUtilsWrapper import org.wordpress.android.viewmodel.SingleLiveEvent import javax.inject.Inject import javax.inject.Named import kotlin.coroutines.CoroutineContext -const val KEY_RESULT = "KEY_RESULT" private const val CONNECTION_ERROR_DELAY_TO_SHOW_LOADING_STATE = 1000L const val LOADING_STATE_TEXT_ANIMATION_DELAY = 2000L private const val ERROR_CONTEXT = "site_preview" @@ -54,7 +48,6 @@ private val loadingTexts = listOf( @HiltViewModel class SiteProgressViewModel @Inject constructor( private val networkUtils: NetworkUtilsWrapper, - private val urlUtils: UrlUtilsWrapper, private val tracker: SiteCreationTracker, @Named(UI_THREAD) private val mainDispatcher: CoroutineDispatcher ) : ViewModel(), CoroutineScope { @@ -64,7 +57,6 @@ class SiteProgressViewModel @Inject constructor( private var loadingAnimationJob: Job? = null private lateinit var siteCreationState: SiteCreationState - private lateinit var result: SiteCreationResult private var urlWithoutScheme: String? = null private var siteTitle: String? = null @@ -80,11 +72,11 @@ class SiteProgressViewModel @Inject constructor( private val _onHelpClicked = SingleLiveEvent() val onHelpClicked: LiveData = _onHelpClicked - private val _onCancelWizardClicked = SingleLiveEvent() - val onCancelWizardClicked: LiveData = _onCancelWizardClicked + private val _onCancelWizardClicked = SingleLiveEvent() + val onCancelWizardClicked: LiveData = _onCancelWizardClicked - private val _onSiteCreationCompleted = SingleLiveEvent() - val onSiteCreationCompleted: LiveData = _onSiteCreationCompleted + private val _onRemoteSiteCreated = SingleLiveEvent() + val onRemoteSiteCreated: LiveData = _onRemoteSiteCreated override fun onCleared() { super.onCleared() @@ -92,28 +84,15 @@ class SiteProgressViewModel @Inject constructor( loadingAnimationJob?.cancel() } - fun writeToBundle(outState: Bundle) = outState.putParcelable(KEY_RESULT, result) - - fun start(siteCreationState: SiteCreationState, savedState: Bundle?) { + fun start(siteCreationState: SiteCreationState) { if (isStarted) return isStarted = true this.siteCreationState = siteCreationState urlWithoutScheme = siteCreationState.domain?.domainName siteTitle = siteCreationState.siteName - val restoredResult = savedState?.getParcelable(KEY_RESULT) - result = restoredResult ?: NotCreated - when (result) { - NotCreated -> { - runLoadingAnimationUi() - startCreateSiteService() - } - is NotInLocalDb -> { - runLoadingAnimationUi() - _onSiteCreationCompleted.postValue(result) - } - else -> Unit - } + runLoadingAnimationUi() + startCreateSiteService() } private fun startCreateSiteService(previousState: SiteCreationServiceState? = null) { @@ -142,9 +121,7 @@ class SiteProgressViewModel @Inject constructor( fun onHelpClicked() = _onHelpClicked.call() - fun onCancelWizardClicked() { - _onCancelWizardClicked.value = result - } + fun onCancelWizardClicked() = _onCancelWizardClicked.call() private fun showFullscreenErrorWithDelay() { runLoadingAnimationUi() @@ -172,9 +149,7 @@ class SiteProgressViewModel @Inject constructor( IDLE, CREATE_SITE -> Unit SUCCESS -> { val remoteSiteId = (event.payload as Pair<*, *>).first as Long - urlWithoutScheme = urlUtils.removeScheme(event.payload.second as String).trimEnd('/') - result = NotInLocalDb(remoteSiteId, !siteTitle.isNullOrBlank()) - _onSiteCreationCompleted.postValue(result) + _onRemoteSiteCreated.postValue(remoteSiteId) } FAILURE -> { serviceStateForRetry = event.payload as SiteCreationServiceState diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index 680276e59229..c88249f1eed2 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -16,11 +16,16 @@ const val SUB_DOMAIN = "test" const val URL = "$SUB_DOMAIN.wordpress.com" val DOMAIN = DomainModel(URL, true, "", 1) -val SITE_CREATION_STATE = SiteCreationState(segmentId = 1, siteDesign = defaultTemplateSlug, domain = DOMAIN) - const val SITE_REMOTE_ID = 1L private const val SITE_LOCAL_ID = 1 +val SITE_CREATION_STATE = SiteCreationState( + segmentId = 1, + siteDesign = defaultTemplateSlug, + domain = DOMAIN, + remoteSiteId = SITE_REMOTE_ID, +) + val SUCCESS_RESPONSE = OnSiteChanged(1) val ERROR_RESPONSE = OnSiteChanged(0).apply { error = SiteError(GENERIC_ERROR) } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 30e677004656..0f9f1992f788 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -12,7 +12,6 @@ import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argThat -import org.mockito.kotlin.argWhere import org.mockito.kotlin.atLeastOnce import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.eq @@ -135,18 +134,21 @@ class SiteCreationMainVMTest : BaseUnitTest() { } @Test - fun `on preview emits completion result to wizardFinishedObservable`() { - viewModel.onSiteCreationCompleted(RESULT_COMPLETED) - - viewModel.onProgressOrPreviewFinished() - + fun `on wizard finished is propagated`() { + viewModel.onWizardFinished(RESULT_COMPLETED) verify(wizardFinishedObserver).onChanged(eq(RESULT_COMPLETED)) } @Test - fun `on progress finished emits result to wizardFinishedObservable`() { - viewModel.onProgressOrPreviewFinished(RESULT_COMPLETED) - verify(wizardFinishedObserver).onChanged(eq(RESULT_COMPLETED)) + fun `on progress screen finished updates state with remote id`() { + viewModel.onProgressScreenFinished(SITE_REMOTE_ID) + assertThat(currentWizardState(viewModel).remoteSiteId).isEqualTo(SITE_REMOTE_ID) + } + + @Test + fun `on progress screen finished shows next step`() { + viewModel.onProgressScreenFinished(SITE_REMOTE_ID) + verify(wizardManager).showNextStep() } @Test @@ -185,6 +187,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun dialogShownOnBackPressedWhenLastStepAndSiteCreationNotCompleted() { whenever(wizardManager.isLastStep()).thenReturn(true) + viewModel.onWizardCancelled() viewModel.onBackPressed() verify(dialogActionsObserver).onChanged(any()) } @@ -192,7 +195,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun flowExitedOnBackPressedWhenLastStepAndSiteCreationCompleted() { whenever(wizardManager.isLastStep()).thenReturn(true) - viewModel.onSiteCreationCompleted(mock()) + viewModel.onWizardFinished(RESULT_COMPLETED) viewModel.onBackPressed() verify(wizardExitedObserver).onChanged(anyOrNull()) } @@ -330,23 +333,6 @@ class SiteCreationMainVMTest : BaseUnitTest() { verify(tracker).trackSiteCreationDomainPurchasingExperimentVariation(isA()) } - @Test - fun `on site creation completed propagates result to state`() { - val expected = mock() - - viewModel.onSiteCreationCompleted(expected) - - val bundle = mock() - viewModel.writeToBundle(bundle) // used this to assert on the private siteCreationState field - verify(bundle).putParcelable(eq(KEY_SITE_CREATION_STATE), argWhere { it.result == expected }) - } - - @Test - fun `on site creation completed shows next step`() { - viewModel.onSiteCreationCompleted(mock()) - verify(wizardManager).showNextStep() - } - private fun currentWizardState(vm: SiteCreationMainVM) = vm.navigationTargetObservable.lastEvent!!.wizardState private fun getNewViewModel() = SiteCreationMainVM( diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index 558a7ee017ea..209ce5fef571 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -128,7 +128,7 @@ class SitePreviewViewModelTest : BaseUnitTest() { } @Test - fun `on ok button click is propagated`() { + fun `on ok button click is propagated`() = testWith(SUCCESS_RESPONSE) { startViewModel() viewModel.onOkButtonClicked() verify(onOkClickedObserver).onChanged(anyOrNull()) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt index 83e6da098127..46748f24ab23 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -1,6 +1,5 @@ package org.wordpress.android.ui.sitecreation.progress -import android.os.Bundle import androidx.lifecycle.Observer import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceTimeBy @@ -13,31 +12,22 @@ import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.atMost import org.mockito.kotlin.check import org.mockito.kotlin.eq -import org.mockito.kotlin.isA import org.mockito.kotlin.isNull import org.mockito.kotlin.mock -import org.mockito.kotlin.notNull import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest -import org.wordpress.android.ui.sitecreation.RESULT_NOT_IN_LOCAL_DB import org.wordpress.android.ui.sitecreation.SERVICE_ERROR import org.wordpress.android.ui.sitecreation.SERVICE_SUCCESS -import org.wordpress.android.ui.sitecreation.SiteCreationResult -import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated -import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb -import org.wordpress.android.ui.sitecreation.SiteCreationState -import org.wordpress.android.ui.sitecreation.URL -import org.wordpress.android.ui.sitecreation.domains.DomainModel +import org.wordpress.android.ui.sitecreation.SITE_CREATION_STATE +import org.wordpress.android.ui.sitecreation.SITE_REMOTE_ID import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.ConnectionError import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.GenericError import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Loading import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.StartServiceData -import org.wordpress.android.ui.sitecreation.theme.defaultTemplateSlug import org.wordpress.android.util.NetworkUtilsWrapper -import org.wordpress.android.util.UrlUtilsWrapper import kotlin.test.assertEquals import kotlin.test.assertIs import kotlin.test.assertNotNull @@ -46,16 +36,13 @@ import kotlin.test.assertNotNull @RunWith(MockitoJUnitRunner::class) class SiteProgressViewModelTest : BaseUnitTest() { private var networkUtils = mock() - private var urlUtils = mock() private var tracker = mock() private val uiStateObserver = mock>() private val startServiceObserver = mock>() private val onHelpClickedObserver = mock>() - private val onCancelWizardClickedObserver = mock>() - private val onSiteCreationCompletedObserver = mock>() - - private val bundle = mock() + private val onCancelWizardClickedObserver = mock>() + private val onRemoteSiteCreatedObserver = mock>() private lateinit var viewModel: SiteProgressViewModel @@ -63,7 +50,6 @@ class SiteProgressViewModelTest : BaseUnitTest() { fun setUp() { viewModel = SiteProgressViewModel( networkUtils, - urlUtils, tracker, testDispatcher(), ) @@ -71,10 +57,9 @@ class SiteProgressViewModelTest : BaseUnitTest() { viewModel.startCreateSiteService.observeForever(startServiceObserver) viewModel.onHelpClicked.observeForever(onHelpClickedObserver) viewModel.onCancelWizardClicked.observeForever(onCancelWizardClickedObserver) - viewModel.onSiteCreationCompleted.observeForever(onSiteCreationCompletedObserver) + viewModel.onRemoteSiteCreated.observeForever(onRemoteSiteCreatedObserver) whenever(networkUtils.isNetworkAvailable()).thenReturn(true) - whenever(urlUtils.removeScheme(URL)).thenReturn(URL) } @Test @@ -83,36 +68,12 @@ class SiteProgressViewModelTest : BaseUnitTest() { assertIs(viewModel.uiState.value) } - @Test - fun `on start shows progress when restoring from SiteNotCreated`() { - startViewModel(NotCreated) - assertIs(viewModel.uiState.value) - } - - @Test - fun `on start shows progress when restoring from SiteNotInLocalDb`() { - startViewModel(RESULT_NOT_IN_LOCAL_DB) - assertIs(viewModel.uiState.value) - } - @Test fun `on start emits service event`() = test { startViewModel() assertNotNull(viewModel.startCreateSiteService.value) } - @Test - fun `on start emits service event when restoring from SiteNotCreated`() { - startViewModel(NotCreated) - assertNotNull(viewModel.startCreateSiteService.value) - } - - @Test - fun `on start emits completion when restoring from NotInLocalDb`() { - startViewModel(RESULT_NOT_IN_LOCAL_DB) - verify(onSiteCreationCompletedObserver).onChanged(isA()) - } - @Test fun `on start shows error when network is not available`() = test { whenever(networkUtils.isNetworkAvailable()).thenReturn(false) @@ -154,7 +115,7 @@ class SiteProgressViewModelTest : BaseUnitTest() { } @Test - fun `on help click is propagate`() { + fun `on help click is propagated`() { startViewModel() viewModel.onHelpClicked() verify(onHelpClickedObserver).onChanged(isNull()) @@ -164,21 +125,14 @@ class SiteProgressViewModelTest : BaseUnitTest() { fun `on cancel wizard click is propagated`() { startViewModel() viewModel.onCancelWizardClicked() - assertEquals(viewModel.onCancelWizardClicked.value, NotCreated) + verify(onCancelWizardClickedObserver).onChanged(isNull()) } @Test - fun `on write to bundle saves result`() { - startViewModel() - viewModel.writeToBundle(bundle) - verify(bundle).putParcelable(eq(KEY_RESULT), notNull()) - } - - @Test - fun `on service success emits completion`() { + fun `on service success propagates remote id`() { startViewModel() viewModel.onSiteCreationServiceStateUpdated(SERVICE_SUCCESS) - verify(onSiteCreationCompletedObserver).onChanged(isA()) + verify(onRemoteSiteCreatedObserver).onChanged(SITE_REMOTE_ID) } @Test @@ -197,17 +151,8 @@ class SiteProgressViewModelTest : BaseUnitTest() { // region Helpers - private fun startViewModel(restoredState: SiteCreationResult? = null) { - viewModel.start( - SiteCreationState( - segmentId = 1, - siteDesign = defaultTemplateSlug, - domain = DomainModel(URL, true, "", 1) - ), - bundle.apply { - restoredState?.let { whenever(getParcelable(KEY_RESULT)).thenReturn(it) } - } - ) + private fun startViewModel() { + viewModel.start( SITE_CREATION_STATE) } // endregion From f51711270a0709346b20f5069d11cee41426fafb Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 16:50:39 +0100 Subject: [PATCH 079/169] Test: improve tests name --- .../ui/sitecreation/progress/SiteProgressViewModelTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt index 46748f24ab23..4eeae737d4e7 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt @@ -89,14 +89,14 @@ class SiteProgressViewModelTest : BaseUnitTest() { } @Test - fun `on start changes the loading text with delayed animation`() = test { + fun `on start changes the loading text with animation after delay`() = test { startViewModel() advanceTimeBy(LOADING_STATE_TEXT_ANIMATION_DELAY) verify(uiStateObserver).onChanged(check { it.animate }) } @Test - fun `on start changes the loading text with delayed animation only 4 times`() = test { + fun `on start changes the loading text with animation after delay 4 times`() = test { startViewModel() val captor = argumentCaptor() (1..9).forEach { From b5e558e53429a3fa72d005c2c35f1b989929ad0a Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 16:51:32 +0100 Subject: [PATCH 080/169] Refactor: move onCleared under init --- .../ui/sitecreation/previews/SitePreviewViewModel.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index a93c77d8095e..006bfb7c59b6 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -45,6 +45,12 @@ class SitePreviewViewModel @Inject constructor( dispatcher.register(fetchWpComSiteUseCase) } + override fun onCleared() { + super.onCleared() + dispatcher.unregister(fetchWpComSiteUseCase) + job.cancel() + } + private val job = Job() override val coroutineContext: CoroutineContext get() = bgDispatcher + job @@ -67,12 +73,6 @@ class SitePreviewViewModel @Inject constructor( private val _onOkButtonClicked = SingleLiveEvent() val onOkButtonClicked: LiveData = _onOkButtonClicked - override fun onCleared() { - super.onCleared() - dispatcher.unregister(fetchWpComSiteUseCase) - job.cancel() - } - fun start(siteCreationState: SiteCreationState) { if (isStarted) return isStarted = true From 73e7e4b102846ccdc996859bae162d923f55abad Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 17:05:57 +0100 Subject: [PATCH 081/169] Test: cleanup unnecessary stubbings --- .../ui/sitecreation/previews/SitePreviewViewModel.kt | 10 ++++++---- .../android/ui/sitecreation/SiteCreationFixtures.kt | 2 -- .../sitecreation/previews/SitePreviewViewModelTest.kt | 8 +++----- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 006bfb7c59b6..05c92a31957e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -57,10 +57,10 @@ class SitePreviewViewModel @Inject constructor( private var isStarted = false private var webviewFullyLoadedTracked = false - private var siteTitle: String? = null private var siteDesign: String? = null - private var remoteSiteId: Long = 0 + private var siteTitle: String? = null private var urlWithoutScheme: String? = null + private var remoteSiteId: Long = 0 private lateinit var result: SiteCreationResult @@ -76,14 +76,16 @@ class SitePreviewViewModel @Inject constructor( fun start(siteCreationState: SiteCreationState) { if (isStarted) return isStarted = true + siteDesign = siteCreationState.siteDesign - urlWithoutScheme = requireNotNull(siteCreationState.domain) { "domain required for preview" }.domainName siteTitle = siteCreationState.siteName + urlWithoutScheme = requireNotNull(siteCreationState.domain) { "url required for preview" }.domainName remoteSiteId = requireNotNull(siteCreationState.remoteSiteId) { "remoteSiteId required for preview" } + + startPreLoadingWebView() launch { result = fetchNewlyCreatedSiteModel(remoteSiteId) } - startPreLoadingWebView() } fun onOkButtonClicked() { diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index c88249f1eed2..e96391a14818 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -4,7 +4,6 @@ import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged import org.wordpress.android.fluxc.store.SiteStore.SiteError import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType.GENERIC_ERROR import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed -import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE @@ -29,7 +28,6 @@ val SITE_CREATION_STATE = SiteCreationState( val SUCCESS_RESPONSE = OnSiteChanged(1) val ERROR_RESPONSE = OnSiteChanged(0).apply { error = SiteError(GENERIC_ERROR) } -val RESULT_NOT_IN_LOCAL_DB = NotInLocalDb(SITE_REMOTE_ID, false) val RESULT_COMPLETED = Completed(SITE_LOCAL_ID, false, URL) val SERVICE_SUCCESS = SiteCreationServiceState(SUCCESS, Pair(SITE_REMOTE_ID, URL)) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index 209ce5fef571..f0426c03d053 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -22,8 +22,6 @@ import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged import org.wordpress.android.ui.sitecreation.ERROR_RESPONSE -import org.wordpress.android.ui.sitecreation.RESULT_COMPLETED -import org.wordpress.android.ui.sitecreation.RESULT_NOT_IN_LOCAL_DB import org.wordpress.android.ui.sitecreation.SITE_CREATION_STATE import org.wordpress.android.ui.sitecreation.SITE_REMOTE_ID import org.wordpress.android.ui.sitecreation.SUB_DOMAIN @@ -85,13 +83,13 @@ class SitePreviewViewModelTest : BaseUnitTest() { @Test fun `on start fetches site by remote id`() = testWith(SUCCESS_RESPONSE) { - startViewModel(SITE_CREATION_STATE.copy(result = RESULT_NOT_IN_LOCAL_DB)) + startViewModel() verify(fetchWpComSiteUseCase).fetchSiteWithRetry(SITE_REMOTE_ID) } @Test fun `on start does not show preview when fetching fails`() = testWith(ERROR_RESPONSE) { - startViewModel(SITE_CREATION_STATE.copy(result = RESULT_NOT_IN_LOCAL_DB)) + startViewModel() verify(siteStore, never()).getSiteBySiteId(SITE_REMOTE_ID) viewModel.onOkButtonClicked() verify(uiStateObserver, never()).onChanged(isA()) @@ -123,7 +121,7 @@ class SitePreviewViewModelTest : BaseUnitTest() { @Test fun `on start preloads the preview when result is Completed`() { - startViewModel(SITE_CREATION_STATE.copy(result = RESULT_COMPLETED)) + startViewModel(SITE_CREATION_STATE) assertThat(viewModel.preloadPreview.value).isEqualTo(URL) } From 23b2608afe6fe76b6fa10471329eed255c14c3d0 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 17:07:32 +0100 Subject: [PATCH 082/169] Test: improve fixtures naming --- .../android/ui/sitecreation/SiteCreationFixtures.kt | 8 ++++---- .../android/ui/sitecreation/SiteCreationMainVMTest.kt | 6 +++--- .../sitecreation/previews/SitePreviewViewModelTest.kt | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index e96391a14818..f3e59969501d 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -13,7 +13,7 @@ import org.wordpress.android.ui.sitecreation.theme.defaultTemplateSlug const val SUB_DOMAIN = "test" const val URL = "$SUB_DOMAIN.wordpress.com" -val DOMAIN = DomainModel(URL, true, "", 1) +val FREE_DOMAIN = DomainModel(URL, true, "", 1) const val SITE_REMOTE_ID = 1L private const val SITE_LOCAL_ID = 1 @@ -21,12 +21,12 @@ private const val SITE_LOCAL_ID = 1 val SITE_CREATION_STATE = SiteCreationState( segmentId = 1, siteDesign = defaultTemplateSlug, - domain = DOMAIN, + domain = FREE_DOMAIN, remoteSiteId = SITE_REMOTE_ID, ) -val SUCCESS_RESPONSE = OnSiteChanged(1) -val ERROR_RESPONSE = OnSiteChanged(0).apply { error = SiteError(GENERIC_ERROR) } +val FETCH_SUCCESS = OnSiteChanged(1) +val FETCH_ERROR = OnSiteChanged(0).apply { error = SiteError(GENERIC_ERROR) } val RESULT_COMPLETED = Completed(SITE_LOCAL_ID, false, URL) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 0f9f1992f788..b5f01a0f2581 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -123,14 +123,14 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun domainSelectedResultsInNextStep() { - viewModel.onDomainsScreenFinished(DOMAIN) + viewModel.onDomainsScreenFinished(FREE_DOMAIN) verify(wizardManager).showNextStep() } @Test fun siteCreationStateUpdatedWithSelectedDomain() { - viewModel.onDomainsScreenFinished(DOMAIN) - assertThat(currentWizardState(viewModel).domain).isEqualTo(DOMAIN) + viewModel.onDomainsScreenFinished(FREE_DOMAIN) + assertThat(currentWizardState(viewModel).domain).isEqualTo(FREE_DOMAIN) } @Test diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index f0426c03d053..286eb7c1355f 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -21,11 +21,11 @@ import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged -import org.wordpress.android.ui.sitecreation.ERROR_RESPONSE +import org.wordpress.android.ui.sitecreation.FETCH_ERROR import org.wordpress.android.ui.sitecreation.SITE_CREATION_STATE import org.wordpress.android.ui.sitecreation.SITE_REMOTE_ID import org.wordpress.android.ui.sitecreation.SUB_DOMAIN -import org.wordpress.android.ui.sitecreation.SUCCESS_RESPONSE +import org.wordpress.android.ui.sitecreation.FETCH_SUCCESS import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.URL @@ -82,13 +82,13 @@ class SitePreviewViewModelTest : BaseUnitTest() { } @Test - fun `on start fetches site by remote id`() = testWith(SUCCESS_RESPONSE) { + fun `on start fetches site by remote id`() = testWith(FETCH_SUCCESS) { startViewModel() verify(fetchWpComSiteUseCase).fetchSiteWithRetry(SITE_REMOTE_ID) } @Test - fun `on start does not show preview when fetching fails`() = testWith(ERROR_RESPONSE) { + fun `on start does not show preview when fetching fails`() = testWith(FETCH_ERROR) { startViewModel() verify(siteStore, never()).getSiteBySiteId(SITE_REMOTE_ID) viewModel.onOkButtonClicked() @@ -126,7 +126,7 @@ class SitePreviewViewModelTest : BaseUnitTest() { } @Test - fun `on ok button click is propagated`() = testWith(SUCCESS_RESPONSE) { + fun `on ok button click is propagated`() = testWith(FETCH_SUCCESS) { startViewModel() viewModel.onOkButtonClicked() verify(onOkClickedObserver).onChanged(anyOrNull()) From 9daedfa7563d4cd6aa332fc671b8ba1527650c09 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 18:04:39 +0100 Subject: [PATCH 083/169] Fix: ignore InconsistentLayout linting like it was initially done --- .../res/layout-land/site_creation_preview_screen_default.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml b/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml index 4b75692ee81d..a4417aff34b3 100644 --- a/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml +++ b/WordPress/src/main/res/layout-land/site_creation_preview_screen_default.xml @@ -16,7 +16,8 @@ android:gravity="center" android:orientation="vertical" android:paddingStart="@dimen/margin_large" - android:paddingEnd="@dimen/margin_large"> + android:paddingEnd="@dimen/margin_large" + tools:ignore="InconsistentLayout"> Date: Mon, 13 Mar 2023 18:20:51 +0100 Subject: [PATCH 084/169] Refactor: rename into SiteCreationProgressViewModel matching class name --- .../ui/sitecreation/SiteCreationActivity.kt | 4 ++-- .../progress/SiteCreationProgressFragment.kt | 6 +++--- .../progress/SiteCreationProgressViewModel.kt | 8 ++++---- ...t.kt => SiteCreationProgressViewModelTest.kt} | 16 ++++++++-------- 4 files changed, 17 insertions(+), 17 deletions(-) rename WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/{SiteProgressViewModelTest.kt => SiteCreationProgressViewModelTest.kt} (87%) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 670d38b2e2a7..8878672f8321 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -43,7 +43,7 @@ import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.previews.SiteCreationPreviewFragment import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressFragment -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel import org.wordpress.android.ui.sitecreation.sitename.SiteCreationSiteNameFragment import org.wordpress.android.ui.sitecreation.sitename.SiteCreationSiteNameViewModel import org.wordpress.android.ui.sitecreation.sitename.SiteNameScreenListener @@ -78,7 +78,7 @@ class SiteCreationActivity : LocaleAwareActivity(), private val siteCreationIntentsViewModel: SiteCreationIntentsViewModel by viewModels() private val siteCreationSiteNameViewModel: SiteCreationSiteNameViewModel by viewModels() private val jetpackFullScreenViewModel: JetpackFeatureFullScreenOverlayViewModel by viewModels() - private val progressViewModel: SiteProgressViewModel by viewModels() + private val progressViewModel: SiteCreationProgressViewModel by viewModels() private val previewViewModel: SitePreviewViewModel by viewModels() @Inject internal lateinit var jetpackFeatureRemovalOverlayUtil: JetpackFeatureRemovalOverlayUtil diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt index af2bad837da7..1dbd3f9e6434 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt @@ -19,8 +19,8 @@ import org.wordpress.android.ui.accounts.HelpActivity import org.wordpress.android.ui.sitecreation.SiteCreationActivity.Companion.ARG_STATE import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.OnHelpClickedListener -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Loading +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState.Error +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState.Loading import org.wordpress.android.ui.sitecreation.services.SiteCreationService import org.wordpress.android.ui.utils.UiHelpers import org.wordpress.android.util.AniUtils @@ -41,7 +41,7 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc private var animatorSet: AnimatorSet? = null private lateinit var binding: SiteCreationProgressScreenBinding - private val viewModel: SiteProgressViewModel by activityViewModels() + private val viewModel: SiteCreationProgressViewModel by activityViewModels() override fun onAttach(context: Context) { super.onAttach(context) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index 564f8e184a1c..b3a7f81aa104 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -17,9 +17,9 @@ import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.UNKNOWN import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.ConnectionError -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.GenericError -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Loading +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState.Error.ConnectionError +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState.Error.GenericError +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState.Loading import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceData import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE @@ -46,7 +46,7 @@ private val loadingTexts = listOf( ) @HiltViewModel -class SiteProgressViewModel @Inject constructor( +class SiteCreationProgressViewModel @Inject constructor( private val networkUtils: NetworkUtilsWrapper, private val tracker: SiteCreationTracker, @Named(UI_THREAD) private val mainDispatcher: CoroutineDispatcher diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt similarity index 87% rename from WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt rename to WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt index 4eeae737d4e7..dfff11ebe70c 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt @@ -22,11 +22,11 @@ import org.wordpress.android.ui.sitecreation.SERVICE_SUCCESS import org.wordpress.android.ui.sitecreation.SITE_CREATION_STATE import org.wordpress.android.ui.sitecreation.SITE_REMOTE_ID import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.ConnectionError -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Error.GenericError -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.SiteProgressUiState.Loading -import org.wordpress.android.ui.sitecreation.progress.SiteProgressViewModel.StartServiceData +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState.Error.ConnectionError +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState.Error.GenericError +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState.Loading +import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.StartServiceData import org.wordpress.android.util.NetworkUtilsWrapper import kotlin.test.assertEquals import kotlin.test.assertIs @@ -34,7 +34,7 @@ import kotlin.test.assertNotNull @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) -class SiteProgressViewModelTest : BaseUnitTest() { +class SiteCreationProgressViewModelTest : BaseUnitTest() { private var networkUtils = mock() private var tracker = mock() @@ -44,11 +44,11 @@ class SiteProgressViewModelTest : BaseUnitTest() { private val onCancelWizardClickedObserver = mock>() private val onRemoteSiteCreatedObserver = mock>() - private lateinit var viewModel: SiteProgressViewModel + private lateinit var viewModel: SiteCreationProgressViewModel @Before fun setUp() { - viewModel = SiteProgressViewModel( + viewModel = SiteCreationProgressViewModel( networkUtils, tracker, testDispatcher(), From 065e659743f8227a4d6e35794a91a24322fb5bd3 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 18:56:49 +0100 Subject: [PATCH 085/169] Refactor: improve namings for site creation result --- .../android/ui/sitecreation/SiteCreationActivity.kt | 10 +++++----- .../android/ui/sitecreation/SiteCreationMainVM.kt | 8 ++------ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 8878672f8321..a659b8bcc9b8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -103,10 +103,10 @@ class SiteCreationActivity : LocaleAwareActivity(), private fun observeVMState() { mainViewModel.navigationTargetObservable .observe(this, Observer { target -> target?.let { showStep(target) } }) - mainViewModel.wizardFinishedObservable.observe(this, Observer { createSiteState -> - createSiteState?.let { + mainViewModel.wizardFinishedObservable.observe(this, Observer { result -> + result?.run { val intent = Intent() - val (siteCreated, localSiteId, titleTaskComplete) = when (createSiteState) { + val (siteCreated, localSiteId, titleTaskComplete) = when (this@run) { // site creation flow was canceled is NotCreated -> { Triple(false, null, false) @@ -115,10 +115,10 @@ class SiteCreationActivity : LocaleAwareActivity(), // Site was created, but we haven't been able to fetch it, let `SitePickerActivity` handle // this with a Snackbar message. intent.putExtra(SitePickerActivity.KEY_SITE_CREATED_BUT_NOT_FETCHED, true) - Triple(true, null, createSiteState.isSiteTitleTaskComplete) + Triple(true, null, isSiteTitleTaskComplete) } is Completed -> { - Triple(true, createSiteState.localSiteId, createSiteState.isSiteTitleTaskComplete) + Triple(true, localId, isSiteTitleTaskComplete) } } intent.putExtra(SitePickerActivity.KEY_SITE_LOCAL_ID, localSiteId) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 15d0923b7648..b6379f2367b7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -65,14 +65,10 @@ sealed interface SiteCreationResult : Parcelable { object NotCreated : SiteCreationResult @Parcelize - data class NotInLocalDb(val remoteSiteId: Long, val isSiteTitleTaskComplete: Boolean) : SiteCreationResult + data class NotInLocalDb(val remoteId: Long, val isSiteTitleTaskComplete: Boolean) : SiteCreationResult @Parcelize - data class Completed( - val localSiteId: Int, - val isSiteTitleTaskComplete: Boolean, - val url: String, - ) : SiteCreationResult + data class Completed(val localId: Int, val isSiteTitleTaskComplete: Boolean, val url: String) : SiteCreationResult } @HiltViewModel From 2559ef9f33835b36a85f20f6978a5c7605d1f44a Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 19:38:13 +0100 Subject: [PATCH 086/169] Refactor: remove unneeded private fields from vm --- .../ui/sitecreation/SiteCreationMainVM.kt | 10 +++++++-- .../previews/SitePreviewViewModel.kt | 22 ++++++++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index b6379f2367b7..8b83849d8516 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -23,6 +23,7 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker @@ -56,7 +57,9 @@ data class SiteCreationState( val domain: DomainModel? = null, val remoteSiteId: Long? = null, val result: SiteCreationResult = NotCreated, -) : WizardState, Parcelable +) : WizardState, Parcelable { + fun isSiteTitleStepCompleted() = !siteName.isNullOrBlank() +} typealias NavigationTarget = WizardNavigationTarget @@ -261,7 +264,10 @@ class SiteCreationMainVM @Inject constructor( } fun onProgressScreenFinished(remoteSiteId: Long) { - siteCreationState = siteCreationState.copy(remoteSiteId = remoteSiteId) + siteCreationState = siteCreationState.copy( + remoteSiteId = remoteSiteId, + result = NotInLocalDb(remoteSiteId, siteCreationState.isSiteTitleStepCompleted()) + ) wizardManager.showNextStep() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 05c92a31957e..321f4896f5a2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -10,6 +10,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD @@ -58,9 +59,7 @@ class SitePreviewViewModel @Inject constructor( private var webviewFullyLoadedTracked = false private var siteDesign: String? = null - private var siteTitle: String? = null private var urlWithoutScheme: String? = null - private var remoteSiteId: Long = 0 private lateinit var result: SiteCreationResult @@ -78,13 +77,18 @@ class SitePreviewViewModel @Inject constructor( isStarted = true siteDesign = siteCreationState.siteDesign - siteTitle = siteCreationState.siteName urlWithoutScheme = requireNotNull(siteCreationState.domain) { "url required for preview" }.domainName - remoteSiteId = requireNotNull(siteCreationState.remoteSiteId) { "remoteSiteId required for preview" } + + val remoteSiteId = requireNotNull(siteCreationState.remoteSiteId) { "remoteSiteId required for preview" } + val isTitleCustomized = siteCreationState.isSiteTitleStepCompleted() startPreLoadingWebView() + + result = NotInLocalDb(siteCreationState.remoteSiteId, isTitleCustomized) launch { - result = fetchNewlyCreatedSiteModel(remoteSiteId) + fetchNewlyCreatedSiteModel(remoteSiteId)?.run { + result = Completed(id, isTitleCustomized, url) + } } } @@ -121,16 +125,14 @@ class SitePreviewViewModel @Inject constructor( /** * Fetch newly created site model - supports retry with linear backoff. */ - private suspend fun fetchNewlyCreatedSiteModel(remoteSiteId: Long): SiteCreationResult { + private suspend fun fetchNewlyCreatedSiteModel(remoteSiteId: Long): SiteModel? { val onSiteFetched = fetchWpComSiteUseCase.fetchSiteWithRetry(remoteSiteId) - val isSiteTitleTaskComplete = !siteTitle.isNullOrBlank() return if (!onSiteFetched.isError) { - val siteBySiteId = requireNotNull(siteStore.getSiteBySiteId(remoteSiteId)) { + return requireNotNull(siteStore.getSiteBySiteId(remoteSiteId)) { "Site successfully fetched but has not been found in the local db." } - Completed(siteBySiteId.id, isSiteTitleTaskComplete, siteBySiteId.url) } else { - NotInLocalDb(remoteSiteId, isSiteTitleTaskComplete) + null } } From b0c9eb9d1b49ce40e92c8f1d179d7d05d0e8cb95 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 13 Mar 2023 19:58:25 +0100 Subject: [PATCH 087/169] Update: Fetch site only if its not in local db to support restoration --- .../previews/SitePreviewViewModel.kt | 16 +++++++--------- .../ui/sitecreation/SiteCreationFixtures.kt | 2 ++ .../previews/SitePreviewViewModelTest.kt | 7 ++++--- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 321f4896f5a2..4272463dfdb5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -78,16 +78,14 @@ class SitePreviewViewModel @Inject constructor( siteDesign = siteCreationState.siteDesign urlWithoutScheme = requireNotNull(siteCreationState.domain) { "url required for preview" }.domainName - - val remoteSiteId = requireNotNull(siteCreationState.remoteSiteId) { "remoteSiteId required for preview" } - val isTitleCustomized = siteCreationState.isSiteTitleStepCompleted() - startPreLoadingWebView() - - result = NotInLocalDb(siteCreationState.remoteSiteId, isTitleCustomized) - launch { - fetchNewlyCreatedSiteModel(remoteSiteId)?.run { - result = Completed(id, isTitleCustomized, url) + result = siteCreationState.result.also { + if (it is NotInLocalDb) { + launch { + fetchNewlyCreatedSiteModel(it.remoteId)?.run { + result = Completed(id, siteCreationState.isSiteTitleStepCompleted(), url) + } + } } } } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index f3e59969501d..60acfb148561 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -4,6 +4,7 @@ import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged import org.wordpress.android.fluxc.store.SiteStore.SiteError import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType.GENERIC_ERROR import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed +import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE @@ -28,6 +29,7 @@ val SITE_CREATION_STATE = SiteCreationState( val FETCH_SUCCESS = OnSiteChanged(1) val FETCH_ERROR = OnSiteChanged(0).apply { error = SiteError(GENERIC_ERROR) } +val RESULT_CREATED = NotInLocalDb(SITE_REMOTE_ID, false) val RESULT_COMPLETED = Completed(SITE_LOCAL_ID, false, URL) val SERVICE_SUCCESS = SiteCreationServiceState(SUCCESS, Pair(SITE_REMOTE_ID, URL)) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index 286eb7c1355f..0013944e817c 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -22,10 +22,11 @@ import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged import org.wordpress.android.ui.sitecreation.FETCH_ERROR +import org.wordpress.android.ui.sitecreation.FETCH_SUCCESS +import org.wordpress.android.ui.sitecreation.RESULT_CREATED import org.wordpress.android.ui.sitecreation.SITE_CREATION_STATE import org.wordpress.android.ui.sitecreation.SITE_REMOTE_ID import org.wordpress.android.ui.sitecreation.SUB_DOMAIN -import org.wordpress.android.ui.sitecreation.FETCH_SUCCESS import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.URL @@ -82,8 +83,8 @@ class SitePreviewViewModelTest : BaseUnitTest() { } @Test - fun `on start fetches site by remote id`() = testWith(FETCH_SUCCESS) { - startViewModel() + fun `on start fetches site by remote id when result is created`() = testWith(FETCH_SUCCESS) { + startViewModel(SITE_CREATION_STATE.copy(result = RESULT_CREATED)) verify(fetchWpComSiteUseCase).fetchSiteWithRetry(SITE_REMOTE_ID) } From b57c49af449890be8587ef97858cce6165b84752 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 14 Mar 2023 20:36:06 +0100 Subject: [PATCH 088/169] Refactor: replace when with if when clearing old state --- .../wordpress/android/ui/sitecreation/SiteCreationMainVM.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 8b83849d8516..5623d639d741 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -231,11 +231,10 @@ class SiteCreationMainVM @Inject constructor( } private fun clearOldSiteCreationState(wizardStep: SiteCreationStep) { - when (wizardStep) { - SiteCreationStep.DOMAINS -> siteCreationState.domain?.let { + if (wizardStep == SiteCreationStep.DOMAINS) { + siteCreationState.domain?.let { siteCreationState = siteCreationState.copy(domain = null) } - else -> Unit // Do nothing } } From b9f078e44bf7dc9d7e5d30f7338a6e964e8ed0f4 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 14 Mar 2023 20:39:18 +0100 Subject: [PATCH 089/169] Refactor: replace run with let --- .../previews/SiteCreationPreviewFragment.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 49cfb57890ba..320e3c92a802 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -83,16 +83,16 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), private fun SiteCreationPreviewScreenDefaultBinding.observeState() { viewModel.uiState.observe(this@SiteCreationPreviewFragment) { - it?.run { - when (val ui = this@run) { + it?.let { ui -> + when (ui) { is SitePreviewContentUiState -> updateContentLayout(ui.data) is SitePreviewWebErrorUiState -> updateContentLayout(ui.data) is SitePreviewLoadingShimmerState -> updateContentLayout(ui.data, isFirstContent = true) } siteCreationPreviewWebViewContainer.apply { - uiHelpers.updateVisibility(sitePreviewWebView, webViewVisibility) - uiHelpers.updateVisibility(sitePreviewWebError, webViewErrorVisibility) - uiHelpers.updateVisibility(sitePreviewWebViewShimmerLayout, shimmerVisibility) + uiHelpers.updateVisibility(sitePreviewWebView, ui.webViewVisibility) + uiHelpers.updateVisibility(sitePreviewWebError, ui.webViewErrorVisibility) + uiHelpers.updateVisibility(sitePreviewWebViewShimmerLayout, ui.shimmerVisibility) } } } From 56c9c6be14087bf14555ec6c512bc489a91d2a69 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 14 Mar 2023 20:42:49 +0100 Subject: [PATCH 090/169] Refactor: replace code to show fragment using ktx --- .../android/ui/sitecreation/SiteCreationActivity.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index a659b8bcc9b8..69f41e41baf6 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -6,6 +6,7 @@ import android.os.Bundle import android.view.MenuItem import androidx.activity.viewModels import androidx.fragment.app.Fragment +import androidx.fragment.app.commit import androidx.lifecycle.Observer import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.cancel @@ -258,10 +259,10 @@ class SiteCreationActivity : LocaleAwareActivity(), } private fun showFragment(fragment: Fragment, tag: String, slideIn: Boolean = true) { - val fragmentTransaction = supportFragmentManager.beginTransaction() - if (supportFragmentManager.findFragmentById(R.id.fragment_container) != null) { - // add to back stack and animate all screen except of the first one - fragmentTransaction.addToBackStack(null).apply { + supportFragmentManager.commit { + if (supportFragmentManager.findFragmentById(R.id.fragment_container) != null) { + // add to back stack and animate all screen except of the first one + addToBackStack(null) if (slideIn) { setCustomAnimations( R.anim.activity_slide_in_from_right, R.anim.activity_slide_out_to_left, @@ -271,9 +272,8 @@ class SiteCreationActivity : LocaleAwareActivity(), setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) } } + replace(R.id.fragment_container, fragment, tag) } - fragmentTransaction.replace(R.id.fragment_container, fragment, tag) - fragmentTransaction.commit() } override fun onPositiveClicked(instanceTag: String) { From dd7f730f827557e071e87493ae3874982020c05c Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 14 Mar 2023 21:02:39 +0100 Subject: [PATCH 091/169] Refactor: inherit from scoped vm --- .../progress/SiteCreationProgressViewModel.kt | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index b3a7f81aa104..f06a0e766a83 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -2,13 +2,10 @@ package org.wordpress.android.ui.sitecreation.progress import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import org.wordpress.android.R @@ -29,10 +26,10 @@ import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.S import org.wordpress.android.ui.utils.UiString import org.wordpress.android.ui.utils.UiString.UiStringRes import org.wordpress.android.util.NetworkUtilsWrapper +import org.wordpress.android.viewmodel.ScopedViewModel import org.wordpress.android.viewmodel.SingleLiveEvent import javax.inject.Inject import javax.inject.Named -import kotlin.coroutines.CoroutineContext private const val CONNECTION_ERROR_DELAY_TO_SHOW_LOADING_STATE = 1000L const val LOADING_STATE_TEXT_ANIMATION_DELAY = 2000L @@ -49,10 +46,8 @@ private val loadingTexts = listOf( class SiteCreationProgressViewModel @Inject constructor( private val networkUtils: NetworkUtilsWrapper, private val tracker: SiteCreationTracker, - @Named(UI_THREAD) private val mainDispatcher: CoroutineDispatcher -) : ViewModel(), CoroutineScope { - private val job = Job() - override val coroutineContext: CoroutineContext get() = mainDispatcher + job + @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, +) : ScopedViewModel(mainDispatcher) { private var isStarted = false private var loadingAnimationJob: Job? = null @@ -80,7 +75,6 @@ class SiteCreationProgressViewModel @Inject constructor( override fun onCleared() { super.onCleared() - job.cancel() loadingAnimationJob?.cancel() } @@ -125,7 +119,7 @@ class SiteCreationProgressViewModel @Inject constructor( private fun showFullscreenErrorWithDelay() { runLoadingAnimationUi() - launch(mainDispatcher) { + launch { // We show the loading indicator for a bit so the user has some feedback when they press retry delay(CONNECTION_ERROR_DELAY_TO_SHOW_LOADING_STATE) tracker.trackErrorShown(ERROR_CONTEXT, INTERNET_UNAVAILABLE_ERROR) @@ -165,7 +159,7 @@ class SiteCreationProgressViewModel @Inject constructor( private fun runLoadingAnimationUi() { loadingAnimationJob?.cancel() - loadingAnimationJob = launch(mainDispatcher) { + loadingAnimationJob = launch { loadingTexts.forEachIndexed { i, uiString -> updateUiState( Loading( From 44d918cfb2bd12af41c038224c10ee3ed1ecf44b Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 14 Mar 2023 20:18:13 +0100 Subject: [PATCH 092/169] Update fluxC version to PR 2676 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b233c935fd2e..e4ba6b2f75f7 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ ext { automatticTracksVersion = '2.2.0' gutenbergMobileVersion = 'v1.91.0' wordPressAztecVersion = 'v1.6.3' - wordPressFluxCVersion = '2.17.0' + wordPressFluxCVersion = '2676-5b0dc33a1b574192660a032900642e19874192a3' wordPressLoginVersion = '1.0.0' wordPressPersistentEditTextVersion = '1.0.2' wordPressUtilsVersion = '3.3.0' From 4391124d667fa143e67e11b61862173f407d27af Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 14 Mar 2023 20:20:08 +0100 Subject: [PATCH 093/169] Update: pass findAvailableUrl for paid domain when creating site --- .../ui/sitecreation/progress/SiteCreationProgressViewModel.kt | 3 ++- .../ui/sitecreation/services/SiteCreationServiceData.kt | 3 ++- .../android/ui/sitecreation/usecases/CreateSiteUseCase.kt | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index f06a0e766a83..b2773b37cd0c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -99,7 +99,8 @@ class SiteCreationProgressViewModel @Inject constructor( segmentIdentifier, siteDesign, urlWithoutScheme, - siteTitle + siteTitle, + requireNotNull(siteCreationState.domain?.isFree) { "domain required to create a site" }, ) _startCreateSiteService.value = StartServiceData(serviceData, previousState) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceData.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceData.kt index 14f32fa688e5..7df837d1e770 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceData.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceData.kt @@ -10,5 +10,6 @@ data class SiteCreationServiceData( val segmentId: Long?, val siteDesign: String?, val domain: String?, - val title: String? + val title: String?, + val isFree: Boolean, ) : Parcelable diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/CreateSiteUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/CreateSiteUseCase.kt index 5ad93e6f89a0..662d1d15e845 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/CreateSiteUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/CreateSiteUseCase.kt @@ -60,7 +60,8 @@ class CreateSiteUseCase @Inject constructor( siteVisibility, siteData.segmentId, siteData.siteDesign, - dryRun + dryRun, + findAvailableUrl = siteData.isFree.takeIf { !it } ) continuation = cont dispatcher.dispatch(SiteActionBuilder.newCreateNewSiteAction(newSitePayload)) From 3883b7a5cd15ceb5066559717ed048285974e0b6 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 14 Mar 2023 20:20:41 +0100 Subject: [PATCH 094/169] Refactor: add newline to separate service state fields from others --- .../ui/sitecreation/progress/SiteCreationProgressViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index b2773b37cd0c..80fc919ec5f2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -55,6 +55,7 @@ class SiteCreationProgressViewModel @Inject constructor( private var urlWithoutScheme: String? = null private var siteTitle: String? = null + private var lastReceivedServiceState: SiteCreationServiceState? = null private var serviceStateForRetry: SiteCreationServiceState? = null From e090e263c1005182ef4309a9e965c54eee9e1cf4 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 14 Mar 2023 20:21:37 +0100 Subject: [PATCH 095/169] Add: print isFree value when logging create site action dispatch --- .../ui/sitecreation/services/SiteCreationServiceManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceManager.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceManager.kt index 799013410b11..86a62720f401 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceManager.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceManager.kt @@ -105,7 +105,7 @@ class SiteCreationServiceManager @Inject constructor( launch { AppLog.i( T.SITE_CREATION, - "Dispatching Create Site Action, SiteName: ${siteData.domain}" + "Dispatching Create Site Action, SiteName: ${siteData.domain}, isFree: ${siteData.isFree}" ) val createSiteEvent: OnNewSiteCreated try { From 2240b2525bdc38cb9ae1e1568e3ca0baba12d3e9 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 14 Mar 2023 20:22:36 +0100 Subject: [PATCH 096/169] Test: logic related to findAvailableUrl --- .../ui/sitecreation/SiteCreationFixtures.kt | 1 + .../previews/CreateSiteUseCaseTest.kt | 13 ++++++++++- .../SiteCreationProgressViewModelTest.kt | 22 +++++++++++++++++-- .../SiteCreationServiceManagerTest.kt | 3 ++- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index 60acfb148561..4cff0dc25d2c 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -15,6 +15,7 @@ import org.wordpress.android.ui.sitecreation.theme.defaultTemplateSlug const val SUB_DOMAIN = "test" const val URL = "$SUB_DOMAIN.wordpress.com" val FREE_DOMAIN = DomainModel(URL, true, "", 1) +val PAID_DOMAIN = DomainModel(URL, false, "$1", 2) const val SITE_REMOTE_ID = 1L private const val SITE_LOCAL_ID = 1 diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt index 0cbf77042355..dc5d41981e46 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt @@ -9,6 +9,7 @@ import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any +import org.mockito.kotlin.argWhere import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest @@ -22,13 +23,15 @@ import org.wordpress.android.fluxc.store.SiteStore.SiteVisibility import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceData import org.wordpress.android.ui.sitecreation.usecases.CreateSiteUseCase import org.wordpress.android.util.UrlUtilsWrapper +import kotlin.test.assertFalse private const val SITE_TITLE = "site title" private val DUMMY_SITE_DATA: SiteCreationServiceData = SiteCreationServiceData( 123, "slug", "domain", - SITE_TITLE + SITE_TITLE, + false, ) private const val LANGUAGE_ID = "lang_id" private const val TIMEZONE_ID = "timezone_id" @@ -75,6 +78,14 @@ class CreateSiteUseCaseTest : BaseUnitTest() { assertThat(payload.siteName).isEqualTo(DUMMY_SITE_DATA.domain) assertThat(payload.segmentId).isEqualTo(DUMMY_SITE_DATA.segmentId) assertThat(payload.siteTitle).isEqualTo(SITE_TITLE) + assertFalse(payload.findAvailableUrl!!) + } + + @Test + fun verifySiteDataWhenFreePropagatesNoFindAvailableUrl() = test { + whenever(dispatcher.dispatch(any())).then { useCase.onNewSiteCreated(event) } + useCase.createSite(DUMMY_SITE_DATA.copy(isFree = true), LANGUAGE_ID, TIMEZONE_ID) + verify(dispatcher).dispatch(argWhere { (it.payload as NewSitePayload).findAvailableUrl == null }) } @Test diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt index dfff11ebe70c..241db62af1d6 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt @@ -17,10 +17,12 @@ import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest +import org.wordpress.android.ui.sitecreation.PAID_DOMAIN import org.wordpress.android.ui.sitecreation.SERVICE_ERROR import org.wordpress.android.ui.sitecreation.SERVICE_SUCCESS import org.wordpress.android.ui.sitecreation.SITE_CREATION_STATE import org.wordpress.android.ui.sitecreation.SITE_REMOTE_ID +import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState.Error.ConnectionError @@ -29,8 +31,10 @@ import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewMo import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.StartServiceData import org.wordpress.android.util.NetworkUtilsWrapper import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertIs import kotlin.test.assertNotNull +import kotlin.test.assertTrue @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) @@ -74,6 +78,20 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { assertNotNull(viewModel.startCreateSiteService.value) } + @Test + fun `on start emits service event for free domains with isFree true`() = test { + startViewModel(SITE_CREATION_STATE) + val request = assertNotNull(viewModel.startCreateSiteService.value).serviceData + assertTrue(request.isFree) + } + + @Test + fun `on start emits service event for paid domains with isFree false`() = test { + startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN)) + val request = assertNotNull(viewModel.startCreateSiteService.value).serviceData + assertFalse(request.isFree) + } + @Test fun `on start shows error when network is not available`() = test { whenever(networkUtils.isNetworkAvailable()).thenReturn(false) @@ -151,8 +169,8 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { // region Helpers - private fun startViewModel() { - viewModel.start( SITE_CREATION_STATE) + private fun startViewModel(state: SiteCreationState = SITE_CREATION_STATE) { + viewModel.start(state) } // endregion diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceManagerTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceManagerTest.kt index 3b76e62a929a..a70333b10838 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceManagerTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/services/SiteCreationServiceManagerTest.kt @@ -34,7 +34,8 @@ private val DUMMY_SITE_DATA: SiteCreationServiceData = SiteCreationServiceData( 123, "slug", "domain", - null + null, + true, ) private val IDLE_STATE = SiteCreationServiceState(IDLE) From 7aa0b06138333a06eadbfa9f2c6e5fe1e205a8b2 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 15 Mar 2023 10:18:56 +0100 Subject: [PATCH 097/169] Update: fix logic and tests for finding available url via api --- .../android/ui/sitecreation/usecases/CreateSiteUseCase.kt | 2 +- .../android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/CreateSiteUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/CreateSiteUseCase.kt index 662d1d15e845..1e190e2a4c5e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/CreateSiteUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/usecases/CreateSiteUseCase.kt @@ -61,7 +61,7 @@ class CreateSiteUseCase @Inject constructor( siteData.segmentId, siteData.siteDesign, dryRun, - findAvailableUrl = siteData.isFree.takeIf { !it } + findAvailableUrl = if (siteData.isFree) null else true ) continuation = cont dispatcher.dispatch(SiteActionBuilder.newCreateNewSiteAction(newSitePayload)) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt index dc5d41981e46..99830137f855 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt @@ -23,7 +23,7 @@ import org.wordpress.android.fluxc.store.SiteStore.SiteVisibility import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceData import org.wordpress.android.ui.sitecreation.usecases.CreateSiteUseCase import org.wordpress.android.util.UrlUtilsWrapper -import kotlin.test.assertFalse +import kotlin.test.assertTrue private const val SITE_TITLE = "site title" private val DUMMY_SITE_DATA: SiteCreationServiceData = SiteCreationServiceData( @@ -78,7 +78,7 @@ class CreateSiteUseCaseTest : BaseUnitTest() { assertThat(payload.siteName).isEqualTo(DUMMY_SITE_DATA.domain) assertThat(payload.segmentId).isEqualTo(DUMMY_SITE_DATA.segmentId) assertThat(payload.siteTitle).isEqualTo(SITE_TITLE) - assertFalse(payload.findAvailableUrl!!) + assertTrue(payload.findAvailableUrl!!) } @Test From cdc37dbfe5cf4ccab50969bd82a4e19e8742acb6 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 15 Mar 2023 11:47:18 +0100 Subject: [PATCH 098/169] Test: move stubbing to setUp --- .../ui/sitecreation/previews/CreateSiteUseCaseTest.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt index 99830137f855..73e86d12b13b 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt @@ -54,11 +54,11 @@ class CreateSiteUseCaseTest : BaseUnitTest() { fun setUp() { useCase = CreateSiteUseCase(dispatcher, store, urlUtilsWrapper) event = OnNewSiteCreated(newSiteRemoteId = 123) + whenever(dispatcher.dispatch(any())).then { useCase.onNewSiteCreated(event) } } @Test fun coroutineResumedWhenResultEventDispatched() = test { - whenever(dispatcher.dispatch(any())).then { useCase.onNewSiteCreated(event) } val resultEvent = useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) assertThat(resultEvent).isEqualTo(event) @@ -66,7 +66,6 @@ class CreateSiteUseCaseTest : BaseUnitTest() { @Test fun verifySiteDataPropagated() = test { - whenever(dispatcher.dispatch(any())).then { useCase.onNewSiteCreated(event) } useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) val captor = ArgumentCaptor.forClass(Action::class.java) @@ -83,14 +82,12 @@ class CreateSiteUseCaseTest : BaseUnitTest() { @Test fun verifySiteDataWhenFreePropagatesNoFindAvailableUrl() = test { - whenever(dispatcher.dispatch(any())).then { useCase.onNewSiteCreated(event) } useCase.createSite(DUMMY_SITE_DATA.copy(isFree = true), LANGUAGE_ID, TIMEZONE_ID) verify(dispatcher).dispatch(argWhere { (it.payload as NewSitePayload).findAvailableUrl == null }) } @Test fun verifyDryRunIsFalse() = test { - whenever(dispatcher.dispatch(any())).then { useCase.onNewSiteCreated(event) } useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) val captor = ArgumentCaptor.forClass(Action::class.java) @@ -102,7 +99,6 @@ class CreateSiteUseCaseTest : BaseUnitTest() { @Test fun verifyCreatesPublicSite() = test { - whenever(dispatcher.dispatch(any())).then { useCase.onNewSiteCreated(event) } useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) val captor = ArgumentCaptor.forClass(Action::class.java) @@ -114,7 +110,6 @@ class CreateSiteUseCaseTest : BaseUnitTest() { @Test fun verifyPropagatesLanguageId() = test { - whenever(dispatcher.dispatch(any())).then { useCase.onNewSiteCreated(event) } useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) val captor = ArgumentCaptor.forClass(Action::class.java) @@ -126,7 +121,6 @@ class CreateSiteUseCaseTest : BaseUnitTest() { @Test fun verifyPropagatesTimeZoneId() = test { - whenever(dispatcher.dispatch(any())).then { useCase.onNewSiteCreated(event) } useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) val captor = ArgumentCaptor.forClass(Action::class.java) From f204a00f3445b49a6a5e1e6793da5ea5feab94da Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 15 Mar 2023 12:35:28 +0100 Subject: [PATCH 099/169] Test: replace imperative captors with typed argThat extension --- .../previews/CreateSiteUseCaseTest.kt | 57 ++++++------------- 1 file changed, 17 insertions(+), 40 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt index 73e86d12b13b..27dfebbe5f9c 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt @@ -5,16 +5,14 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any -import org.mockito.kotlin.argWhere +import org.mockito.kotlin.argThat import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest import org.wordpress.android.fluxc.Dispatcher -import org.wordpress.android.fluxc.action.SiteAction import org.wordpress.android.fluxc.annotations.action.Action import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.fluxc.store.SiteStore.NewSitePayload @@ -23,7 +21,8 @@ import org.wordpress.android.fluxc.store.SiteStore.SiteVisibility import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceData import org.wordpress.android.ui.sitecreation.usecases.CreateSiteUseCase import org.wordpress.android.util.UrlUtilsWrapper -import kotlin.test.assertTrue +import kotlin.test.assertEquals +import kotlin.test.assertNotNull private const val SITE_TITLE = "site title" private val DUMMY_SITE_DATA: SiteCreationServiceData = SiteCreationServiceData( @@ -60,7 +59,6 @@ class CreateSiteUseCaseTest : BaseUnitTest() { @Test fun coroutineResumedWhenResultEventDispatched() = test { val resultEvent = useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) - assertThat(resultEvent).isEqualTo(event) } @@ -68,65 +66,44 @@ class CreateSiteUseCaseTest : BaseUnitTest() { fun verifySiteDataPropagated() = test { useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) - val captor = ArgumentCaptor.forClass(Action::class.java) - verify(dispatcher).dispatch(captor.capture()) - - assertThat(captor.value.type).isEqualTo(SiteAction.CREATE_NEW_SITE) - assertThat(captor.value.payload).isInstanceOf(NewSitePayload::class.java) - val payload = captor.value.payload as NewSitePayload - assertThat(payload.siteName).isEqualTo(DUMMY_SITE_DATA.domain) - assertThat(payload.segmentId).isEqualTo(DUMMY_SITE_DATA.segmentId) - assertThat(payload.siteTitle).isEqualTo(SITE_TITLE) - assertTrue(payload.findAvailableUrl!!) + verify(dispatcher).dispatch(argPayload { + assertEquals(siteName, DUMMY_SITE_DATA.domain) + assertEquals(segmentId, DUMMY_SITE_DATA.segmentId) + assertEquals(siteTitle, SITE_TITLE) + val findAvailableUrl = assertNotNull(findAvailableUrl) + findAvailableUrl + }) } @Test fun verifySiteDataWhenFreePropagatesNoFindAvailableUrl() = test { useCase.createSite(DUMMY_SITE_DATA.copy(isFree = true), LANGUAGE_ID, TIMEZONE_ID) - verify(dispatcher).dispatch(argWhere { (it.payload as NewSitePayload).findAvailableUrl == null }) + verify(dispatcher).dispatch(argPayload { findAvailableUrl == null }) } @Test fun verifyDryRunIsFalse() = test { useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) - - val captor = ArgumentCaptor.forClass(Action::class.java) - verify(dispatcher).dispatch(captor.capture()) - - val payload = captor.value.payload as NewSitePayload - assertThat(payload.dryRun).isEqualTo(false) + verify(dispatcher).dispatch(argPayload { !dryRun }) } @Test fun verifyCreatesPublicSite() = test { useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) - - val captor = ArgumentCaptor.forClass(Action::class.java) - verify(dispatcher).dispatch(captor.capture()) - - val payload = captor.value.payload as NewSitePayload - assertThat(payload.visibility).isEqualTo(SiteVisibility.PUBLIC) + verify(dispatcher).dispatch(argPayload { visibility == SiteVisibility.PUBLIC }) } @Test fun verifyPropagatesLanguageId() = test { useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) - - val captor = ArgumentCaptor.forClass(Action::class.java) - verify(dispatcher).dispatch(captor.capture()) - - val payload = captor.value.payload as NewSitePayload - assertThat(payload.language).isEqualTo(LANGUAGE_ID) + verify(dispatcher).dispatch(argPayload { language == LANGUAGE_ID }) } @Test fun verifyPropagatesTimeZoneId() = test { useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) - - val captor = ArgumentCaptor.forClass(Action::class.java) - verify(dispatcher).dispatch(captor.capture()) - - val payload = captor.value.payload as NewSitePayload - assertThat(payload.timeZoneId).isEqualTo(TIMEZONE_ID) + verify(dispatcher).dispatch(argPayload { timeZoneId == TIMEZONE_ID }) } } + +fun argPayload(predicate: NewSitePayload.() -> Boolean) = argThat> { predicate(payload) } From 6c3e50d71adf2a3367d82666820cd25dc3c97ada Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 16 Mar 2023 11:20:30 +0100 Subject: [PATCH 100/169] Update: fluxC version after merging PR 2676 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e4ba6b2f75f7..26109506b9fa 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ ext { automatticTracksVersion = '2.2.0' gutenbergMobileVersion = 'v1.91.0' wordPressAztecVersion = 'v1.6.3' - wordPressFluxCVersion = '2676-5b0dc33a1b574192660a032900642e19874192a3' + wordPressFluxCVersion = 'trunk-314cad0eed02a26dd51b7b17a2813de097f0c43e' wordPressLoginVersion = '1.0.0' wordPressPersistentEditTextVersion = '1.0.2' wordPressUtilsVersion = '3.3.0' From 571df8aae8b5644498f25ec5ed788d32ac3912d5 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 16 Mar 2023 11:33:00 +0100 Subject: [PATCH 101/169] Update: fluxC version to latest commit on trunk --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 26109506b9fa..9c57f8390390 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ ext { automatticTracksVersion = '2.2.0' gutenbergMobileVersion = 'v1.91.0' wordPressAztecVersion = 'v1.6.3' - wordPressFluxCVersion = 'trunk-314cad0eed02a26dd51b7b17a2813de097f0c43e' + wordPressFluxCVersion = 'trunk-aff6f17db9549bc47bc4e6372c8d8f32e62b65bb' wordPressLoginVersion = '1.0.0' wordPressPersistentEditTextVersion = '1.0.2' wordPressUtilsVersion = '3.3.0' From 650e99e88463ef1d01e7415af8570070faf5ba95 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 16 Mar 2023 11:33:23 +0100 Subject: [PATCH 102/169] Test: reuse site creation fixtures in use case test --- .../ui/sitecreation/previews/CreateSiteUseCaseTest.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt index 27dfebbe5f9c..b692185ef8c6 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt @@ -18,6 +18,7 @@ import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.fluxc.store.SiteStore.NewSitePayload import org.wordpress.android.fluxc.store.SiteStore.OnNewSiteCreated import org.wordpress.android.fluxc.store.SiteStore.SiteVisibility +import org.wordpress.android.ui.sitecreation.FREE_DOMAIN import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceData import org.wordpress.android.ui.sitecreation.usecases.CreateSiteUseCase import org.wordpress.android.util.UrlUtilsWrapper @@ -28,9 +29,9 @@ private const val SITE_TITLE = "site title" private val DUMMY_SITE_DATA: SiteCreationServiceData = SiteCreationServiceData( 123, "slug", - "domain", + FREE_DOMAIN.domainName, SITE_TITLE, - false, + FREE_DOMAIN.isFree, ) private const val LANGUAGE_ID = "lang_id" private const val TIMEZONE_ID = "timezone_id" From 71c82db60391eda7840bafeda8566aa64ca8765f Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 16 Mar 2023 14:08:19 +0100 Subject: [PATCH 103/169] Test: fix and cleanup tests --- .../ui/sitecreation/SiteCreationFixtures.kt | 3 +- .../previews/CreateSiteUseCaseTest.kt | 44 ++++++++++++------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index 4cff0dc25d2c..d61bf9c41a2e 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -14,8 +14,9 @@ import org.wordpress.android.ui.sitecreation.theme.defaultTemplateSlug const val SUB_DOMAIN = "test" const val URL = "$SUB_DOMAIN.wordpress.com" +const val URL_CUSTOM = "$SUB_DOMAIN.host.com" val FREE_DOMAIN = DomainModel(URL, true, "", 1) -val PAID_DOMAIN = DomainModel(URL, false, "$1", 2) +val PAID_DOMAIN = DomainModel(URL_CUSTOM, false, "$1", 2) const val SITE_REMOTE_ID = 1L private const val SITE_LOCAL_ID = 1 diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt index b692185ef8c6..bbecfe3041ba 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/CreateSiteUseCaseTest.kt @@ -19,6 +19,8 @@ import org.wordpress.android.fluxc.store.SiteStore.NewSitePayload import org.wordpress.android.fluxc.store.SiteStore.OnNewSiteCreated import org.wordpress.android.fluxc.store.SiteStore.SiteVisibility import org.wordpress.android.ui.sitecreation.FREE_DOMAIN +import org.wordpress.android.ui.sitecreation.PAID_DOMAIN +import org.wordpress.android.ui.sitecreation.SITE_REMOTE_ID import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceData import org.wordpress.android.ui.sitecreation.usecases.CreateSiteUseCase import org.wordpress.android.util.UrlUtilsWrapper @@ -26,15 +28,23 @@ import kotlin.test.assertEquals import kotlin.test.assertNotNull private const val SITE_TITLE = "site title" -private val DUMMY_SITE_DATA: SiteCreationServiceData = SiteCreationServiceData( +private val SITE_DATA_FREE = SiteCreationServiceData( 123, "slug", FREE_DOMAIN.domainName, SITE_TITLE, FREE_DOMAIN.isFree, ) +private val SITE_DATA_PAID = SiteCreationServiceData( + 123, + "slug", + PAID_DOMAIN.domainName, + SITE_TITLE, + PAID_DOMAIN.isFree, +) private const val LANGUAGE_ID = "lang_id" private const val TIMEZONE_ID = "timezone_id" +private val EVENT = OnNewSiteCreated(newSiteRemoteId = SITE_REMOTE_ID) @ExperimentalCoroutinesApi @RunWith(MockitoJUnitRunner::class) @@ -48,29 +58,27 @@ class CreateSiteUseCaseTest : BaseUnitTest() { @Mock private lateinit var urlUtilsWrapper: UrlUtilsWrapper private lateinit var useCase: CreateSiteUseCase - private lateinit var event: OnNewSiteCreated @Before fun setUp() { useCase = CreateSiteUseCase(dispatcher, store, urlUtilsWrapper) - event = OnNewSiteCreated(newSiteRemoteId = 123) - whenever(dispatcher.dispatch(any())).then { useCase.onNewSiteCreated(event) } + whenever(dispatcher.dispatch(any())).then { useCase.onNewSiteCreated(EVENT) } } @Test fun coroutineResumedWhenResultEventDispatched() = test { - val resultEvent = useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) - assertThat(resultEvent).isEqualTo(event) + val resultEvent = useCase.createSite(SITE_DATA_FREE, LANGUAGE_ID, TIMEZONE_ID) + assertThat(resultEvent).isEqualTo(EVENT) } @Test fun verifySiteDataPropagated() = test { - useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) + useCase.createSite(SITE_DATA_PAID, LANGUAGE_ID, TIMEZONE_ID) verify(dispatcher).dispatch(argPayload { - assertEquals(siteName, DUMMY_SITE_DATA.domain) - assertEquals(segmentId, DUMMY_SITE_DATA.segmentId) - assertEquals(siteTitle, SITE_TITLE) + assertEquals(SITE_DATA_PAID.domain, siteName) + assertEquals(SITE_DATA_PAID.segmentId, segmentId) + assertEquals(SITE_DATA_PAID.title, siteTitle) val findAvailableUrl = assertNotNull(findAvailableUrl) findAvailableUrl }) @@ -78,31 +86,35 @@ class CreateSiteUseCaseTest : BaseUnitTest() { @Test fun verifySiteDataWhenFreePropagatesNoFindAvailableUrl() = test { - useCase.createSite(DUMMY_SITE_DATA.copy(isFree = true), LANGUAGE_ID, TIMEZONE_ID) - verify(dispatcher).dispatch(argPayload { findAvailableUrl == null }) + whenever(urlUtilsWrapper.extractSubDomain(any())).thenReturn(SITE_DATA_FREE.domain) + useCase.createSite(SITE_DATA_FREE, LANGUAGE_ID, TIMEZONE_ID) + verify(dispatcher).dispatch(argPayload { + assertEquals(SITE_DATA_FREE.domain, siteName) + findAvailableUrl == null + }) } @Test fun verifyDryRunIsFalse() = test { - useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) + useCase.createSite(SITE_DATA_FREE, LANGUAGE_ID, TIMEZONE_ID) verify(dispatcher).dispatch(argPayload { !dryRun }) } @Test fun verifyCreatesPublicSite() = test { - useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) + useCase.createSite(SITE_DATA_FREE, LANGUAGE_ID, TIMEZONE_ID) verify(dispatcher).dispatch(argPayload { visibility == SiteVisibility.PUBLIC }) } @Test fun verifyPropagatesLanguageId() = test { - useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) + useCase.createSite(SITE_DATA_FREE, LANGUAGE_ID, TIMEZONE_ID) verify(dispatcher).dispatch(argPayload { language == LANGUAGE_ID }) } @Test fun verifyPropagatesTimeZoneId() = test { - useCase.createSite(DUMMY_SITE_DATA, LANGUAGE_ID, TIMEZONE_ID) + useCase.createSite(SITE_DATA_FREE, LANGUAGE_ID, TIMEZONE_ID) verify(dispatcher).dispatch(argPayload { timeZoneId == TIMEZONE_ID }) } } From 5308ba3359d1ad6ee3717949d65658833242890f Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Thu, 23 Mar 2023 18:18:58 +0100 Subject: [PATCH 104/169] Merge branch 'trunk' resolving conflicts manually --- .../android/ui/sitecreation/SiteCreationActivity.kt | 4 ++-- .../ui/sitecreation/domains/SiteCreationDomainsFragment.kt | 2 +- .../ui/sitecreation/previews/SiteCreationPreviewFragment.kt | 6 +++--- .../sitecreation/progress/SiteCreationProgressFragment.kt | 5 +++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 37fc9a2ab135..bb59a13242d3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -114,8 +114,8 @@ class SiteCreationActivity : LocaleAwareActivity(), private fun observeVMState() { mainViewModel.navigationTargetObservable .observe(this) { target -> target?.let { showStep(target) } } - mainViewModel.wizardFinishedObservable.observe(this) { createSiteState -> - createSiteState?.let { + mainViewModel.wizardFinishedObservable.observe(this) { result -> + result?.run { val intent = Intent() val (siteCreated, localSiteId, titleTaskComplete) = when (this@run) { // site creation flow was canceled diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt index e912a9e1ac43..847070e5399c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsFragment.kt @@ -49,7 +49,7 @@ class SiteCreationDomainsFragment : SiteCreationBaseFormFragment() { return R.layout.site_creation_domains_screen } - override val screenTitle get() = requireArguments()[EXTRA_SCREEN_TITLE] as String + override val screenTitle get() = requireArguments().getString(EXTRA_SCREEN_TITLE).orEmpty() override fun setBindingViewStubListener(parentBinding: SiteCreationFormScreenBinding) { parentBinding.siteCreationFormContentStub.setOnInflateListener { _, inflated -> diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt index 2ac621d763f9..3e895c8b23e3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SiteCreationPreviewFragment.kt @@ -30,8 +30,8 @@ import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SiteP import org.wordpress.android.ui.utils.UiHelpers import org.wordpress.android.util.ErrorManagedWebViewClient.ErrorManagedWebViewClientListener import org.wordpress.android.util.URLFilteredWebViewClient -import org.wordpress.android.widgets.NestedWebView import org.wordpress.android.util.extensions.getParcelableCompat +import org.wordpress.android.widgets.NestedWebView import javax.inject.Inject private const val SLIDE_IN_ANIMATION_DURATION = 450L @@ -61,12 +61,12 @@ class SiteCreationPreviewFragment : SiteCreationBaseFormFragment(), private fun init() { (requireActivity() as AppCompatActivity).supportActionBar?.hide() - viewModel.start(requireArguments().getParcelableCompat(ARG_DATA)) + viewModel.start(requireNotNull(requireArguments().getParcelableCompat(ARG_STATE))) } override fun getContentLayout() = R.layout.site_creation_preview_screen - override val screenTitle get() = requireArguments()[EXTRA_SCREEN_TITLE] as String + override val screenTitle get() = requireArguments().getString(EXTRA_SCREEN_TITLE).orEmpty() override fun setBindingViewStubListener(parentBinding: SiteCreationFormScreenBinding) { parentBinding.siteCreationFormContentStub.setOnInflateListener { _, inflated -> diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt index 1dbd3f9e6434..0037832a1209 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressFragment.kt @@ -26,6 +26,7 @@ import org.wordpress.android.ui.utils.UiHelpers import org.wordpress.android.util.AniUtils import org.wordpress.android.util.AppLog import org.wordpress.android.util.AutoForeground.ServiceEventConnection +import org.wordpress.android.util.extensions.getParcelableCompat import javax.inject.Inject @AndroidEntryPoint @@ -68,7 +69,7 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc (requireActivity() as AppCompatActivity).supportActionBar?.hide() - viewModel.start(requireArguments()[ARG_STATE] as SiteCreationState) + viewModel.start(requireNotNull(requireArguments().getParcelableCompat(ARG_STATE))) } private fun SiteCreationProgressScreenBinding.observeState() { @@ -148,7 +149,7 @@ class SiteCreationProgressFragment : Fragment(R.layout.site_creation_progress_sc progressText.text = newText } - override fun onAnimationEnd(animation: Animator?) { + override fun onAnimationEnd(animation: Animator) { super.onAnimationEnd(animation) animatorSet = null } From db3afcc977ef682c5d37b59cc8210493d51f44fd Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Fri, 24 Mar 2023 16:27:42 +0100 Subject: [PATCH 105/169] Update fluxC version to 2.19.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 68c5f2f46f0f..538a5a22f0f3 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ ext { automatticTracksVersion = '2.2.0' gutenbergMobileVersion = 'v1.92.0-alpha1' wordPressAztecVersion = 'v1.6.3' - wordPressFluxCVersion = 'trunk-aff6f17db9549bc47bc4e6372c8d8f32e62b65bb' + wordPressFluxCVersion = '2.19.0' wordPressLoginVersion = '1.0.0' wordPressPersistentEditTextVersion = '1.0.2' wordPressUtilsVersion = '3.3.0' From 679531829e6945eae78f42a7d5252420a146557d Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 13:36:40 +0200 Subject: [PATCH 106/169] Update: add supportsPrivacy to domain model --- .../android/ui/sitecreation/domains/DomainsScreenListener.kt | 1 + .../ui/sitecreation/domains/SiteCreationDomainsViewModel.kt | 1 + .../wordpress/android/ui/sitecreation/SiteCreationFixtures.kt | 4 ++-- .../sitecreation/domains/SiteCreationDomainsViewModelTest.kt | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt index be96ecd25dc3..96ea55347d88 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/DomainsScreenListener.kt @@ -13,4 +13,5 @@ data class DomainModel( val isFree: Boolean, val cost: String, val productId: Int, + val supportsPrivacy: Boolean, ) : Parcelable diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt index 233e0f50e228..ad42ba370e3f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModel.kt @@ -226,6 +226,7 @@ class SiteCreationDomainsViewModel @Inject constructor( isFree = is_free, cost = cost.orEmpty(), productId = product_id, + supportsPrivacy = supports_privacy, ) } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index d61bf9c41a2e..35f72a7e2dca 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -15,8 +15,8 @@ import org.wordpress.android.ui.sitecreation.theme.defaultTemplateSlug const val SUB_DOMAIN = "test" const val URL = "$SUB_DOMAIN.wordpress.com" const val URL_CUSTOM = "$SUB_DOMAIN.host.com" -val FREE_DOMAIN = DomainModel(URL, true, "", 1) -val PAID_DOMAIN = DomainModel(URL_CUSTOM, false, "$1", 2) +val FREE_DOMAIN = DomainModel(URL, true, "", 1, false) +val PAID_DOMAIN = DomainModel(URL_CUSTOM, false, "$1", 2, true) const val SITE_REMOTE_ID = 1L private const val SITE_LOCAL_ID = 1 diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt index c80e8c770e20..7eb471b44f30 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt @@ -346,6 +346,7 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { is_free = it % 2 == 0 cost = if (is_free) "Free" else "$$it.00" product_id = it + supports_privacy = !is_free } } @@ -576,6 +577,7 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { private fun mockDomain(name: String = "", free: Boolean = true) = mock { on { domainName } doReturn name on { isFree } doReturn free + on { supportsPrivacy } doReturn true } // endregion } From fcf47bce20fd9cf58be1b52481e821b5fcb0ae29 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 13:37:57 +0200 Subject: [PATCH 107/169] Refactor: remove unneeded suppress lint of ParcelCreator --- .../org/wordpress/android/ui/domains/DomainProductDetails.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainProductDetails.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainProductDetails.kt index 054ad9c81517..b6eaad296252 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainProductDetails.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainProductDetails.kt @@ -1,11 +1,9 @@ package org.wordpress.android.ui.domains -import android.annotation.SuppressLint import android.os.Parcelable import kotlinx.parcelize.Parcelize @Parcelize -@SuppressLint("ParcelCreator") data class DomainProductDetails( val productId: Int, val domainName: String From 790efde1a120bf61b2c356c212c7bcffcc7a3b6a Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 13:39:59 +0200 Subject: [PATCH 108/169] Refactor: remove unnecessary stubbing on supportsPrivacy --- .../ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt index 7eb471b44f30..e1289edd2304 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/domains/SiteCreationDomainsViewModelTest.kt @@ -577,7 +577,6 @@ class SiteCreationDomainsViewModelTest : BaseUnitTest() { private fun mockDomain(name: String = "", free: Boolean = true) = mock { on { domainName } doReturn name on { isFree } doReturn free - on { supportsPrivacy } doReturn true } // endregion } From a57a7e158f14a8c0f231db90d0926e86f4da6a87 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 14:37:18 +0200 Subject: [PATCH 109/169] Add: add paid domain product to shopping cart after creating the blog --- .../progress/SiteCreationProgressViewModel.kt | 64 +++++++++++++++---- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index 80fc919ec5f2..4a081a0fb125 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -9,8 +9,13 @@ import kotlinx.coroutines.delay import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import org.wordpress.android.R +import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.modules.UI_THREAD +import org.wordpress.android.ui.domains.DomainProductDetails +import org.wordpress.android.ui.domains.DomainsRegistrationTracker +import org.wordpress.android.ui.domains.usecases.CreateCartUseCase import org.wordpress.android.ui.sitecreation.SiteCreationState +import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.UNKNOWN import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker @@ -25,6 +30,7 @@ import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.S import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.SUCCESS import org.wordpress.android.ui.utils.UiString import org.wordpress.android.ui.utils.UiString.UiStringRes +import org.wordpress.android.util.AppLog import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.viewmodel.ScopedViewModel import org.wordpress.android.viewmodel.SingleLiveEvent @@ -34,6 +40,7 @@ import javax.inject.Named private const val CONNECTION_ERROR_DELAY_TO_SHOW_LOADING_STATE = 1000L const val LOADING_STATE_TEXT_ANIMATION_DELAY = 2000L private const val ERROR_CONTEXT = "site_preview" +private val LOG_TAG = AppLog.T.SITE_CREATION private val loadingTexts = listOf( UiStringRes(R.string.new_site_creation_creating_site_loading_1), @@ -46,15 +53,15 @@ private val loadingTexts = listOf( class SiteCreationProgressViewModel @Inject constructor( private val networkUtils: NetworkUtilsWrapper, private val tracker: SiteCreationTracker, + private val domainsRegistrationTracker: DomainsRegistrationTracker, + private val createCartUseCase: CreateCartUseCase, @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, ) : ScopedViewModel(mainDispatcher) { private var isStarted = false private var loadingAnimationJob: Job? = null private lateinit var siteCreationState: SiteCreationState - - private var urlWithoutScheme: String? = null - private var siteTitle: String? = null + private lateinit var domain: DomainModel private var lastReceivedServiceState: SiteCreationServiceState? = null private var serviceStateForRetry: SiteCreationServiceState? = null @@ -74,17 +81,20 @@ class SiteCreationProgressViewModel @Inject constructor( private val _onRemoteSiteCreated = SingleLiveEvent() val onRemoteSiteCreated: LiveData = _onRemoteSiteCreated + private val _onCartCreated = SingleLiveEvent() + // val onCartCreated: LiveData = _onCartCreated + override fun onCleared() { super.onCleared() loadingAnimationJob?.cancel() + createCartUseCase.clear() } fun start(siteCreationState: SiteCreationState) { if (isStarted) return isStarted = true this.siteCreationState = siteCreationState - urlWithoutScheme = siteCreationState.domain?.domainName - siteTitle = siteCreationState.siteName + domain = requireNotNull(siteCreationState.domain) { "domain required to create a site" } runLoadingAnimationUi() startCreateSiteService() @@ -92,16 +102,16 @@ class SiteCreationProgressViewModel @Inject constructor( private fun startCreateSiteService(previousState: SiteCreationServiceState? = null) { if (networkUtils.isNetworkAvailable()) { - siteCreationState.apply { + siteCreationState.let { state -> // A non-null [segmentId] may invalidate the [siteDesign] selection // https://github.com/wordpress-mobile/WordPress-Android/issues/13749 - val segmentIdentifier = segmentId.takeIf { siteDesign != null } + val segmentIdentifier = state.segmentId.takeIf { state.siteDesign != null } val serviceData = SiteCreationServiceData( segmentIdentifier, - siteDesign, - urlWithoutScheme, - siteTitle, - requireNotNull(siteCreationState.domain?.isFree) { "domain required to create a site" }, + state.siteDesign, + domain.domainName, + state.siteName, + domain.isFree, ) _startCreateSiteService.value = StartServiceData(serviceData, previousState) } @@ -144,8 +154,14 @@ class SiteCreationProgressViewModel @Inject constructor( when (event.step) { IDLE, CREATE_SITE -> Unit SUCCESS -> { - val remoteSiteId = (event.payload as Pair<*, *>).first as Long - _onRemoteSiteCreated.postValue(remoteSiteId) + require(event.payload is Pair<*, *>) { "Expected Pair in Payload but got: ${event.payload}" } + val blogId = event.payload.first as Long + if (domain.isFree) { + _onRemoteSiteCreated.postValue(blogId) + } else { + val siteSlug = event.payload.second as String + createCart(blogId, siteSlug) + } } FAILURE -> { serviceStateForRetry = event.payload as SiteCreationServiceState @@ -159,6 +175,28 @@ class SiteCreationProgressViewModel @Inject constructor( } } + private fun createCart(blogId: Long, siteSlug: String) = launch { + AppLog.d(LOG_TAG, "Creating cart: $domain") + + val site = SiteModel().apply { siteId = blogId; url = siteSlug } + val event = createCartUseCase.execute( + site, + domain.productId, + domain.domainName, + domain.supportsPrivacy, + false, + ) + + if (event.isError) { + AppLog.e(LOG_TAG, "Failed cart creation: ${event.error.message}") + updateUiStateAsync(GenericError) + } else { + AppLog.d(LOG_TAG, "Successful cart creation: ${event.cartDetails}") + _onCartCreated.postValue(DomainProductDetails(domain.productId, domain.domainName)) + domainsRegistrationTracker.trackDomainsPurchaseWebviewViewed(site, isSiteCreation = true) + } + } + private fun runLoadingAnimationUi() { loadingAnimationJob?.cancel() loadingAnimationJob = launch { From 741b41ddfbb970b93b5369db9a62017f9f9a61df Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 19:47:45 +0200 Subject: [PATCH 110/169] Test: shopping cart logic --- .../ui/sitecreation/SiteCreationFixtures.kt | 7 ++++ .../SiteCreationProgressViewModelTest.kt | 42 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index 35f72a7e2dca..6cf290923173 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -1,8 +1,12 @@ package org.wordpress.android.ui.sitecreation +import org.mockito.kotlin.mock +import org.wordpress.android.fluxc.network.rest.wpcom.transactions.TransactionsRestClient.CreateShoppingCartResponse import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged import org.wordpress.android.fluxc.store.SiteStore.SiteError import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType.GENERIC_ERROR +import org.wordpress.android.fluxc.store.TransactionsStore.CreateShoppingCartError +import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartCreated import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.domains.DomainModel @@ -31,6 +35,9 @@ val SITE_CREATION_STATE = SiteCreationState( val FETCH_SUCCESS = OnSiteChanged(1) val FETCH_ERROR = OnSiteChanged(0).apply { error = SiteError(GENERIC_ERROR) } +val CART_SUCCESS = OnShoppingCartCreated(mock()) +val CART_ERROR = OnShoppingCartCreated(mock()) + val RESULT_CREATED = NotInLocalDb(SITE_REMOTE_ID, false) val RESULT_COMPLETED = Completed(SITE_LOCAL_ID, false, URL) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt index 241db62af1d6..caf4eaf1b8f3 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt @@ -1,6 +1,7 @@ package org.wordpress.android.ui.sitecreation.progress import androidx.lifecycle.Observer +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceTimeBy import org.assertj.core.api.Assertions.assertThat @@ -8,6 +9,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.atMost import org.mockito.kotlin.check @@ -17,6 +19,11 @@ import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest +import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartCreated +import org.wordpress.android.ui.domains.DomainsRegistrationTracker +import org.wordpress.android.ui.domains.usecases.CreateCartUseCase +import org.wordpress.android.ui.sitecreation.CART_ERROR +import org.wordpress.android.ui.sitecreation.CART_SUCCESS import org.wordpress.android.ui.sitecreation.PAID_DOMAIN import org.wordpress.android.ui.sitecreation.SERVICE_ERROR import org.wordpress.android.ui.sitecreation.SERVICE_SUCCESS @@ -41,6 +48,8 @@ import kotlin.test.assertTrue class SiteCreationProgressViewModelTest : BaseUnitTest() { private var networkUtils = mock() private var tracker = mock() + private val domainsRegistrationTracker = mock() + private val createCartUseCase = mock() private val uiStateObserver = mock>() private val startServiceObserver = mock>() @@ -55,6 +64,8 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { viewModel = SiteCreationProgressViewModel( networkUtils, tracker, + domainsRegistrationTracker, + createCartUseCase, testDispatcher(), ) viewModel.uiState.observeForever(uiStateObserver) @@ -153,6 +164,33 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { verify(onRemoteSiteCreatedObserver).onChanged(SITE_REMOTE_ID) } + @Test + fun `on service success for paid domain creates cart`() = test { + startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN)) + viewModel.onSiteCreationServiceStateUpdated(SERVICE_SUCCESS) + verify(createCartUseCase).execute( + any(), + eq(PAID_DOMAIN.productId), + eq(PAID_DOMAIN.domainName), + eq(PAID_DOMAIN.supportsPrivacy), + any(), + ) + } + + @Test + fun `on cart success tracks domain purchase webview viewed`() = testWith(CART_SUCCESS) { + startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN)) + viewModel.onSiteCreationServiceStateUpdated(SERVICE_SUCCESS) + verify(domainsRegistrationTracker).trackDomainsPurchaseWebviewViewed(any(), eq(true)) + } + + @Test + fun `on cart failure shows generic error`() = testWith(CART_ERROR) { + startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN)) + viewModel.onSiteCreationServiceStateUpdated(SERVICE_SUCCESS) + verify(uiStateObserver).onChanged(eq(GenericError)) + } + @Test fun `on service failure shows generic error`() { startViewModel() @@ -168,6 +206,10 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { } // region Helpers + private fun testWith(response: OnShoppingCartCreated, block: suspend CoroutineScope.() -> Unit) = test { + whenever(createCartUseCase.execute(any(), any(), any(), any(), any())).thenReturn(response) + block() + } private fun startViewModel(state: SiteCreationState = SITE_CREATION_STATE) { viewModel.start(state) From 1215dff8b57df89e75f80f5d2ba5cddec80d8bb8 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 22:02:36 +0200 Subject: [PATCH 111/169] Refactor: remove unused remote site id from state --- .../wordpress/android/ui/sitecreation/SiteCreationMainVM.kt | 2 -- .../wordpress/android/ui/sitecreation/SiteCreationFixtures.kt | 1 - .../android/ui/sitecreation/SiteCreationMainVMTest.kt | 4 ++-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index f4c93f1fd9e6..e760c140d788 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -56,7 +56,6 @@ data class SiteCreationState( val segmentId: Long? = null, val siteDesign: String? = null, val domain: DomainModel? = null, - val remoteSiteId: Long? = null, val result: SiteCreationResult = NotCreated, ) : WizardState, Parcelable { fun isSiteTitleStepCompleted() = !siteName.isNullOrBlank() @@ -265,7 +264,6 @@ class SiteCreationMainVM @Inject constructor( fun onProgressScreenFinished(remoteSiteId: Long) { siteCreationState = siteCreationState.copy( - remoteSiteId = remoteSiteId, result = NotInLocalDb(remoteSiteId, siteCreationState.isSiteTitleStepCompleted()) ) wizardManager.showNextStep() diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index 6cf290923173..b87475952862 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -29,7 +29,6 @@ val SITE_CREATION_STATE = SiteCreationState( segmentId = 1, siteDesign = defaultTemplateSlug, domain = FREE_DOMAIN, - remoteSiteId = SITE_REMOTE_ID, ) val FETCH_SUCCESS = OnSiteChanged(1) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 51e3a7aec68d..0052a67aa302 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -141,9 +141,9 @@ class SiteCreationMainVMTest : BaseUnitTest() { } @Test - fun `on progress screen finished updates state with remote id`() { + fun `on progress screen finished updates state with result`() { viewModel.onProgressScreenFinished(SITE_REMOTE_ID) - assertThat(currentWizardState(viewModel).remoteSiteId).isEqualTo(SITE_REMOTE_ID) + assertThat(currentWizardState(viewModel).result).isEqualTo(RESULT_CREATED) } @Test From d0052d40fcc2ebad362642c9e71336d23b8a61d5 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 22:08:37 +0200 Subject: [PATCH 112/169] Refactor: cleanup logic to pre-complete site title task for quickstart --- .../android/ui/sitecreation/SiteCreationMainVM.kt | 8 ++++---- .../ui/sitecreation/previews/SitePreviewViewModel.kt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index e760c140d788..fe315872dd6d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -57,9 +57,7 @@ data class SiteCreationState( val siteDesign: String? = null, val domain: DomainModel? = null, val result: SiteCreationResult = NotCreated, -) : WizardState, Parcelable { - fun isSiteTitleStepCompleted() = !siteName.isNullOrBlank() -} +) : WizardState, Parcelable typealias NavigationTarget = WizardNavigationTarget @@ -264,11 +262,13 @@ class SiteCreationMainVM @Inject constructor( fun onProgressScreenFinished(remoteSiteId: Long) { siteCreationState = siteCreationState.copy( - result = NotInLocalDb(remoteSiteId, siteCreationState.isSiteTitleStepCompleted()) + result = NotInLocalDb(remoteSiteId, isSiteTitleTaskCompleted()) ) wizardManager.showNextStep() } + private fun isSiteTitleTaskCompleted() = !siteCreationState.siteName.isNullOrBlank() + fun onWizardCancelled() { _wizardFinishedObservable.value = NotCreated } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 4272463dfdb5..d5203f369f54 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -83,7 +83,7 @@ class SitePreviewViewModel @Inject constructor( if (it is NotInLocalDb) { launch { fetchNewlyCreatedSiteModel(it.remoteId)?.run { - result = Completed(id, siteCreationState.isSiteTitleStepCompleted(), url) + result = Completed(id, it.isSiteTitleTaskComplete, url) } } } From 331497a49992b56c29f0e6975a6db47d6c062831 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 22:09:38 +0200 Subject: [PATCH 113/169] Refactor: add empty lines between injected props --- .../wordpress/android/ui/sitecreation/SiteCreationActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index bb59a13242d3..2d755148aad4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -82,8 +82,10 @@ class SiteCreationActivity : LocaleAwareActivity(), private val jetpackFullScreenViewModel: JetpackFeatureFullScreenOverlayViewModel by viewModels() private val progressViewModel: SiteCreationProgressViewModel by viewModels() private val previewViewModel: SitePreviewViewModel by viewModels() + @Inject internal lateinit var jetpackFeatureRemovalOverlayUtil: JetpackFeatureRemovalOverlayUtil + @Inject internal lateinit var activityLauncherWrapper: ActivityLauncherWrapper From fb5c07a057e2b1ee888ae476da56f81f8376c5cf Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 22:12:16 +0200 Subject: [PATCH 114/169] Refactor: remove duplicate test --- .../progress/SiteCreationProgressViewModelTest.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt index caf4eaf1b8f3..6a45ca5c5f70 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt @@ -193,13 +193,6 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { @Test fun `on service failure shows generic error`() { - startViewModel() - viewModel.onSiteCreationServiceStateUpdated(SERVICE_ERROR) - verify(uiStateObserver).onChanged(eq(GenericError)) - } - - @Test - fun `on service failure shows error`() { startViewModel() viewModel.onSiteCreationServiceStateUpdated(SERVICE_ERROR) assertIs(viewModel.uiState.value) From dbfa330d11b6b7923df182eeed1660727b3f1f2d Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 22:13:53 +0200 Subject: [PATCH 115/169] Refactor: assert generic error uniformly --- .../sitecreation/progress/SiteCreationProgressViewModelTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt index 6a45ca5c5f70..11c247e3e073 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt @@ -188,7 +188,7 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { fun `on cart failure shows generic error`() = testWith(CART_ERROR) { startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN)) viewModel.onSiteCreationServiceStateUpdated(SERVICE_SUCCESS) - verify(uiStateObserver).onChanged(eq(GenericError)) + assertIs(viewModel.uiState.value) } @Test From 1830d615f05b3ac583921b14770fe1c1683f86dc Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 22:28:03 +0200 Subject: [PATCH 116/169] Add: emit checkout details on cart created successfully --- .../ui/sitecreation/SiteCreationActivity.kt | 1 + .../progress/SiteCreationProgressViewModel.kt | 8 ++++---- .../SiteCreationProgressViewModelTest.kt | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 2d755148aad4..4472e9519ba5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -177,6 +177,7 @@ class SiteCreationActivity : LocaleAwareActivity(), progressViewModel.onRemoteSiteCreated.observe(this) { remoteSiteId -> mainViewModel.onProgressScreenFinished(remoteSiteId) } + progressViewModel.onCartCreated.observe(this) { mainViewModel.onCartCreated(it) } previewViewModel.onOkButtonClicked.observe(this) { result -> mainViewModel.onWizardFinished(result) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index 4a081a0fb125..e6ff803c75b4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -11,7 +11,7 @@ import org.greenrobot.eventbus.ThreadMode import org.wordpress.android.R import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.modules.UI_THREAD -import org.wordpress.android.ui.domains.DomainProductDetails +import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity.OpenCheckout.CheckoutDetails import org.wordpress.android.ui.domains.DomainsRegistrationTracker import org.wordpress.android.ui.domains.usecases.CreateCartUseCase import org.wordpress.android.ui.sitecreation.SiteCreationState @@ -81,8 +81,8 @@ class SiteCreationProgressViewModel @Inject constructor( private val _onRemoteSiteCreated = SingleLiveEvent() val onRemoteSiteCreated: LiveData = _onRemoteSiteCreated - private val _onCartCreated = SingleLiveEvent() - // val onCartCreated: LiveData = _onCartCreated + private val _onCartCreated = SingleLiveEvent() + val onCartCreated: LiveData = _onCartCreated override fun onCleared() { super.onCleared() @@ -192,7 +192,7 @@ class SiteCreationProgressViewModel @Inject constructor( updateUiStateAsync(GenericError) } else { AppLog.d(LOG_TAG, "Successful cart creation: ${event.cartDetails}") - _onCartCreated.postValue(DomainProductDetails(domain.productId, domain.domainName)) + _onCartCreated.postValue(CheckoutDetails(site, domain.domainName)) domainsRegistrationTracker.trackDomainsPurchaseWebviewViewed(site, isSiteCreation = true) } } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt index 11c247e3e073..935ed3f6364f 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt @@ -10,6 +10,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any +import org.mockito.kotlin.argThat import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.atMost import org.mockito.kotlin.check @@ -20,6 +21,7 @@ import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartCreated +import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity.OpenCheckout.CheckoutDetails import org.wordpress.android.ui.domains.DomainsRegistrationTracker import org.wordpress.android.ui.domains.usecases.CreateCartUseCase import org.wordpress.android.ui.sitecreation.CART_ERROR @@ -30,6 +32,7 @@ import org.wordpress.android.ui.sitecreation.SERVICE_SUCCESS import org.wordpress.android.ui.sitecreation.SITE_CREATION_STATE import org.wordpress.android.ui.sitecreation.SITE_REMOTE_ID import org.wordpress.android.ui.sitecreation.SiteCreationState +import org.wordpress.android.ui.sitecreation.URL import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState import org.wordpress.android.ui.sitecreation.progress.SiteCreationProgressViewModel.SiteProgressUiState.Error.ConnectionError @@ -56,6 +59,7 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { private val onHelpClickedObserver = mock>() private val onCancelWizardClickedObserver = mock>() private val onRemoteSiteCreatedObserver = mock>() + private val onCartCreatedObserver = mock>() private lateinit var viewModel: SiteCreationProgressViewModel @@ -73,6 +77,7 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { viewModel.onHelpClicked.observeForever(onHelpClickedObserver) viewModel.onCancelWizardClicked.observeForever(onCancelWizardClickedObserver) viewModel.onRemoteSiteCreated.observeForever(onRemoteSiteCreatedObserver) + viewModel.onCartCreated.observeForever(onCartCreatedObserver) whenever(networkUtils.isNetworkAvailable()).thenReturn(true) } @@ -184,6 +189,17 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { verify(domainsRegistrationTracker).trackDomainsPurchaseWebviewViewed(any(), eq(true)) } + @Test + fun `on cart success propagates checkout details`() = testWith(CART_SUCCESS) { + startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN)) + viewModel.onSiteCreationServiceStateUpdated(SERVICE_SUCCESS) + verify(onCartCreatedObserver).onChanged(argThat { + assertEquals(SITE_REMOTE_ID, site.siteId) + assertEquals(URL, site.url) + domainName == PAID_DOMAIN.domainName + }) + } + @Test fun `on cart failure shows generic error`() = testWith(CART_ERROR) { startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN)) From 6e0f75b01ecfa7502a67d6b4935bcd001bd0216d Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Sun, 26 Mar 2023 22:37:41 +0200 Subject: [PATCH 117/169] Add: open checkout on cart created successfully --- .../ui/sitecreation/SiteCreationActivity.kt | 11 ++++++ .../ui/sitecreation/SiteCreationMainVM.kt | 34 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 4472e9519ba5..c3dde1788d19 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -16,6 +16,7 @@ import org.wordpress.android.ui.ActivityLauncherWrapper import org.wordpress.android.ui.ActivityLauncherWrapper.Companion.JETPACK_PACKAGE_NAME import org.wordpress.android.ui.LocaleAwareActivity import org.wordpress.android.ui.accounts.HelpActivity.Origin +import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity.OpenCheckout import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureFullScreenOverlayFragment import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureFullScreenOverlayViewModel import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureOverlayActions.DismissDialog @@ -28,6 +29,7 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed +import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistered import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.SiteCreationStep.DOMAINS @@ -95,6 +97,10 @@ class SiteCreationActivity : LocaleAwareActivity(), } } + private val domainCheckoutActivityLauncher = registerForActivityResult(OpenCheckout()) { + it?.let(mainViewModel::onCheckoutSuccess) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.site_creation_activity) @@ -130,6 +136,10 @@ class SiteCreationActivity : LocaleAwareActivity(), intent.putExtra(SitePickerActivity.KEY_SITE_CREATED_BUT_NOT_FETCHED, true) Triple(true, null, isSiteTitleTaskComplete) } + is DomainRegistered -> { + intent.putExtra(SitePickerActivity.KEY_SITE_CREATED_BUT_NOT_FETCHED, true) + Triple(true, null, isSiteTitleTaskComplete) + } is Completed -> { Triple(true, localId, isSiteTitleTaskComplete) } @@ -151,6 +161,7 @@ class SiteCreationActivity : LocaleAwareActivity(), ActivityUtils.hideKeyboard(this) onBackPressedDispatcher.onBackPressedCompat(backPressedCallback) } + mainViewModel.launchDomainCheckout.observe(this, domainCheckoutActivityLauncher::launch) siteCreationIntentsViewModel.onBackButtonPressed.observe(this) { mainViewModel.onBackPressed() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index fe315872dd6d..cdef77942a9d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -17,11 +17,14 @@ import kotlinx.parcelize.Parcelize import org.wordpress.android.R import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.networking.MShot +import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity.OpenCheckout.CheckoutDetails +import org.wordpress.android.ui.domains.DomainRegistrationCompletedEvent import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleEmpty import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed +import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistered import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.domains.DomainModel @@ -68,6 +71,14 @@ sealed interface SiteCreationResult : Parcelable { @Parcelize data class NotInLocalDb(val remoteId: Long, val isSiteTitleTaskComplete: Boolean) : SiteCreationResult + @Parcelize + data class DomainRegistered( + val domainName: String, + val email: String, + val remoteId: Long, + val isSiteTitleTaskComplete: Boolean, + ) : SiteCreationResult + @Parcelize data class Completed(val localId: Int, val isSiteTitleTaskComplete: Boolean, val url: String) : SiteCreationResult } @@ -124,6 +135,9 @@ class SiteCreationMainVM @Inject constructor( private val _showJetpackOverlay = MutableLiveData>() val showJetpackOverlay: LiveData> = _showJetpackOverlay + private val _showDomainCheckout = SingleLiveEvent() + val launchDomainCheckout: LiveData = _showDomainCheckout + fun start(savedInstanceState: Bundle?, siteCreationSource: SiteCreationSource) { if (isStarted) return if (savedInstanceState == null) { @@ -260,6 +274,26 @@ class SiteCreationMainVM @Inject constructor( } } + fun onCartCreated(checkoutDetails: CheckoutDetails) { + siteCreationState = siteCreationState.copy( + result = NotInLocalDb(checkoutDetails.site.siteId, isSiteTitleTaskCompleted()) + ) + _showDomainCheckout.value = checkoutDetails + } + + fun onCheckoutSuccess(event: DomainRegistrationCompletedEvent) { + val (remoteId, isSiteTitleTaskComplete) = siteCreationState.result as NotInLocalDb + siteCreationState = siteCreationState.copy( + result = DomainRegistered( + event.domainName, + event.email, + remoteId, + isSiteTitleTaskComplete + ) + ) + wizardManager.showNextStep() + } + fun onProgressScreenFinished(remoteSiteId: Long) { siteCreationState = siteCreationState.copy( result = NotInLocalDb(remoteSiteId, isSiteTitleTaskCompleted()) From 2bb1e8282dfefe3e134e6a244284970239e7cc8f Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 27 Mar 2023 18:47:23 +0200 Subject: [PATCH 118/169] Refactor: rename DomainRegistered to DomainRegistrationPurchased --- .../wordpress/android/ui/sitecreation/SiteCreationActivity.kt | 2 +- .../wordpress/android/ui/sitecreation/SiteCreationMainVM.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index c3dde1788d19..eef3341fffec 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -136,7 +136,7 @@ class SiteCreationActivity : LocaleAwareActivity(), intent.putExtra(SitePickerActivity.KEY_SITE_CREATED_BUT_NOT_FETCHED, true) Triple(true, null, isSiteTitleTaskComplete) } - is DomainRegistered -> { + is DomainRegistrationPurchased -> { intent.putExtra(SitePickerActivity.KEY_SITE_CREATED_BUT_NOT_FETCHED, true) Triple(true, null, isSiteTitleTaskComplete) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index cdef77942a9d..27bea32c147d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -72,7 +72,7 @@ sealed interface SiteCreationResult : Parcelable { data class NotInLocalDb(val remoteId: Long, val isSiteTitleTaskComplete: Boolean) : SiteCreationResult @Parcelize - data class DomainRegistered( + data class DomainRegistrationPurchased( val domainName: String, val email: String, val remoteId: Long, @@ -284,7 +284,7 @@ class SiteCreationMainVM @Inject constructor( fun onCheckoutSuccess(event: DomainRegistrationCompletedEvent) { val (remoteId, isSiteTitleTaskComplete) = siteCreationState.result as NotInLocalDb siteCreationState = siteCreationState.copy( - result = DomainRegistered( + result = DomainRegistrationPurchased( event.domainName, event.email, remoteId, From 800c613fe5bcee7a3cb4b8e491c95d94dd740f91 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 09:02:15 +0200 Subject: [PATCH 119/169] Add: support back navigation from checkout web-view --- .../ui/sitecreation/SiteCreationActivity.kt | 8 ++-- .../ui/sitecreation/SiteCreationMainVM.kt | 48 +++++++++++++------ .../previews/SitePreviewViewModel.kt | 4 +- .../progress/SiteCreationProgressViewModel.kt | 11 +++-- 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index eef3341fffec..9914e5fd89b7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -29,9 +29,9 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed -import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistered +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Created +import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistrationPurchased import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated -import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.SiteCreationStep.DOMAINS import org.wordpress.android.ui.sitecreation.SiteCreationStep.INTENTS import org.wordpress.android.ui.sitecreation.SiteCreationStep.PROGRESS @@ -98,7 +98,7 @@ class SiteCreationActivity : LocaleAwareActivity(), } private val domainCheckoutActivityLauncher = registerForActivityResult(OpenCheckout()) { - it?.let(mainViewModel::onCheckoutSuccess) + mainViewModel.onCheckoutResult(it) } override fun onCreate(savedInstanceState: Bundle?) { @@ -130,7 +130,7 @@ class SiteCreationActivity : LocaleAwareActivity(), is NotCreated -> { Triple(false, null, false) } - is NotInLocalDb -> { + is Created -> { // Site was created, but we haven't been able to fetch it, let `SitePickerActivity` handle // this with a Snackbar message. intent.putExtra(SitePickerActivity.KEY_SITE_CREATED_BUT_NOT_FETCHED, true) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 27bea32c147d..e7d70a250691 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -24,9 +24,9 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed -import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistered +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Created +import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistrationPurchased import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated -import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker @@ -68,8 +68,23 @@ sealed interface SiteCreationResult : Parcelable { @Parcelize object NotCreated : SiteCreationResult - @Parcelize - data class NotInLocalDb(val remoteId: Long, val isSiteTitleTaskComplete: Boolean) : SiteCreationResult + sealed interface Created : SiteCreationResult { + val remoteId: Long + val isSiteTitleTaskComplete: Boolean + + @Parcelize + data class NotInLocalDb( + override val remoteId: Long, + override val isSiteTitleTaskComplete: Boolean, + ) : Created + + @Parcelize + data class InCart( + val siteSlug: String, + override val remoteId: Long, + override val isSiteTitleTaskComplete: Boolean, + ) : Created + } @Parcelize data class DomainRegistrationPurchased( @@ -276,27 +291,30 @@ class SiteCreationMainVM @Inject constructor( fun onCartCreated(checkoutDetails: CheckoutDetails) { siteCreationState = siteCreationState.copy( - result = NotInLocalDb(checkoutDetails.site.siteId, isSiteTitleTaskCompleted()) + result = Created.InCart(checkoutDetails.site.url, checkoutDetails.site.siteId, isSiteTitleTaskCompleted()) ) _showDomainCheckout.value = checkoutDetails } - fun onCheckoutSuccess(event: DomainRegistrationCompletedEvent) { - val (remoteId, isSiteTitleTaskComplete) = siteCreationState.result as NotInLocalDb - siteCreationState = siteCreationState.copy( - result = DomainRegistrationPurchased( - event.domainName, - event.email, - remoteId, - isSiteTitleTaskComplete + fun onCheckoutResult(event: DomainRegistrationCompletedEvent?) { + if (event == null) return onBackPressed() + siteCreationState = siteCreationState.run { + check(result is Created) + copy( + result = DomainRegistrationPurchased( + event.domainName, + event.email, + result.remoteId, + isSiteTitleTaskCompleted() + ) ) - ) + } wizardManager.showNextStep() } fun onProgressScreenFinished(remoteSiteId: Long) { siteCreationState = siteCreationState.copy( - result = NotInLocalDb(remoteSiteId, isSiteTitleTaskCompleted()) + result = Created.NotInLocalDb(remoteSiteId, isSiteTitleTaskCompleted()) ) wizardManager.showNextStep() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index d5203f369f54..8ca1eb63d711 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -16,7 +16,7 @@ import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed -import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Created import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState @@ -80,7 +80,7 @@ class SitePreviewViewModel @Inject constructor( urlWithoutScheme = requireNotNull(siteCreationState.domain) { "url required for preview" }.domainName startPreLoadingWebView() result = siteCreationState.result.also { - if (it is NotInLocalDb) { + if (it is Created) { launch { fetchNewlyCreatedSiteModel(it.remoteId)?.run { result = Completed(id, it.isSiteTitleTaskComplete, url) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index e6ff803c75b4..2a5aee9f7ffc 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -14,6 +14,7 @@ import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity.OpenCheckout.CheckoutDetails import org.wordpress.android.ui.domains.DomainsRegistrationTracker import org.wordpress.android.ui.domains.usecases.CreateCartUseCase +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Created import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR @@ -57,7 +58,6 @@ class SiteCreationProgressViewModel @Inject constructor( private val createCartUseCase: CreateCartUseCase, @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, ) : ScopedViewModel(mainDispatcher) { - private var isStarted = false private var loadingAnimationJob: Job? = null private lateinit var siteCreationState: SiteCreationState @@ -91,8 +91,13 @@ class SiteCreationProgressViewModel @Inject constructor( } fun start(siteCreationState: SiteCreationState) { - if (isStarted) return - isStarted = true + if (siteCreationState.result is Created.InCart) { + // reuse the previously blog when returning with the same domain + if (siteCreationState.domain == this.siteCreationState.domain) { + createCart(siteCreationState.result.remoteId, siteCreationState.result.siteSlug) + return + } + } this.siteCreationState = siteCreationState domain = requireNotNull(siteCreationState.domain) { "domain required to create a site" } From 370b7453fa803fbb958238f8de7f3b64bc8e1575 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 10:52:36 +0200 Subject: [PATCH 120/169] Refactor: fix non-uniform naming for checkout event(s) --- .../wordpress/android/ui/sitecreation/SiteCreationActivity.kt | 2 +- .../org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index 9914e5fd89b7..dac9e59b49d6 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -161,7 +161,7 @@ class SiteCreationActivity : LocaleAwareActivity(), ActivityUtils.hideKeyboard(this) onBackPressedDispatcher.onBackPressedCompat(backPressedCallback) } - mainViewModel.launchDomainCheckout.observe(this, domainCheckoutActivityLauncher::launch) + mainViewModel.showDomainCheckout.observe(this, domainCheckoutActivityLauncher::launch) siteCreationIntentsViewModel.onBackButtonPressed.observe(this) { mainViewModel.onBackPressed() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index e7d70a250691..6f73a9f36e09 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -151,7 +151,7 @@ class SiteCreationMainVM @Inject constructor( val showJetpackOverlay: LiveData> = _showJetpackOverlay private val _showDomainCheckout = SingleLiveEvent() - val launchDomainCheckout: LiveData = _showDomainCheckout + val showDomainCheckout: LiveData = _showDomainCheckout fun start(savedInstanceState: Bundle?, siteCreationSource: SiteCreationSource) { if (isStarted) return From 63a480985a01cd208a29ecf41a17d338b14efaf3 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 11:04:43 +0200 Subject: [PATCH 121/169] Test: onCartCreated --- .../ui/sitecreation/SiteCreationFixtures.kt | 15 +++++++++++-- .../ui/sitecreation/SiteCreationMainVMTest.kt | 21 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index b87475952862..469c720e98cc 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -1,14 +1,16 @@ package org.wordpress.android.ui.sitecreation import org.mockito.kotlin.mock +import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.network.rest.wpcom.transactions.TransactionsRestClient.CreateShoppingCartResponse import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged import org.wordpress.android.fluxc.store.SiteStore.SiteError import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType.GENERIC_ERROR import org.wordpress.android.fluxc.store.TransactionsStore.CreateShoppingCartError import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartCreated +import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed -import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotInLocalDb +import org.wordpress.android.ui.sitecreation.SiteCreationResult.Created import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE @@ -19,6 +21,7 @@ import org.wordpress.android.ui.sitecreation.theme.defaultTemplateSlug const val SUB_DOMAIN = "test" const val URL = "$SUB_DOMAIN.wordpress.com" const val URL_CUSTOM = "$SUB_DOMAIN.host.com" +const val SITE_SLUG = "${SUB_DOMAIN}host0.wordpress.com" val FREE_DOMAIN = DomainModel(URL, true, "", 1, false) val PAID_DOMAIN = DomainModel(URL_CUSTOM, false, "$1", 2, true) @@ -31,13 +34,21 @@ val SITE_CREATION_STATE = SiteCreationState( domain = FREE_DOMAIN, ) +val SITE_MODEL = SiteModel().apply { + siteId = SITE_REMOTE_ID + url = SITE_SLUG +} + +val CHECKOUT_DETAILS = DomainRegistrationCheckoutWebViewActivity.OpenCheckout.CheckoutDetails(SITE_MODEL, SITE_SLUG) + val FETCH_SUCCESS = OnSiteChanged(1) val FETCH_ERROR = OnSiteChanged(0).apply { error = SiteError(GENERIC_ERROR) } val CART_SUCCESS = OnShoppingCartCreated(mock()) val CART_ERROR = OnShoppingCartCreated(mock()) -val RESULT_CREATED = NotInLocalDb(SITE_REMOTE_ID, false) +val RESULT_CREATED = Created.NotInLocalDb(SITE_REMOTE_ID, false) +val RESULT_IN_CART = Created.InCart(SITE_SLUG, SITE_REMOTE_ID, false) val RESULT_COMPLETED = Completed(SITE_LOCAL_ID, false, URL) val SERVICE_SUCCESS = SiteCreationServiceState(SUCCESS, Pair(SITE_REMOTE_ID, URL)) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 0052a67aa302..cbfe6c266ba8 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -1,3 +1,4 @@ + package org.wordpress.android.ui.sitecreation import android.os.Bundle @@ -12,6 +13,7 @@ import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argThat +import org.mockito.kotlin.argWhere import org.mockito.kotlin.atLeastOnce import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.eq @@ -42,6 +44,7 @@ import org.wordpress.android.util.image.ImageManager import org.wordpress.android.util.wizard.WizardManager import org.wordpress.android.viewmodel.SingleLiveEvent import org.wordpress.android.viewmodel.helpers.DialogHolder +import kotlin.test.assertEquals private const val SEGMENT_ID = 1L private const val VERTICAL = "Test Vertical" @@ -140,6 +143,24 @@ class SiteCreationMainVMTest : BaseUnitTest() { verify(wizardFinishedObserver).onChanged(eq(RESULT_COMPLETED)) } + @Test + fun `on cart created is propagated`() { + viewModel.onCartCreated(CHECKOUT_DETAILS) + assertEquals(CHECKOUT_DETAILS, viewModel.showDomainCheckout.value) + } + + @Test + fun `on cart created updates state with result`() { + viewModel.onCartCreated(CHECKOUT_DETAILS) + + // Assert on the private state via bundle + viewModel.writeToBundle(savedInstanceState) + verify(savedInstanceState).putParcelable( + eq(KEY_SITE_CREATION_STATE), + argWhere { it.result == RESULT_IN_CART } + ) + } + @Test fun `on progress screen finished updates state with result`() { viewModel.onProgressScreenFinished(SITE_REMOTE_ID) From 8b55af557a48adb02cc3ef0aff276f379ec7e50c Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 11:05:32 +0200 Subject: [PATCH 122/169] Refactor: force Created.InCart contract on checkout result --- .../org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 6f73a9f36e09..33369dcfbecd 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -299,7 +299,7 @@ class SiteCreationMainVM @Inject constructor( fun onCheckoutResult(event: DomainRegistrationCompletedEvent?) { if (event == null) return onBackPressed() siteCreationState = siteCreationState.run { - check(result is Created) + check(result is Created.InCart) copy( result = DomainRegistrationPurchased( event.domainName, From c0cfb5d655222356088d8cf9e7aec9f39a82b7ab Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 11:21:22 +0200 Subject: [PATCH 123/169] Test: on checkout result --- .../ui/sitecreation/SiteCreationFixtures.kt | 3 ++ .../ui/sitecreation/SiteCreationMainVMTest.kt | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index 469c720e98cc..7ecfe1b6e39d 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -9,6 +9,7 @@ import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType.GENERIC_ERROR import org.wordpress.android.fluxc.store.TransactionsStore.CreateShoppingCartError import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartCreated import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity +import org.wordpress.android.ui.domains.DomainRegistrationCompletedEvent import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed import org.wordpress.android.ui.sitecreation.SiteCreationResult.Created import org.wordpress.android.ui.sitecreation.domains.DomainModel @@ -51,5 +52,7 @@ val RESULT_CREATED = Created.NotInLocalDb(SITE_REMOTE_ID, false) val RESULT_IN_CART = Created.InCart(SITE_SLUG, SITE_REMOTE_ID, false) val RESULT_COMPLETED = Completed(SITE_LOCAL_ID, false, URL) +val CHECKOUT_EVENT = DomainRegistrationCompletedEvent(URL_CUSTOM, "email@host.com") + val SERVICE_SUCCESS = SiteCreationServiceState(SUCCESS, Pair(SITE_REMOTE_ID, URL)) val SERVICE_ERROR = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index cbfe6c266ba8..b2326d7e3ebc 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -33,6 +33,7 @@ import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleEmpty import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount +import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistrationPurchased import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.usecases.FetchHomePageLayoutsUseCase @@ -45,6 +46,7 @@ import org.wordpress.android.util.wizard.WizardManager import org.wordpress.android.viewmodel.SingleLiveEvent import org.wordpress.android.viewmodel.helpers.DialogHolder import kotlin.test.assertEquals +import kotlin.test.assertIs private const val SEGMENT_ID = 1L private const val VERTICAL = "Test Vertical" @@ -161,6 +163,36 @@ class SiteCreationMainVMTest : BaseUnitTest() { ) } + @Test + fun `on checkout result when null shows previous step`() { + viewModel.onCheckoutResult(null) + + verify(wizardManager).onBackPressed() + verify(onBackPressedObserver).onChanged(anyOrNull()) + } + + @Test + fun `on checkout result when not null shows next step`() { + viewModel.onCartCreated(CHECKOUT_DETAILS) + + viewModel.onCheckoutResult(CHECKOUT_EVENT) + + verify(wizardManager).showNextStep() + } + + @Test + fun `on checkout result when not null updates state with result`() { + viewModel.onCartCreated(CHECKOUT_DETAILS) + + viewModel.onCheckoutResult(CHECKOUT_EVENT) + + assertIs(currentWizardState(viewModel).result).run { + assertEquals(CHECKOUT_DETAILS.site.siteId, remoteId) + assertEquals(CHECKOUT_EVENT.domainName, domainName) + assertEquals(CHECKOUT_EVENT.email, email) + } + } + @Test fun `on progress screen finished updates state with result`() { viewModel.onProgressScreenFinished(SITE_REMOTE_ID) From 5df6b1d84af78dfa07e7d43214565b63af22c991 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 11:24:31 +0200 Subject: [PATCH 124/169] Refactor: imply site was not fetched in result name --- .../ui/sitecreation/SiteCreationActivity.kt | 7 +++---- .../android/ui/sitecreation/SiteCreationMainVM.kt | 14 +++++++------- .../sitecreation/previews/SitePreviewViewModel.kt | 4 ++-- .../progress/SiteCreationProgressViewModel.kt | 4 ++-- .../ui/sitecreation/SiteCreationFixtures.kt | 6 +++--- .../ui/sitecreation/SiteCreationMainVMTest.kt | 2 +- .../previews/SitePreviewViewModelTest.kt | 4 ++-- 7 files changed, 20 insertions(+), 21 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index dac9e59b49d6..c87fe35b24d2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -29,7 +29,7 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed -import org.wordpress.android.ui.sitecreation.SiteCreationResult.Created +import org.wordpress.android.ui.sitecreation.SiteCreationResult.CreatedButNotFetched import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistrationPurchased import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.SiteCreationStep.DOMAINS @@ -130,9 +130,8 @@ class SiteCreationActivity : LocaleAwareActivity(), is NotCreated -> { Triple(false, null, false) } - is Created -> { - // Site was created, but we haven't been able to fetch it, let `SitePickerActivity` handle - // this with a Snackbar message. + is CreatedButNotFetched -> { + // Let `SitePickerActivity` handle this with a Snackbar message intent.putExtra(SitePickerActivity.KEY_SITE_CREATED_BUT_NOT_FETCHED, true) Triple(true, null, isSiteTitleTaskComplete) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 33369dcfbecd..42e00e7997cf 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -24,7 +24,7 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed -import org.wordpress.android.ui.sitecreation.SiteCreationResult.Created +import org.wordpress.android.ui.sitecreation.SiteCreationResult.CreatedButNotFetched import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistrationPurchased import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.domains.DomainModel @@ -68,7 +68,7 @@ sealed interface SiteCreationResult : Parcelable { @Parcelize object NotCreated : SiteCreationResult - sealed interface Created : SiteCreationResult { + sealed interface CreatedButNotFetched : SiteCreationResult { val remoteId: Long val isSiteTitleTaskComplete: Boolean @@ -76,14 +76,14 @@ sealed interface SiteCreationResult : Parcelable { data class NotInLocalDb( override val remoteId: Long, override val isSiteTitleTaskComplete: Boolean, - ) : Created + ) : CreatedButNotFetched @Parcelize data class InCart( val siteSlug: String, override val remoteId: Long, override val isSiteTitleTaskComplete: Boolean, - ) : Created + ) : CreatedButNotFetched } @Parcelize @@ -291,7 +291,7 @@ class SiteCreationMainVM @Inject constructor( fun onCartCreated(checkoutDetails: CheckoutDetails) { siteCreationState = siteCreationState.copy( - result = Created.InCart(checkoutDetails.site.url, checkoutDetails.site.siteId, isSiteTitleTaskCompleted()) + result = CreatedButNotFetched.InCart(checkoutDetails.site.url, checkoutDetails.site.siteId, isSiteTitleTaskCompleted()) ) _showDomainCheckout.value = checkoutDetails } @@ -299,7 +299,7 @@ class SiteCreationMainVM @Inject constructor( fun onCheckoutResult(event: DomainRegistrationCompletedEvent?) { if (event == null) return onBackPressed() siteCreationState = siteCreationState.run { - check(result is Created.InCart) + check(result is CreatedButNotFetched.InCart) copy( result = DomainRegistrationPurchased( event.domainName, @@ -314,7 +314,7 @@ class SiteCreationMainVM @Inject constructor( fun onProgressScreenFinished(remoteSiteId: Long) { siteCreationState = siteCreationState.copy( - result = Created.NotInLocalDb(remoteSiteId, isSiteTitleTaskCompleted()) + result = CreatedButNotFetched.NotInLocalDb(remoteSiteId, isSiteTitleTaskCompleted()) ) wizardManager.showNextStep() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt index 8ca1eb63d711..ecff041b4825 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModel.kt @@ -16,7 +16,7 @@ import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.sitecreation.SiteCreationResult import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed -import org.wordpress.android.ui.sitecreation.SiteCreationResult.Created +import org.wordpress.android.ui.sitecreation.SiteCreationResult.CreatedButNotFetched import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.previews.SitePreviewViewModel.SitePreviewUiState.SitePreviewContentUiState @@ -80,7 +80,7 @@ class SitePreviewViewModel @Inject constructor( urlWithoutScheme = requireNotNull(siteCreationState.domain) { "url required for preview" }.domainName startPreLoadingWebView() result = siteCreationState.result.also { - if (it is Created) { + if (it is CreatedButNotFetched) { launch { fetchNewlyCreatedSiteModel(it.remoteId)?.run { result = Completed(id, it.isSiteTitleTaskComplete, url) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index 2a5aee9f7ffc..09a26bac296d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -14,7 +14,7 @@ import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity.OpenCheckout.CheckoutDetails import org.wordpress.android.ui.domains.DomainsRegistrationTracker import org.wordpress.android.ui.domains.usecases.CreateCartUseCase -import org.wordpress.android.ui.sitecreation.SiteCreationResult.Created +import org.wordpress.android.ui.sitecreation.SiteCreationResult.CreatedButNotFetched import org.wordpress.android.ui.sitecreation.SiteCreationState import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationErrorType.INTERNET_UNAVAILABLE_ERROR @@ -91,7 +91,7 @@ class SiteCreationProgressViewModel @Inject constructor( } fun start(siteCreationState: SiteCreationState) { - if (siteCreationState.result is Created.InCart) { + if (siteCreationState.result is CreatedButNotFetched.InCart) { // reuse the previously blog when returning with the same domain if (siteCreationState.domain == this.siteCreationState.domain) { createCart(siteCreationState.result.remoteId, siteCreationState.result.siteSlug) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index 7ecfe1b6e39d..f95ff72ff981 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -11,7 +11,7 @@ import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartCreated import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity import org.wordpress.android.ui.domains.DomainRegistrationCompletedEvent import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed -import org.wordpress.android.ui.sitecreation.SiteCreationResult.Created +import org.wordpress.android.ui.sitecreation.SiteCreationResult.CreatedButNotFetched import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState import org.wordpress.android.ui.sitecreation.services.SiteCreationServiceState.SiteCreationStep.CREATE_SITE @@ -48,8 +48,8 @@ val FETCH_ERROR = OnSiteChanged(0).apply { error = SiteError(GENERIC_ERROR) } val CART_SUCCESS = OnShoppingCartCreated(mock()) val CART_ERROR = OnShoppingCartCreated(mock()) -val RESULT_CREATED = Created.NotInLocalDb(SITE_REMOTE_ID, false) -val RESULT_IN_CART = Created.InCart(SITE_SLUG, SITE_REMOTE_ID, false) +val RESULT_NOT_IN_LOCAL_DB = CreatedButNotFetched.NotInLocalDb(SITE_REMOTE_ID, false) +val RESULT_IN_CART = CreatedButNotFetched.InCart(SITE_SLUG, SITE_REMOTE_ID, false) val RESULT_COMPLETED = Completed(SITE_LOCAL_ID, false, URL) val CHECKOUT_EVENT = DomainRegistrationCompletedEvent(URL_CUSTOM, "email@host.com") diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index b2326d7e3ebc..2f51332914ff 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -196,7 +196,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Test fun `on progress screen finished updates state with result`() { viewModel.onProgressScreenFinished(SITE_REMOTE_ID) - assertThat(currentWizardState(viewModel).result).isEqualTo(RESULT_CREATED) + assertThat(currentWizardState(viewModel).result).isEqualTo(RESULT_NOT_IN_LOCAL_DB) } @Test diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt index 0013944e817c..a0536a596a1d 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/previews/SitePreviewViewModelTest.kt @@ -23,7 +23,7 @@ import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged import org.wordpress.android.ui.sitecreation.FETCH_ERROR import org.wordpress.android.ui.sitecreation.FETCH_SUCCESS -import org.wordpress.android.ui.sitecreation.RESULT_CREATED +import org.wordpress.android.ui.sitecreation.RESULT_NOT_IN_LOCAL_DB import org.wordpress.android.ui.sitecreation.SITE_CREATION_STATE import org.wordpress.android.ui.sitecreation.SITE_REMOTE_ID import org.wordpress.android.ui.sitecreation.SUB_DOMAIN @@ -84,7 +84,7 @@ class SitePreviewViewModelTest : BaseUnitTest() { @Test fun `on start fetches site by remote id when result is created`() = testWith(FETCH_SUCCESS) { - startViewModel(SITE_CREATION_STATE.copy(result = RESULT_CREATED)) + startViewModel(SITE_CREATION_STATE.copy(result = RESULT_NOT_IN_LOCAL_DB)) verify(fetchWpComSiteUseCase).fetchSiteWithRetry(SITE_REMOTE_ID) } From af9558665854593a8576710ac4da913b0d069fe3 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 11:27:51 +0200 Subject: [PATCH 125/169] Refactor: replace `when` with `check` to enforce dialog contract --- .../ui/sitecreation/SiteCreationMainVM.kt | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 42e00e7997cf..91f91ecde07c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -341,21 +341,13 @@ class SiteCreationMainVM @Inject constructor( } fun onPositiveDialogButtonClicked(instanceTag: String) { - when (instanceTag) { - TAG_WARNING_DIALOG -> { - exitFlow(true) - } - else -> NotImplementedError("Unknown dialog tag: $instanceTag") - } + check(instanceTag == TAG_WARNING_DIALOG) { "Unknown dialog tag: $instanceTag" } + exitFlow(true) } fun onNegativeDialogButtonClicked(instanceTag: String) { - when (instanceTag) { - TAG_WARNING_DIALOG -> { - // do nothing - } - else -> NotImplementedError("Unknown dialog tag: $instanceTag") - } + check(instanceTag == TAG_WARNING_DIALOG) { "Unknown dialog tag: $instanceTag" } + // do nothing } sealed class SiteCreationScreenTitle { From 517d45c45c07e9c33c498eea2f296e5fb38d929a Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 12:40:14 +0200 Subject: [PATCH 126/169] Test: restart progress when returning from checkout --- .../SiteCreationProgressViewModelTest.kt | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt index 935ed3f6364f..e2a2bdc4273a 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.Observer import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.advanceUntilIdle import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test @@ -14,12 +15,17 @@ import org.mockito.kotlin.argThat import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.atMost import org.mockito.kotlin.check +import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.eq import org.mockito.kotlin.isNull import org.mockito.kotlin.mock +import org.mockito.kotlin.refEq +import org.mockito.kotlin.times import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyNoMoreInteractions import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest +import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartCreated import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity.OpenCheckout.CheckoutDetails import org.wordpress.android.ui.domains.DomainsRegistrationTracker @@ -27,6 +33,7 @@ import org.wordpress.android.ui.domains.usecases.CreateCartUseCase import org.wordpress.android.ui.sitecreation.CART_ERROR import org.wordpress.android.ui.sitecreation.CART_SUCCESS import org.wordpress.android.ui.sitecreation.PAID_DOMAIN +import org.wordpress.android.ui.sitecreation.RESULT_IN_CART import org.wordpress.android.ui.sitecreation.SERVICE_ERROR import org.wordpress.android.ui.sitecreation.SERVICE_SUCCESS import org.wordpress.android.ui.sitecreation.SITE_CREATION_STATE @@ -93,7 +100,6 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { startViewModel() assertNotNull(viewModel.startCreateSiteService.value) } - @Test fun `on start emits service event for free domains with isFree true`() = test { startViewModel(SITE_CREATION_STATE) @@ -214,6 +220,47 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { assertIs(viewModel.uiState.value) } + @Test + fun `on restart with same paid domain reuses previous blog to create new cart`() = testWith(CART_SUCCESS) { + val state = SITE_CREATION_STATE.copy(domain = PAID_DOMAIN) + startViewModel(state) + val previous = SiteModel().apply { siteId = 9L;url = "blog.wordpress.com" } + viewModel.onSiteCreationServiceStateUpdated(SERVICE_SUCCESS.copy(payload = previous.siteId to previous.url)) + + startViewModel(state.copy(result = RESULT_IN_CART)) + + verify(startServiceObserver, atMost(1)).onChanged(any()) + verify(createCartUseCase).execute( + refEq(previous), + eq(PAID_DOMAIN.productId), + eq(PAID_DOMAIN.domainName), + eq(PAID_DOMAIN.supportsPrivacy), + any() + ) + } + + @Test + fun `on restart with different paid domain emits service event`() = testWith(CART_SUCCESS) { + startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN)) + viewModel.onSiteCreationServiceStateUpdated(SERVICE_SUCCESS) + + startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN.copy(domainName = "different"))) + + verify(startServiceObserver, times(2)).onChanged(any()) + } + + @Test + fun `on restart with free domain emits service event`() = testWith(CART_SUCCESS) { + startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN)) + viewModel.onSiteCreationServiceStateUpdated(SERVICE_SUCCESS) + clearInvocations(createCartUseCase) + + startViewModel(SITE_CREATION_STATE) + + verify(startServiceObserver, times(2)).onChanged(any()) + verifyNoMoreInteractions(createCartUseCase) + } + // region Helpers private fun testWith(response: OnShoppingCartCreated, block: suspend CoroutineScope.() -> Unit) = test { whenever(createCartUseCase.execute(any(), any(), any(), any(), any())).thenReturn(response) From 3298017f8a6f03a80c833edb7649365eef75ca25 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 12:41:57 +0200 Subject: [PATCH 127/169] Refactor: fix line length lint issue --- .../wordpress/android/ui/sitecreation/SiteCreationMainVM.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 91f91ecde07c..89f92062f1e9 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -291,7 +291,11 @@ class SiteCreationMainVM @Inject constructor( fun onCartCreated(checkoutDetails: CheckoutDetails) { siteCreationState = siteCreationState.copy( - result = CreatedButNotFetched.InCart(checkoutDetails.site.url, checkoutDetails.site.siteId, isSiteTitleTaskCompleted()) + result = CreatedButNotFetched.InCart( + checkoutDetails.site.url, + checkoutDetails.site.siteId, + isSiteTitleTaskCompleted() + ) ) _showDomainCheckout.value = checkoutDetails } From b75332d65f7b6a1c5dd5a727e9cffe5071ddfebb Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 13:50:35 +0200 Subject: [PATCH 128/169] Refactor: cleanup test fixtures code --- .../android/ui/sitecreation/SiteCreationFixtures.kt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt index f95ff72ff981..886924561098 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationFixtures.kt @@ -27,7 +27,6 @@ val FREE_DOMAIN = DomainModel(URL, true, "", 1, false) val PAID_DOMAIN = DomainModel(URL_CUSTOM, false, "$1", 2, true) const val SITE_REMOTE_ID = 1L -private const val SITE_LOCAL_ID = 1 val SITE_CREATION_STATE = SiteCreationState( segmentId = 1, @@ -35,12 +34,10 @@ val SITE_CREATION_STATE = SiteCreationState( domain = FREE_DOMAIN, ) -val SITE_MODEL = SiteModel().apply { - siteId = SITE_REMOTE_ID - url = SITE_SLUG -} +val SITE_MODEL = SiteModel().apply { siteId = SITE_REMOTE_ID; url = SITE_SLUG } val CHECKOUT_DETAILS = DomainRegistrationCheckoutWebViewActivity.OpenCheckout.CheckoutDetails(SITE_MODEL, SITE_SLUG) +val CHECKOUT_EVENT = DomainRegistrationCompletedEvent(URL_CUSTOM, "email@host.com") val FETCH_SUCCESS = OnSiteChanged(1) val FETCH_ERROR = OnSiteChanged(0).apply { error = SiteError(GENERIC_ERROR) } @@ -50,9 +47,7 @@ val CART_ERROR = OnShoppingCartCreated(mock()) val RESULT_NOT_IN_LOCAL_DB = CreatedButNotFetched.NotInLocalDb(SITE_REMOTE_ID, false) val RESULT_IN_CART = CreatedButNotFetched.InCart(SITE_SLUG, SITE_REMOTE_ID, false) -val RESULT_COMPLETED = Completed(SITE_LOCAL_ID, false, URL) - -val CHECKOUT_EVENT = DomainRegistrationCompletedEvent(URL_CUSTOM, "email@host.com") +val RESULT_COMPLETED = Completed(1, false, URL) val SERVICE_SUCCESS = SiteCreationServiceState(SUCCESS, Pair(SITE_REMOTE_ID, URL)) val SERVICE_ERROR = SiteCreationServiceState(FAILURE, SiteCreationServiceState(CREATE_SITE)) From b70f5d9dbf58bea51fbe36205539fab5ecd7035c Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 13:51:16 +0200 Subject: [PATCH 129/169] Refactor: remove newline at start of file --- .../wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 2f51332914ff..098abed71545 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -1,4 +1,3 @@ - package org.wordpress.android.ui.sitecreation import android.os.Bundle From 95c5ae1f22b5f0f98dd11bb2f7c2de1d0aabe309 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 28 Mar 2023 13:52:52 +0200 Subject: [PATCH 130/169] Refactor: replace "updates state with result" to "updates result" --- .../android/ui/sitecreation/SiteCreationMainVMTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 098abed71545..24101ff88eea 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -151,7 +151,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { } @Test - fun `on cart created updates state with result`() { + fun `on cart created updates result`() { viewModel.onCartCreated(CHECKOUT_DETAILS) // Assert on the private state via bundle @@ -180,7 +180,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { } @Test - fun `on checkout result when not null updates state with result`() { + fun `on checkout result when not null updates result`() { viewModel.onCartCreated(CHECKOUT_DETAILS) viewModel.onCheckoutResult(CHECKOUT_EVENT) @@ -193,7 +193,7 @@ class SiteCreationMainVMTest : BaseUnitTest() { } @Test - fun `on progress screen finished updates state with result`() { + fun `on progress screen finished updates result`() { viewModel.onProgressScreenFinished(SITE_REMOTE_ID) assertThat(currentWizardState(viewModel).result).isEqualTo(RESULT_NOT_IN_LOCAL_DB) } From 61198775cab61d26241b45e156ba1ec8d5055374 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 29 Mar 2023 20:51:29 +0200 Subject: [PATCH 131/169] Refactor: optimize result model to 3 variants --- .../ui/sitecreation/SiteCreationActivity.kt | 5 ----- .../ui/sitecreation/SiteCreationMainVM.kt | 19 +++++++++---------- .../ui/sitecreation/SiteCreationMainVMTest.kt | 2 +- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt index c87fe35b24d2..e93c5b3f43d2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationActivity.kt @@ -30,7 +30,6 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed import org.wordpress.android.ui.sitecreation.SiteCreationResult.CreatedButNotFetched -import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistrationPurchased import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.SiteCreationStep.DOMAINS import org.wordpress.android.ui.sitecreation.SiteCreationStep.INTENTS @@ -135,10 +134,6 @@ class SiteCreationActivity : LocaleAwareActivity(), intent.putExtra(SitePickerActivity.KEY_SITE_CREATED_BUT_NOT_FETCHED, true) Triple(true, null, isSiteTitleTaskComplete) } - is DomainRegistrationPurchased -> { - intent.putExtra(SitePickerActivity.KEY_SITE_CREATED_BUT_NOT_FETCHED, true) - Triple(true, null, isSiteTitleTaskComplete) - } is Completed -> { Triple(true, localId, isSiteTitleTaskComplete) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index 89f92062f1e9..d73082c89e27 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -25,7 +25,6 @@ import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScre import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount import org.wordpress.android.ui.sitecreation.SiteCreationResult.Completed import org.wordpress.android.ui.sitecreation.SiteCreationResult.CreatedButNotFetched -import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistrationPurchased import org.wordpress.android.ui.sitecreation.SiteCreationResult.NotCreated import org.wordpress.android.ui.sitecreation.domains.DomainModel import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource @@ -84,15 +83,15 @@ sealed interface SiteCreationResult : Parcelable { override val remoteId: Long, override val isSiteTitleTaskComplete: Boolean, ) : CreatedButNotFetched - } - @Parcelize - data class DomainRegistrationPurchased( - val domainName: String, - val email: String, - val remoteId: Long, - val isSiteTitleTaskComplete: Boolean, - ) : SiteCreationResult + @Parcelize + data class DomainRegistrationPurchased( + val domainName: String, + val email: String, + override val remoteId: Long, + override val isSiteTitleTaskComplete: Boolean, + ) : CreatedButNotFetched + } @Parcelize data class Completed(val localId: Int, val isSiteTitleTaskComplete: Boolean, val url: String) : SiteCreationResult @@ -305,7 +304,7 @@ class SiteCreationMainVM @Inject constructor( siteCreationState = siteCreationState.run { check(result is CreatedButNotFetched.InCart) copy( - result = DomainRegistrationPurchased( + result = CreatedButNotFetched.DomainRegistrationPurchased( event.domainName, event.email, result.remoteId, diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 24101ff88eea..06ac6072e755 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -32,7 +32,7 @@ import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleEmpty import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleStepCount -import org.wordpress.android.ui.sitecreation.SiteCreationResult.DomainRegistrationPurchased +import org.wordpress.android.ui.sitecreation.SiteCreationResult.CreatedButNotFetched.DomainRegistrationPurchased import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource import org.wordpress.android.ui.sitecreation.misc.SiteCreationTracker import org.wordpress.android.ui.sitecreation.usecases.FetchHomePageLayoutsUseCase From d7a4cd31b0b546d1f8192ffa2a6472ddbcaaa3f7 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 29 Mar 2023 21:06:28 +0200 Subject: [PATCH 132/169] Refactor: track checkout webview viewed event in main vm --- .../android/ui/sitecreation/SiteCreationMainVM.kt | 3 +++ .../progress/SiteCreationProgressViewModel.kt | 3 --- .../ui/sitecreation/SiteCreationMainVMTest.kt | 13 ++++++++++++- .../progress/SiteCreationProgressViewModelTest.kt | 10 ---------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt index d73082c89e27..9bde487af692 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVM.kt @@ -19,6 +19,7 @@ import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.networking.MShot import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity.OpenCheckout.CheckoutDetails import org.wordpress.android.ui.domains.DomainRegistrationCompletedEvent +import org.wordpress.android.ui.domains.DomainsRegistrationTracker import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleEmpty import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral @@ -108,6 +109,7 @@ class SiteCreationMainVM @Inject constructor( private val jetpackFeatureRemovalOverlayUtil: JetpackFeatureRemovalOverlayUtil, private val domainPurchasingExperiment: SiteCreationDomainPurchasingExperiment, private val domainPurchasingFeatureConfig: SiteCreationDomainPurchasingFeatureConfig, + private val domainsRegistrationTracker: DomainsRegistrationTracker, ) : ViewModel() { init { dispatcher.register(fetchHomePageLayoutsUseCase) @@ -296,6 +298,7 @@ class SiteCreationMainVM @Inject constructor( isSiteTitleTaskCompleted() ) ) + domainsRegistrationTracker.trackDomainsPurchaseWebviewViewed(checkoutDetails.site, isSiteCreation = true) _showDomainCheckout.value = checkoutDetails } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt index 09a26bac296d..a45c86a5e4ee 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModel.kt @@ -12,7 +12,6 @@ import org.wordpress.android.R import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity.OpenCheckout.CheckoutDetails -import org.wordpress.android.ui.domains.DomainsRegistrationTracker import org.wordpress.android.ui.domains.usecases.CreateCartUseCase import org.wordpress.android.ui.sitecreation.SiteCreationResult.CreatedButNotFetched import org.wordpress.android.ui.sitecreation.SiteCreationState @@ -54,7 +53,6 @@ private val loadingTexts = listOf( class SiteCreationProgressViewModel @Inject constructor( private val networkUtils: NetworkUtilsWrapper, private val tracker: SiteCreationTracker, - private val domainsRegistrationTracker: DomainsRegistrationTracker, private val createCartUseCase: CreateCartUseCase, @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, ) : ScopedViewModel(mainDispatcher) { @@ -198,7 +196,6 @@ class SiteCreationProgressViewModel @Inject constructor( } else { AppLog.d(LOG_TAG, "Successful cart creation: ${event.cartDetails}") _onCartCreated.postValue(CheckoutDetails(site, domain.domainName)) - domainsRegistrationTracker.trackDomainsPurchaseWebviewViewed(site, isSiteCreation = true) } } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt index 06ac6072e755..b62eafa44a8d 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/SiteCreationMainVMTest.kt @@ -28,6 +28,7 @@ import org.wordpress.android.R import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.model.experiments.Variation.Control import org.wordpress.android.fluxc.model.experiments.Variation.Treatment +import org.wordpress.android.ui.domains.DomainsRegistrationTracker import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleEmpty import org.wordpress.android.ui.sitecreation.SiteCreationMainVM.SiteCreationScreenTitle.ScreenTitleGeneral @@ -104,6 +105,9 @@ class SiteCreationMainVMTest : BaseUnitTest() { @Mock lateinit var domainPurchasingFeatureConfig: SiteCreationDomainPurchasingFeatureConfig + @Mock + lateinit var domainsRegistrationTracker: DomainsRegistrationTracker + private val wizardManagerNavigatorLiveData = SingleLiveEvent() private lateinit var viewModel: SiteCreationMainVM @@ -145,11 +149,17 @@ class SiteCreationMainVMTest : BaseUnitTest() { } @Test - fun `on cart created is propagated`() { + fun `on cart created propagates details to show checkout`() { viewModel.onCartCreated(CHECKOUT_DETAILS) assertEquals(CHECKOUT_DETAILS, viewModel.showDomainCheckout.value) } + @Test + fun `on cart created tracks checkout webview viewed`() { + viewModel.onCartCreated(CHECKOUT_DETAILS) + verify(domainsRegistrationTracker).trackDomainsPurchaseWebviewViewed(eq(CHECKOUT_DETAILS.site), eq(true)) + } + @Test fun `on cart created updates result`() { viewModel.onCartCreated(CHECKOUT_DETAILS) @@ -398,5 +408,6 @@ class SiteCreationMainVMTest : BaseUnitTest() { jetpackFeatureRemovalOverlayUtil, domainPurchasingExperiment, domainPurchasingFeatureConfig, + domainsRegistrationTracker, ) } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt index e2a2bdc4273a..f96eafd3e223 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitecreation/progress/SiteCreationProgressViewModelTest.kt @@ -28,7 +28,6 @@ import org.wordpress.android.BaseUnitTest import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartCreated import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity.OpenCheckout.CheckoutDetails -import org.wordpress.android.ui.domains.DomainsRegistrationTracker import org.wordpress.android.ui.domains.usecases.CreateCartUseCase import org.wordpress.android.ui.sitecreation.CART_ERROR import org.wordpress.android.ui.sitecreation.CART_SUCCESS @@ -58,7 +57,6 @@ import kotlin.test.assertTrue class SiteCreationProgressViewModelTest : BaseUnitTest() { private var networkUtils = mock() private var tracker = mock() - private val domainsRegistrationTracker = mock() private val createCartUseCase = mock() private val uiStateObserver = mock>() @@ -75,7 +73,6 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { viewModel = SiteCreationProgressViewModel( networkUtils, tracker, - domainsRegistrationTracker, createCartUseCase, testDispatcher(), ) @@ -188,13 +185,6 @@ class SiteCreationProgressViewModelTest : BaseUnitTest() { ) } - @Test - fun `on cart success tracks domain purchase webview viewed`() = testWith(CART_SUCCESS) { - startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN)) - viewModel.onSiteCreationServiceStateUpdated(SERVICE_SUCCESS) - verify(domainsRegistrationTracker).trackDomainsPurchaseWebviewViewed(any(), eq(true)) - } - @Test fun `on cart success propagates checkout details`() = testWith(CART_SUCCESS) { startViewModel(SITE_CREATION_STATE.copy(domain = PAID_DOMAIN)) From 1d1986f089a954445973aa12af5e02204947b46c Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Sun, 9 Apr 2023 00:54:10 +0300 Subject: [PATCH 133/169] Fix the crash on reader post list screen ReaderPostListActivity is migrated to the Hilt to fix the crash. --- .../main/java/org/wordpress/android/modules/AppComponent.java | 3 --- .../wordpress/android/ui/reader/ReaderPostListActivity.java | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java b/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java index 7bf3acf80190..be4024ac52ca 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java @@ -136,7 +136,6 @@ import org.wordpress.android.ui.reader.CommentNotificationsBottomSheetFragment; import org.wordpress.android.ui.reader.ReaderBlogFragment; import org.wordpress.android.ui.reader.ReaderPostDetailFragment; -import org.wordpress.android.ui.reader.ReaderPostListActivity; import org.wordpress.android.ui.reader.ReaderPostListFragment; import org.wordpress.android.ui.reader.ReaderPostPagerActivity; import org.wordpress.android.ui.reader.ReaderSearchActivity; @@ -342,8 +341,6 @@ public interface AppComponent { void inject(ReaderPostPagerActivity object); - void inject(ReaderPostListActivity object); - void inject(ReaderBlogFragment object); void inject(ReaderBlogAdapter object); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java index 9f3a8e422bfe..8f6df01769f0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java @@ -46,9 +46,12 @@ import javax.inject.Inject; +import dagger.hilt.android.AndroidEntryPoint; + /* * serves as the host for ReaderPostListFragment when showing blog preview & tag preview */ +@AndroidEntryPoint public class ReaderPostListActivity extends LocaleAwareActivity { private String mSource; private ReaderPostListType mPostListType; @@ -65,7 +68,6 @@ public class ReaderPostListActivity extends LocaleAwareActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ((WordPress) getApplication()).component().inject(this); setContentView(R.layout.reader_activity_post_list); From 5e2300046de76dee9c19c275655e4217a52b4c1c Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Sun, 9 Apr 2023 17:22:24 +0300 Subject: [PATCH 134/169] Get package name dynamically in ReaderTests --- .../android/e2e/pages/ReaderViewPage.kt | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderViewPage.kt b/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderViewPage.kt index aed5f4c374a8..5edabffbea86 100644 --- a/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderViewPage.kt +++ b/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderViewPage.kt @@ -8,53 +8,57 @@ import junit.framework.TestCase import org.wordpress.android.support.WPSupportUtils class ReaderViewPage { - var mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - var mLikerContainerId = "org.wordpress.android.prealpha:id/liker_faces_container" - var mRelatedPostsId = "org.wordpress.android.prealpha:id/container_related_posts" - var mFooterId = "org.wordpress.android.prealpha:id/layout_post_detail_footer" - var mLikerContainer = mDevice.findObject(UiSelector().resourceId(mLikerContainerId)) - var mRelatedPostsContainer = mDevice.findObject(UiSelector().resourceId(mRelatedPostsId)) - var mSwipeForMore = mDevice.findObject(UiSelector().textContains("Swipe for more")) - var mFooter = mDevice.findObject(UiSelector().resourceId(mFooterId)) + private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + private val likerContainer = device.findObject(UiSelector().resourceId(buildResourceId("liker_faces_container"))) + private val relatedPostsContainer = device.findObject( + UiSelector().resourceId(buildResourceId("container_related_posts")) + ) + private val swipeForMore = device.findObject(UiSelector().textContains("Swipe for more")) + + private fun buildResourceId(id: String): String { + val packageName = InstrumentationRegistry.getInstrumentation().targetContext.packageName + return "$packageName:id/$id" + } + fun waitUntilLoaded(): ReaderViewPage { - mRelatedPostsContainer.waitForExists(WPSupportUtils.DEFAULT_TIMEOUT.toLong()) + relatedPostsContainer.waitForExists(WPSupportUtils.DEFAULT_TIMEOUT.toLong()) return this } fun likePost(): ReaderViewPage { tapLikeButton() - mLikerContainer.waitForExists(WPSupportUtils.DEFAULT_TIMEOUT.toLong()) + likerContainer.waitForExists(WPSupportUtils.DEFAULT_TIMEOUT.toLong()) return this } fun unlikePost(): ReaderViewPage { tapLikeButton() - mLikerContainer.waitUntilGone(WPSupportUtils.DEFAULT_TIMEOUT.toLong()) + likerContainer.waitUntilGone(WPSupportUtils.DEFAULT_TIMEOUT.toLong()) return this } private fun tapLikeButton() { - mSwipeForMore.waitUntilGone(WPSupportUtils.DEFAULT_TIMEOUT.toLong()) + swipeForMore.waitUntilGone(WPSupportUtils.DEFAULT_TIMEOUT.toLong()) // Even though it was working locally in simulator, tapping the footer buttons, // like 'mLikeButton.click()', was not working in CI. // The current workaround is to use arrows navigation. // Bring focus to the footer. First button is selected. - mDevice.pressKeyCode(KeyEvent.KEYCODE_DPAD_DOWN) + device.pressKeyCode(KeyEvent.KEYCODE_DPAD_DOWN) // Navigate to Like button. - mDevice.pressKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT) - mDevice.pressKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT) - mDevice.pressKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT) + device.pressKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT) + device.pressKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT) + device.pressKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT) // Click the Like button. - mDevice.pressKeyCode(KeyEvent.KEYCODE_DPAD_CENTER) + device.pressKeyCode(KeyEvent.KEYCODE_DPAD_CENTER) // Navigate back to the first footer button. - mDevice.pressKeyCode(KeyEvent.KEYCODE_DPAD_LEFT) - mDevice.pressKeyCode(KeyEvent.KEYCODE_DPAD_LEFT) - mDevice.pressKeyCode(KeyEvent.KEYCODE_DPAD_LEFT) + device.pressKeyCode(KeyEvent.KEYCODE_DPAD_LEFT) + device.pressKeyCode(KeyEvent.KEYCODE_DPAD_LEFT) + device.pressKeyCode(KeyEvent.KEYCODE_DPAD_LEFT) } fun goBackToReader(): ReaderPage { - mDevice.pressBack() + device.pressBack() return ReaderPage() } @@ -77,7 +81,7 @@ class ReaderViewPage { } fun verifyPostLiked(): ReaderViewPage { - val isLiked = mDevice + val isLiked = device .findObject(UiSelector().textContains("You like this.")) .waitForExists(WPSupportUtils.DEFAULT_TIMEOUT.toLong()) TestCase.assertTrue("Liker was not displayed.", isLiked) @@ -85,7 +89,7 @@ class ReaderViewPage { } fun verifyPostNotLiked(): ReaderViewPage { - val likerDisplayed = mLikerContainer.exists() + val likerDisplayed = likerContainer.exists() TestCase.assertFalse("Liker faces container was displayed.", likerDisplayed) return this } From 8479ba67385b022b25e9fa62fd7f6821a0746ed2 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Sun, 9 Apr 2023 19:03:43 +0300 Subject: [PATCH 135/169] Add a test for bookmarking in post list screen --- .../org/wordpress/android/e2e/ReaderTests.kt | 27 +- .../wordpress/android/e2e/pages/ReaderPage.kt | 7 + .../android/e2e/pages/ReaderViewPage.kt | 24 + .../reader/rest_v11_read_sites_179863948.json | 59 + .../rest_v12_read_sites_179863948_posts.json | 5812 +++++++++++++++++ 5 files changed, 5922 insertions(+), 7 deletions(-) create mode 100644 libs/mocks/src/main/assets/mocks/mappings/wpcom/reader/rest_v11_read_sites_179863948.json create mode 100644 libs/mocks/src/main/assets/mocks/mappings/wpcom/reader/rest_v12_read_sites_179863948_posts.json diff --git a/WordPress/src/androidTest/java/org/wordpress/android/e2e/ReaderTests.kt b/WordPress/src/androidTest/java/org/wordpress/android/e2e/ReaderTests.kt index e353e82ae306..b3183f9f2dab 100644 --- a/WordPress/src/androidTest/java/org/wordpress/android/e2e/ReaderTests.kt +++ b/WordPress/src/androidTest/java/org/wordpress/android/e2e/ReaderTests.kt @@ -21,18 +21,16 @@ class ReaderTests : BaseTest() { ReaderPage().go() } - var mCoachingPostTitle = "Let's check out the coaching team!" - var mCompetitionPostTitle = "Let's focus on the competition." @Test fun e2eNavigateThroughPosts() { ReaderPage() .tapFollowingTab() - .openPost(mCoachingPostTitle) - .verifyPostDisplayed(mCoachingPostTitle) + .openPost(TITLE_COACHING_POST) + .verifyPostDisplayed(TITLE_COACHING_POST) .slideToPreviousPost() - .verifyPostDisplayed(mCompetitionPostTitle) + .verifyPostDisplayed(TITLE_COMPETITION_POST) .slideToNextPost() - .verifyPostDisplayed(mCoachingPostTitle) + .verifyPostDisplayed(TITLE_COACHING_POST) .goBackToReader() } @@ -40,11 +38,26 @@ class ReaderTests : BaseTest() { fun e2eLikePost() { ReaderPage() .tapFollowingTab() - .openPost(mCoachingPostTitle) + .openPost(TITLE_COACHING_POST) .likePost() .verifyPostLiked() .unlikePost() .verifyPostNotLiked() .goBackToReader() } + + @Test + fun e2eBookmarkPost() { + ReaderPage() + .openBlog(TITLE_BLOG) + .bookmarkPost() + .verifyPostBookmarked() + .goBackToReader() + } + + companion object { + private const val TITLE_BLOG = "Technical World" + private const val TITLE_COACHING_POST = "Let's check out the coaching team!" + private const val TITLE_COMPETITION_POST = "Let's focus on the competition." + } } diff --git a/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderPage.kt b/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderPage.kt index 15fc175dafd4..f8bad6a9417d 100644 --- a/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderPage.kt +++ b/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderPage.kt @@ -16,6 +16,13 @@ class ReaderPage { return this } + fun openBlog(blogName: String?): ReaderViewPage { + val post = Espresso.onView(ViewMatchers.withChild(ViewMatchers.withText(blogName))) + WPSupportUtils.scrollIntoView(R.id.ptr_layout, post, 1f) + WPSupportUtils.clickOn(blogName) + return ReaderViewPage().waitUntilLoaded() + } + fun openPost(postTitle: String?): ReaderViewPage { val post = Espresso.onView(ViewMatchers.withChild(ViewMatchers.withText(postTitle))) WPSupportUtils.scrollIntoView(R.id.reader_recycler_view, post, 1f) diff --git a/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderViewPage.kt b/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderViewPage.kt index 5edabffbea86..749cea9ab349 100644 --- a/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderViewPage.kt +++ b/WordPress/src/androidTest/java/org/wordpress/android/e2e/pages/ReaderViewPage.kt @@ -14,6 +14,8 @@ class ReaderViewPage { UiSelector().resourceId(buildResourceId("container_related_posts")) ) private val swipeForMore = device.findObject(UiSelector().textContains("Swipe for more")) + private val savePostsForLater = device.findObject(UiSelector().text("Save Posts for Later")) + private val ok = device.findObject(UiSelector().text("OK")) private fun buildResourceId(id: String): String { val packageName = InstrumentationRegistry.getInstrumentation().targetContext.packageName @@ -57,6 +59,21 @@ class ReaderViewPage { device.pressKeyCode(KeyEvent.KEYCODE_DPAD_LEFT) } + fun bookmarkPost(): ReaderViewPage { + // Navigate to Bookmark button. + device.pressKeyCode(KeyEvent.KEYCODE_TAB) + device.pressKeyCode(KeyEvent.KEYCODE_TAB) + device.pressKeyCode(KeyEvent.KEYCODE_TAB) + device.pressKeyCode(KeyEvent.KEYCODE_TAB) + // Click the Bookmark button. + device.pressKeyCode(KeyEvent.KEYCODE_DPAD_CENTER) + // Dismiss save posts locally dialog. + if (savePostsForLater.exists()) { + ok.clickAndWaitForNewWindow() + } + return this + } + fun goBackToReader(): ReaderPage { device.pressBack() return ReaderPage() @@ -93,4 +110,11 @@ class ReaderViewPage { TestCase.assertFalse("Liker faces container was displayed.", likerDisplayed) return this } + + fun verifyPostBookmarked(): ReaderViewPage { + val isBookmarked = device.findObject(UiSelector().text("Post saved")) + .waitForExists(WPSupportUtils.DEFAULT_TIMEOUT.toLong()) + TestCase.assertTrue("Snackbar was not displayed.", isBookmarked) + return this + } } diff --git a/libs/mocks/src/main/assets/mocks/mappings/wpcom/reader/rest_v11_read_sites_179863948.json b/libs/mocks/src/main/assets/mocks/mappings/wpcom/reader/rest_v11_read_sites_179863948.json new file mode 100644 index 000000000000..7e1f9b263a16 --- /dev/null +++ b/libs/mocks/src/main/assets/mocks/mappings/wpcom/reader/rest_v11_read_sites_179863948.json @@ -0,0 +1,59 @@ +{ + "request": { + "urlPath": "/rest/v1.1/read/sites/179863948", + "method": "GET", + "queryParameters": { + "locale": { + "matches": "(.*)" + } + } + }, + "response": { + "status": 200, + "jsonBody": { + "ID": 179863948, + "name": "Technical World", + "description": "never give up", + "URL": "http:\/\/technicalworled.tech.blog", + "jetpack": false, + "jetpack_connection": false, + "subscribers_count": 295, + "locale": false, + "icon": { + "img": "https:\/\/technicalworledtech.files.wordpress.com\/2020\/08\/wp-1597659805687.jpg?w=96", + "ico": "https:\/\/technicalworledtech.files.wordpress.com\/2020\/08\/wp-1597659805687.jpg?w=96" + }, + "logo": { + "id": 0, + "sizes": [], + "url": "" + }, + "visible": null, + "is_private": false, + "is_coming_soon": false, + "is_following": false, + "organization_id": 0, + "meta": { + "links": { + "self": "https:\/\/public-api.wordpress.com\/rest\/v1.2\/sites\/179863948", + "help": "https:\/\/public-api.wordpress.com\/rest\/v1.2\/sites\/179863948\/help", + "posts": "https:\/\/public-api.wordpress.com\/rest\/v1.2\/sites\/179863948\/posts\/", + "comments": "https:\/\/public-api.wordpress.com\/rest\/v1.1\/sites\/179863948\/comments\/", + "xmlrpc": "https:\/\/technicalworledtech.wordpress.com\/xmlrpc.php" + } + }, + "launch_status": false, + "site_migration": null, + "is_fse_active": false, + "is_fse_eligible": false, + "is_core_site_editor_enabled": false, + "is_wpcom_atomic": false, + "is_wpcom_staging_site": false + }, + "headers": { + "Content-Type": "application/json", + "Connection": "keep-alive", + "Cache-Control": "no-cache, must-revalidate, max-age=0" + } + } +} diff --git a/libs/mocks/src/main/assets/mocks/mappings/wpcom/reader/rest_v12_read_sites_179863948_posts.json b/libs/mocks/src/main/assets/mocks/mappings/wpcom/reader/rest_v12_read_sites_179863948_posts.json new file mode 100644 index 000000000000..d3e5b5443872 --- /dev/null +++ b/libs/mocks/src/main/assets/mocks/mappings/wpcom/reader/rest_v12_read_sites_179863948_posts.json @@ -0,0 +1,5812 @@ +{ + "request": { + "urlPath": "/rest/v1.2/read/sites/179863948/posts/", + "method": "GET", + "queryParameters": { + "locale": { + "matches": "(.*)" + }, + "meta": { + "equalTo": "site,likes" + } + } + }, + "response": { + "status": 200, + "jsonBody": { + "found": 52, + "posts": [ + { + "ID": 396, + "site_ID": 179863948, + "author": { + "ID": 189322726, + "login": "shivamchoudhary1911", + "email": false, + "name": "Shivam Choudhary", + "first_name": "Shivam", + "last_name": "Choudhary", + "nice_name": "shivamchoudhary1911", + "URL": "https:\/\/bestinformationavailable.wordpress.com\/", + "avatar_URL": "https:\/\/2.gravatar.com\/avatar\/8df388309ebb33505f3404b524807586?s=96&d=identicon&r=G", + "profile_URL": "https:\/\/en.gravatar.com\/shivamchoudhary1911", + "site_ID": 179868076, + "has_avatar": true + }, + "date": "2020-10-07T12:12:48+01:00", + "modified": "2020-10-07T12:12:48+01:00", + "title": "India was the most cyber-attacked country in the world for three months", + "URL": "http:\/\/technicalworled.tech.blog\/2020\/10\/07\/india-was-the-most-cyber-attacked-country-in-the-world-for-three-months\/", + "short_URL": "https:\/\/wp.me\/pcaGPq-6o", + "content": "
\n

Rise in ransomware hacking makes\u00a0India the second<\/a> most attacked<\/strong>\u00a0country globally. After COVID infections, here\u2019s another dubious rise to the No.2 spot for\u00a0India<\/strong>\u2014ransomware\u00a0attacks<\/strong>. \u2026 \u201cRansomware\u00a0is<\/strong>\u00a0breaking records in 2020,\u201d quipped Lotem Finkelsteen, Check Point\u2019s head of threat intelligence.<\/p>\n\n\n\n