From 8db200192e726382004a799dc772ce817c4a17f3 Mon Sep 17 00:00:00 2001 From: Renan Lukas <14964993+RenanLukas@users.noreply.github.com> Date: Mon, 21 Mar 2022 03:45:43 -0300 Subject: [PATCH 001/173] Integrate ExPlat to project: create ExperimentationModule --- WooCommerce/build.gradle | 2 + .../android/di/ExperimentationModule.kt | 39 +++++++++++++++++++ .../experiment/TestExperiment.kt | 10 +++++ .../android/ui/main/MainActivity.kt | 1 + 4 files changed, 52 insertions(+) create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/experimentation/experiment/TestExperiment.kt diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index a3e9abcebd9..ebbe40dfa4e 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -24,6 +24,7 @@ repositories { includeGroup "org.wordpress.wellsql" includeGroup "org.wordpress.mediapicker" includeGroup "com.automattic" + includeGroup "com.automattic.tracks" } } maven { @@ -200,6 +201,7 @@ dependencies { } implementation 'com.github.Automattic:Automattic-Tracks-Android:2.1.0' + implementation "com.automattic.tracks:experimentation:121-cf817e1b407a6b9389055495d7b264b68debd69d" implementation("${gradle.ext.fluxCBinaryPath}:$fluxCVersion") { exclude group: "com.android.support" diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt new file mode 100644 index 00000000000..35756cba4e5 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt @@ -0,0 +1,39 @@ +package com.woocommerce.android.di + +import com.automattic.android.experimentation.ExPlat +import com.automattic.android.experimentation.Experiment +import com.woocommerce.android.BuildConfig +import dagger.Lazy +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.CoroutineScope +import org.wordpress.android.fluxc.store.ExperimentStore +import org.wordpress.android.fluxc.utils.AppLogWrapper +import javax.inject.Singleton + +@InstallIn(SingletonComponent::class) +@Module +class ExperimentationModule { + @Provides + @Singleton + fun provideExperiments(exPlat: ExPlat): Set = setOf() + + @Provides + @Singleton + fun provideExPlat( + experiments: Lazy>, + experimentStore: ExperimentStore, + appLogWrapper: AppLogWrapper, + @AppCoroutineScope appCoroutineScope: CoroutineScope, + ) = ExPlat( + platform = ExperimentStore.Platform.WOOCOMMERCE_ANDROID, + experiments = experiments, + experimentStore = experimentStore, + appLogWrapper = appLogWrapper, + coroutineScope = appCoroutineScope, + isDebug = BuildConfig.DEBUG + + ) +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/experimentation/experiment/TestExperiment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/experimentation/experiment/TestExperiment.kt new file mode 100644 index 00000000000..412d2e3930e --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/experimentation/experiment/TestExperiment.kt @@ -0,0 +1,10 @@ +package com.woocommerce.android.experimentation.experiment + +import com.automattic.android.experimentation.ExPlat +import com.automattic.android.experimentation.Experiment +import javax.inject.Inject + +class TestExperiment @Inject constructor(exPlat: ExPlat) : Experiment( + name = "test", + exPlat = exPlat +) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt index ff946c27711..70f4a9d02e4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt @@ -33,6 +33,7 @@ import com.woocommerce.android.R.dimen import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.databinding.ActivityMainBinding +import com.woocommerce.android.experimentation.experiment.TestExperiment import com.woocommerce.android.extensions.active import com.woocommerce.android.extensions.collapse import com.woocommerce.android.extensions.expand From 2c7be3683f1130331b832adcb8b18d317e971e18 Mon Sep 17 00:00:00 2001 From: Renan Lukas <14964993+RenanLukas@users.noreply.github.com> Date: Mon, 21 Mar 2022 04:14:15 -0300 Subject: [PATCH 002/173] Fix detekt warning: UnusedPrivateMember in ExperimentationModule --- .../kotlin/com/woocommerce/android/di/ExperimentationModule.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt index 35756cba4e5..d1e8b7d7c4f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt @@ -16,6 +16,8 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) @Module class ExperimentationModule { + //Suppress can be removed after the first Experiment is added + @Suppress("UnusedPrivateMember") @Provides @Singleton fun provideExperiments(exPlat: ExPlat): Set = setOf() From 2f9113fb0cbf0d17fb838c692fd529c8717078bb Mon Sep 17 00:00:00 2001 From: Renan Lukas <14964993+RenanLukas@users.noreply.github.com> Date: Mon, 21 Mar 2022 04:17:06 -0300 Subject: [PATCH 003/173] Fix detekt warning: unused import in MainActivity, delete unused class TestExperiment --- .../experimentation/experiment/TestExperiment.kt | 10 ---------- .../com/woocommerce/android/ui/main/MainActivity.kt | 1 - 2 files changed, 11 deletions(-) delete mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/experimentation/experiment/TestExperiment.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/experimentation/experiment/TestExperiment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/experimentation/experiment/TestExperiment.kt deleted file mode 100644 index 412d2e3930e..00000000000 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/experimentation/experiment/TestExperiment.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.woocommerce.android.experimentation.experiment - -import com.automattic.android.experimentation.ExPlat -import com.automattic.android.experimentation.Experiment -import javax.inject.Inject - -class TestExperiment @Inject constructor(exPlat: ExPlat) : Experiment( - name = "test", - exPlat = exPlat -) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt index 70f4a9d02e4..ff946c27711 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt @@ -33,7 +33,6 @@ import com.woocommerce.android.R.dimen import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.databinding.ActivityMainBinding -import com.woocommerce.android.experimentation.experiment.TestExperiment import com.woocommerce.android.extensions.active import com.woocommerce.android.extensions.collapse import com.woocommerce.android.extensions.expand From 145c67d44c12789700bde09e285532b31fc22fbf Mon Sep 17 00:00:00 2001 From: Renan Lukas <14964993+RenanLukas@users.noreply.github.com> Date: Mon, 21 Mar 2022 04:26:15 -0300 Subject: [PATCH 004/173] Fix detekt warning: comment spacing, add TODO to ExperimentationModule comment --- .../kotlin/com/woocommerce/android/di/ExperimentationModule.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt index d1e8b7d7c4f..87eada3cd75 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt @@ -16,7 +16,7 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) @Module class ExperimentationModule { - //Suppress can be removed after the first Experiment is added + // TODO Suppress can be removed after the first Experiment is added @Suppress("UnusedPrivateMember") @Provides @Singleton @@ -36,6 +36,5 @@ class ExperimentationModule { appLogWrapper = appLogWrapper, coroutineScope = appCoroutineScope, isDebug = BuildConfig.DEBUG - ) } From fd1f4d76180096d7c2cf2e931caa958045bf969a Mon Sep 17 00:00:00 2001 From: Renan Lukas <14964993+RenanLukas@users.noreply.github.com> Date: Wed, 27 Apr 2022 19:49:52 -0300 Subject: [PATCH 005/173] Update ExperimentationModule with new experimentation dependency version --- .../woocommerce/android/di/ExperimentationModule.kt | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt index 87eada3cd75..f4dec2e4f03 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt @@ -1,9 +1,7 @@ package com.woocommerce.android.di import com.automattic.android.experimentation.ExPlat -import com.automattic.android.experimentation.Experiment import com.woocommerce.android.BuildConfig -import dagger.Lazy import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -16,22 +14,16 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) @Module class ExperimentationModule { - // TODO Suppress can be removed after the first Experiment is added - @Suppress("UnusedPrivateMember") - @Provides - @Singleton - fun provideExperiments(exPlat: ExPlat): Set = setOf() @Provides @Singleton fun provideExPlat( - experiments: Lazy>, experimentStore: ExperimentStore, appLogWrapper: AppLogWrapper, @AppCoroutineScope appCoroutineScope: CoroutineScope, ) = ExPlat( platform = ExperimentStore.Platform.WOOCOMMERCE_ANDROID, - experiments = experiments, + experiments = setOf(), experimentStore = experimentStore, appLogWrapper = appLogWrapper, coroutineScope = appCoroutineScope, From f19a0c11ba25f4ad83688ec600ab9ca6f052eefb Mon Sep 17 00:00:00 2001 From: Renan Lukas <14964993+RenanLukas@users.noreply.github.com> Date: Wed, 27 Apr 2022 19:56:13 -0300 Subject: [PATCH 006/173] Fix checkstyle --- .../kotlin/com/woocommerce/android/di/ExperimentationModule.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt index f4dec2e4f03..b6b3a1a8318 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/ExperimentationModule.kt @@ -14,7 +14,6 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) @Module class ExperimentationModule { - @Provides @Singleton fun provideExPlat( From 961669d0ada0f004c17dd7bba23b78d37c40b3fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 05:52:15 +0000 Subject: [PATCH 007/173] Bump constraintlayout from 2.1.3 to 2.1.4 Bumps [constraintlayout](https://github.com/androidx/constraintlayout) from 2.1.3 to 2.1.4. - [Release notes](https://github.com/androidx/constraintlayout/releases) - [Commits](https://github.com/androidx/constraintlayout/compare/2.1.3...2.1.4) --- updated-dependencies: - dependency-name: androidx.constraintlayout:constraintlayout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- WooCommerce/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 778bbd7677c..c50ab8e4a02 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -183,13 +183,13 @@ dependencies { exclude group: "com.google.guava", module: "guava" } - implementation 'com.google.firebase:firebase-messaging-ktx:23.0.3' + implementation 'com.google.firebase:firebase-messaging-ktx:23.0.5' implementation 'com.google.android.gms:play-services-auth:20.2.0' // Support library implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.core:core-ktx:$coreKtxVersion" - implementation "androidx.constraintlayout:constraintlayout:2.1.3" + implementation "androidx.constraintlayout:constraintlayout:2.1.4" implementation "androidx.recyclerview:recyclerview:1.2.1" implementation "androidx.recyclerview:recyclerview-selection:1.1.0" implementation "androidx.appcompat:appcompat:$appCompatVersion" From aa54a29b12da87dcdb15eed91f1ff11e870c4c81 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Fri, 17 Jun 2022 13:25:20 +0530 Subject: [PATCH 008/173] replace AnalyticsTracks with AnalyticsTracksWrapper. This helps in writing tests to verify proper track events are being triggered with correct parameters. --- .../android/ui/mystore/MyStoreViewModel.kt | 12 ++++++---- .../ui/mystore/MyStoreViewModelTest.kt | 23 +++++++++++++++++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt index a11dcf709fa..cb89a0cb0c8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt @@ -10,6 +10,7 @@ import com.woocommerce.android.AppPrefsWrapper import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.analytics.AnalyticsTracker +import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.network.ConnectionChangeReceiver import com.woocommerce.android.network.ConnectionChangeReceiver.ConnectionChangeEvent import com.woocommerce.android.tools.NetworkStatus @@ -52,7 +53,8 @@ class MyStoreViewModel @Inject constructor( private val currencyFormatter: CurrencyFormatter, private val selectedSite: SelectedSite, private val appPrefsWrapper: AppPrefsWrapper, - private val usageTracksEventEmitter: MyStoreStatsUsageTracksEventEmitter + private val usageTracksEventEmitter: MyStoreStatsUsageTracksEventEmitter, + private val analyticsTrackerWrapper: AnalyticsTrackerWrapper, ) : ScopedViewModel(savedState) { private companion object { const val NUM_TOP_PERFORMERS = 5 @@ -123,7 +125,7 @@ class MyStoreViewModel @Inject constructor( fun onSwipeToRefresh() { usageTracksEventEmitter.interacted() - AnalyticsTracker.track(AnalyticsEvent.DASHBOARD_PULLED_TO_REFRESH) + analyticsTrackerWrapper.track(AnalyticsEvent.DASHBOARD_PULLED_TO_REFRESH) resetForceRefresh() refreshTrigger.tryEmit(Unit) } @@ -172,7 +174,7 @@ class MyStoreViewModel @Inject constructor( it.stats?.toStoreStatsUiModel(), selectedGranularity ) - AnalyticsTracker.track( + analyticsTrackerWrapper.track( AnalyticsEvent.DASHBOARD_MAIN_STATS_LOADED, mapOf(AnalyticsTracker.KEY_RANGE to selectedGranularity.name.lowercase()) ) @@ -234,7 +236,7 @@ class MyStoreViewModel @Inject constructor( it.topPerformers.toTopPerformersUiList(), granularity ) - AnalyticsTracker.track( + analyticsTrackerWrapper.track( AnalyticsEvent.DASHBOARD_TOP_PERFORMERS_LOADED, mapOf(AnalyticsTracker.KEY_RANGE to granularity.name.lowercase()) ) @@ -255,7 +257,7 @@ class MyStoreViewModel @Inject constructor( private fun onTopPerformerSelected(productId: Long) { triggerEvent(MyStoreEvent.OpenTopPerformer(productId)) - AnalyticsTracker.track(AnalyticsEvent.TOP_EARNER_PRODUCT_TAPPED) + analyticsTrackerWrapper.track(AnalyticsEvent.TOP_EARNER_PRODUCT_TAPPED) usageTracksEventEmitter.interacted() } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt index 603ea2727e9..8c4de813a61 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt @@ -2,6 +2,8 @@ package com.woocommerce.android.ui.mystore import androidx.lifecycle.SavedStateHandle import com.woocommerce.android.AppPrefsWrapper +import com.woocommerce.android.analytics.AnalyticsEvent +import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.tools.NetworkStatus import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.mystore.domain.GetStats @@ -15,7 +17,11 @@ import kotlinx.coroutines.flow.flow import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test -import org.mockito.kotlin.* +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity import org.wordpress.android.fluxc.store.WooCommerceStore @@ -33,6 +39,7 @@ class MyStoreViewModelTest : BaseUnitTest() { private val selectedSite: SelectedSite = mock() private val appPrefsWrapper: AppPrefsWrapper = mock() private val usageTracksEventEmitter: MyStoreStatsUsageTracksEventEmitter = mock() + private val analyticsTrackerWrapper: AnalyticsTrackerWrapper = mock() private lateinit var sut: MyStoreViewModel @@ -149,6 +156,17 @@ class MyStoreViewModelTest : BaseUnitTest() { ) } + @Test + fun `Given network connection, When on swipe to refresh, Then analytics is tracked`() = + testBlocking { + whenViewModelIsCreated() + givenNetworkConnectivity(connected = true) + + sut.onSwipeToRefresh() + + verify(analyticsTrackerWrapper).track(AnalyticsEvent.DASHBOARD_PULLED_TO_REFRESH) + } + @Test fun `Given success loading revenue, When stats granularity changes, Then UI is updated with revenue stats`() = testBlocking { @@ -341,7 +359,8 @@ class MyStoreViewModelTest : BaseUnitTest() { currencyFormatter, selectedSite, appPrefsWrapper, - usageTracksEventEmitter + usageTracksEventEmitter, + analyticsTrackerWrapper, ) } From 1d295742a6ecfa74ed4d7819e53f24d917db340c Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Fri, 17 Jun 2022 13:26:30 +0530 Subject: [PATCH 009/173] write test to verify that analytics is tracked when loading revenue stats successfully --- .../android/ui/mystore/MyStoreViewModelTest.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt index 8c4de813a61..a6ce20b6bc0 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt @@ -3,6 +3,7 @@ package com.woocommerce.android.ui.mystore import androidx.lifecycle.SavedStateHandle import com.woocommerce.android.AppPrefsWrapper import com.woocommerce.android.analytics.AnalyticsEvent +import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.tools.NetworkStatus import com.woocommerce.android.tools.SelectedSite @@ -184,6 +185,22 @@ class MyStoreViewModelTest : BaseUnitTest() { ) } + @Test + fun `Given success loading revenue, When stats granularity changes, Then analytics is tracked`() = + testBlocking { + whenViewModelIsCreated() + givenNetworkConnectivity(connected = true) + givenStatsLoadingResult(GetStats.LoadStatsResult.RevenueStatsSuccess(null)) + + sut.onStatsGranularityChanged(ANY_SELECTED_STATS_GRANULARITY) + + verify(analyticsTrackerWrapper).track( + AnalyticsEvent.DASHBOARD_MAIN_STATS_LOADED, + mapOf(AnalyticsTracker.KEY_RANGE to "weeks") + ) + } + + @Test fun `Given error loading revenue, When stats granularity changes, Then UI is updated with error`() = testBlocking { From 862f73ad13c576a64dbcd10e76453c4437b7713a Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Fri, 17 Jun 2022 13:27:43 +0530 Subject: [PATCH 010/173] write test to verify that analytics is tracked when top performers are loaded successfully --- .../ui/mystore/MyStoreViewModelTest.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt index a6ce20b6bc0..2352b2528b9 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt @@ -24,8 +24,11 @@ import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.model.WCProductModel +import org.wordpress.android.fluxc.model.leaderboards.WCTopPerformerProductModel import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity import org.wordpress.android.fluxc.store.WooCommerceStore +import java.math.BigDecimal import kotlin.test.assertTrue @ExperimentalCoroutinesApi @@ -312,6 +315,31 @@ class MyStoreViewModelTest : BaseUnitTest() { ) } + @Test + fun `Given top performers load success, When clicked, Then analytics is tracked`() = + testBlocking { + val topPerformerModel = mock { + on(it.currency).thenReturn("USD") + on(it.product).thenReturn(WCProductModel()) + } + whenever(currencyFormatter.formatCurrency(BigDecimal("0.0"), "USD")).thenReturn("1.00") + whenever(resourceProvider.getString(any(), any())).thenReturn("") + whenViewModelIsCreated() + givenNetworkConnectivity(connected = true) + givenToPerformersResult( + GetTopPerformers.TopPerformersResult.TopPerformersSuccess( + listOf( + topPerformerModel + ) + ) + ) + + sut.onStatsGranularityChanged(ANY_SELECTED_STATS_GRANULARITY) + (sut.topPerformersState.value as MyStoreViewModel.TopPerformersViewState.Content).topPerformers[0].onClick.invoke(1L) + + verify(analyticsTrackerWrapper).track(AnalyticsEvent.TOP_EARNER_PRODUCT_TAPPED) + } + @Test fun `Given top performers error, When stats granularity changes, Then UI is updated with top performers error`() = testBlocking { From b860f68c6635e1d7c3a056b7ee735cc84c09ead5 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Fri, 17 Jun 2022 13:28:23 +0530 Subject: [PATCH 011/173] write test to verify that analytics is tracked when top performers are loaded successfully --- .../android/ui/mystore/MyStoreViewModelTest.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt index 2352b2528b9..b0cc544eb00 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt @@ -340,6 +340,21 @@ class MyStoreViewModelTest : BaseUnitTest() { verify(analyticsTrackerWrapper).track(AnalyticsEvent.TOP_EARNER_PRODUCT_TAPPED) } + @Test + fun `Given top performers load success, When stats granularity changes, Then analytics is tracked`() = + testBlocking { + whenViewModelIsCreated() + givenNetworkConnectivity(connected = true) + givenToPerformersResult(GetTopPerformers.TopPerformersResult.TopPerformersSuccess(emptyList())) + + sut.onStatsGranularityChanged(ANY_SELECTED_STATS_GRANULARITY) + + verify(analyticsTrackerWrapper).track( + AnalyticsEvent.DASHBOARD_TOP_PERFORMERS_LOADED, + mapOf(AnalyticsTracker.KEY_RANGE to "weeks") + ) + } + @Test fun `Given top performers error, When stats granularity changes, Then UI is updated with top performers error`() = testBlocking { From 9b7070328972987cd940c6825a56acc0b35fdb11 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Fri, 17 Jun 2022 13:33:22 +0530 Subject: [PATCH 012/173] refactor tests for better readability --- .../android/ui/mystore/MyStoreViewModelTest.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt index b0cc544eb00..c72e6a01818 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt @@ -322,8 +322,8 @@ class MyStoreViewModelTest : BaseUnitTest() { on(it.currency).thenReturn("USD") on(it.product).thenReturn(WCProductModel()) } - whenever(currencyFormatter.formatCurrency(BigDecimal("0.0"), "USD")).thenReturn("1.00") - whenever(resourceProvider.getString(any(), any())).thenReturn("") + givenCurrencyFormatter(BigDecimal("0.0"), "USD") + givenResourceProvider() whenViewModelIsCreated() givenNetworkConnectivity(connected = true) givenToPerformersResult( @@ -335,7 +335,8 @@ class MyStoreViewModelTest : BaseUnitTest() { ) sut.onStatsGranularityChanged(ANY_SELECTED_STATS_GRANULARITY) - (sut.topPerformersState.value as MyStoreViewModel.TopPerformersViewState.Content).topPerformers[0].onClick.invoke(1L) + (sut.topPerformersState.value as MyStoreViewModel.TopPerformersViewState.Content) + .topPerformers[0].onClick.invoke(1L) verify(analyticsTrackerWrapper).track(AnalyticsEvent.TOP_EARNER_PRODUCT_TAPPED) } @@ -398,6 +399,14 @@ class MyStoreViewModelTest : BaseUnitTest() { whenever(getTopPerformers.invoke(any(), any(), any())).thenReturn(flow { emit(result) }) } + private fun givenCurrencyFormatter(amount: BigDecimal, currency: String) { + whenever(currencyFormatter.formatCurrency(amount, currency)).thenReturn("1.00") + } + + private fun givenResourceProvider() { + whenever(resourceProvider.getString(any(), any())).thenReturn("") + } + private fun givenStatsForGranularityCached(granularity: StatsGranularity) { sut.refreshStoreStats[granularity.ordinal] = false sut.refreshTopPerformerStats[granularity.ordinal] = false From efddb80c8ff74f65fe8b66db67784599a104e78b Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Fri, 17 Jun 2022 13:38:34 +0530 Subject: [PATCH 013/173] fix detekt errors --- .../android/ui/mystore/MyStoreViewModel.kt | 17 +++++++++++++++-- .../android/ui/mystore/MyStoreViewModelTest.kt | 1 - 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt index cb89a0cb0c8..a8debdcec61 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt @@ -16,7 +16,13 @@ import com.woocommerce.android.network.ConnectionChangeReceiver.ConnectionChange import com.woocommerce.android.tools.NetworkStatus import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.mystore.domain.GetStats -import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.* +import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.HasOrders +import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.IsJetPackCPEnabled +import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.PluginNotActive +import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.RevenueStatsError +import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.RevenueStatsSuccess +import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.VisitorsStatsError +import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.VisitorsStatsSuccess import com.woocommerce.android.ui.mystore.domain.GetTopPerformers import com.woocommerce.android.ui.mystore.domain.GetTopPerformers.TopPerformersResult.TopPerformersError import com.woocommerce.android.ui.mystore.domain.GetTopPerformers.TopPerformersResult.TopPerformersSuccess @@ -27,7 +33,14 @@ import com.woocommerce.android.viewmodel.ScopedViewModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Job import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.take +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.apache.commons.text.StringEscapeUtils import org.greenrobot.eventbus.Subscribe diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt index c72e6a01818..8ba67fbe5cf 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt @@ -203,7 +203,6 @@ class MyStoreViewModelTest : BaseUnitTest() { ) } - @Test fun `Given error loading revenue, When stats granularity changes, Then UI is updated with error`() = testBlocking { From ce7e247a86bc0c38900582f5ed9f38b24915f6d6 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Fri, 17 Jun 2022 13:42:42 +0530 Subject: [PATCH 014/173] replace AnalyticsTracker with AnalyticsTrackerWrapper --- .../com/woocommerce/android/ui/mystore/MyStoreViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt index a8debdcec61..31863b352db 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModel.kt @@ -205,7 +205,7 @@ class MyStoreViewModel @Inject constructor( _visitorStatsState.value = VisitorStatsViewState.JetpackCpConnected(BenefitsBannerUiModel(show = false)) appPrefsWrapper.recordJetpackBenefitsDismissal() - AnalyticsTracker.track( + analyticsTrackerWrapper.track( stat = AnalyticsEvent.FEATURE_JETPACK_BENEFITS_BANNER, properties = mapOf(AnalyticsTracker.KEY_JETPACK_BENEFITS_BANNER_ACTION to "dismissed") ) From b5654151a7c22e0e50d52319111c4f63d789f347 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 22 Jun 2022 11:55:05 +0530 Subject: [PATCH 015/173] Add shared preference for storing "isPluginExplicitlySelected" flag --- .../com/woocommerce/android/AppPrefsTest.kt | 36 +++++++++++++++++++ .../com/woocommerce/android/AppPrefs.kt | 33 +++++++++++++++++ .../woocommerce/android/AppPrefsWrapper.kt | 17 +++++++++ 3 files changed, 86 insertions(+) diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt index 09e44a6dd50..ffd6bf4c2d5 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/AppPrefsTest.kt @@ -482,4 +482,40 @@ class AppPrefsTest { ) ).isNull() } + + @Test + fun givenIsPluginExplicitlySelectedIsFalseThenReturnFalse() { + AppPrefs.setIsCardReaderPluginExplicitlySelectedFlag( + localSiteId = 0, + remoteSiteId = 0L, + selfHostedSiteId = 0L, + isPluginExplicitlySelected = false + ) + + assertThat( + AppPrefs.isCardReaderPluginExplicitlySelected( + localSiteId = 0, + remoteSiteId = 0L, + selfHostedSiteId = 0L, + ) + ).isFalse + } + + @Test + fun givenIsPluginExplicitlySelectedIsTrueThenReturnTrue() { + AppPrefs.setIsCardReaderPluginExplicitlySelectedFlag( + localSiteId = 0, + remoteSiteId = 0L, + selfHostedSiteId = 0L, + isPluginExplicitlySelected = true + ) + + assertThat( + AppPrefs.isCardReaderPluginExplicitlySelected( + localSiteId = 0, + remoteSiteId = 0L, + selfHostedSiteId = 0L, + ) + ).isTrue + } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt index f01b1c4f099..265884e1c8e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt @@ -9,6 +9,7 @@ import android.content.SharedPreferences.Editor import androidx.preference.PreferenceManager import com.woocommerce.android.AppPrefs.CardReaderOnboardingStatus.CARD_READER_ONBOARDING_COMPLETED import com.woocommerce.android.AppPrefs.CardReaderOnboardingStatus.CARD_READER_ONBOARDING_NOT_COMPLETED +import com.woocommerce.android.AppPrefs.DeletablePrefKey.CARD_READER_IS_PLUGIN_EXPLICITLY_SELECTED import com.woocommerce.android.AppPrefs.DeletablePrefKey.CARD_READER_ONBOARDING_COMPLETED_STATUS_V2 import com.woocommerce.android.AppPrefs.DeletablePrefKey.CARD_READER_PREFERRED_PLUGIN import com.woocommerce.android.AppPrefs.DeletablePrefKey.CARD_READER_PREFERRED_PLUGIN_VERSION @@ -71,6 +72,7 @@ object AppPrefs { USER_EMAIL, RECEIPT_PREFIX, CARD_READER_ONBOARDING_COMPLETED_STATUS_V2, + CARD_READER_IS_PLUGIN_EXPLICITLY_SELECTED, CARD_READER_PREFERRED_PLUGIN, CARD_READER_PREFERRED_PLUGIN_VERSION, CARD_READER_STATEMENT_DESCRIPTOR, @@ -475,6 +477,19 @@ object AppPrefs { fun isCardReaderWelcomeDialogShown() = getBoolean(UndeletablePrefKey.CARD_READER_WELCOME_SHOWN, false) + fun isCardReaderPluginExplicitlySelected( + localSiteId: Int, + remoteSiteId: Long, + selfHostedSiteId: Long + ) = getBoolean( + getIsPluginExplicitlySelectedKey( + localSiteId, + remoteSiteId, + selfHostedSiteId + ), + false + ) + fun getCardReaderPreferredPlugin( localSiteId: Int, remoteSiteId: Long, @@ -534,12 +549,30 @@ object AppPrefs { } } + fun setIsCardReaderPluginExplicitlySelectedFlag( + localSiteId: Int, + remoteSiteId: Long, + selfHostedSiteId: Long, + isPluginExplicitlySelected: Boolean + ) { + setBoolean( + getIsPluginExplicitlySelectedKey(localSiteId, remoteSiteId, selfHostedSiteId), + isPluginExplicitlySelected + ) + } + private fun getCardReaderOnboardingStatusKey( localSiteId: Int, remoteSiteId: Long, selfHostedSiteId: Long ) = PrefKeyString("$CARD_READER_ONBOARDING_COMPLETED_STATUS_V2:$localSiteId:$remoteSiteId:$selfHostedSiteId") + private fun getIsPluginExplicitlySelectedKey( + localSiteId: Int, + remoteSiteId: Long, + selfHostedSiteId: Long + ) = PrefKeyString("$CARD_READER_IS_PLUGIN_EXPLICITLY_SELECTED:$localSiteId:$remoteSiteId:$selfHostedSiteId") + private fun getCardReaderPreferredPluginKey( localSiteId: Int, remoteSiteId: Long, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefsWrapper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefsWrapper.kt index abd708f6e22..b8157f6856f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefsWrapper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefsWrapper.kt @@ -27,6 +27,9 @@ class AppPrefsWrapper @Inject constructor() { fun isCardReaderWelcomeDialogShown() = AppPrefs.isCardReaderWelcomeDialogShown() + fun isCardReaderPluginExplicitlySelected(localSiteId: Int, remoteSiteId: Long, selfHostedSiteId: Long) = + AppPrefs.isCardReaderPluginExplicitlySelected(localSiteId, remoteSiteId, selfHostedSiteId) + fun getCardReaderPreferredPlugin( localSiteId: Int, remoteSiteId: Long, @@ -59,6 +62,20 @@ class AppPrefsWrapper @Inject constructor() { ) } + fun setIsCardReaderPluginExplicitlySelectedFlag( + localSiteId: Int, + remoteSiteId: Long, + selfHostedSiteId: Long, + isPluginExplicitlySelected: Boolean = false + ) { + AppPrefs.setIsCardReaderPluginExplicitlySelectedFlag( + localSiteId, + remoteSiteId, + selfHostedSiteId, + isPluginExplicitlySelected + ) + } + fun setCardReaderStatementDescriptor( statementDescriptor: String?, localSiteId: Int, From 83152aeacb017b3cb672597b01c95233503ba2cb Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 22 Jun 2022 12:12:28 +0530 Subject: [PATCH 016/173] Clear plugin explicitly selected flag when the onboarding fails for any reason --- .../onboarding/CardReaderOnboardingChecker.kt | 15 ++++++++++++++- .../CardReaderOnboardingCheckerTest.kt | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index 22b6f117781..9ac479d5f11 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -82,7 +82,10 @@ class CardReaderOnboardingChecker @Inject constructor( val (status, version) = when (it) { is OnboardingCompleted -> CARD_READER_ONBOARDING_COMPLETED to it.version is StripeAccountPendingRequirement -> CARD_READER_ONBOARDING_PENDING to it.version - else -> CARD_READER_ONBOARDING_NOT_COMPLETED to null + else -> { + updatePluginExplicitlySelectedFlag(false) + CARD_READER_ONBOARDING_NOT_COMPLETED to null + } } updateSharedPreferences( status, @@ -283,6 +286,16 @@ class CardReaderOnboardingChecker @Inject constructor( PersistentOnboardingData(status, preferredPlugin, version), ) } + + private fun updatePluginExplicitlySelectedFlag(isPluginExplicitlySelected: Boolean) { + val site = selectedSite.get() + appPrefsWrapper.setIsCardReaderPluginExplicitlySelectedFlag( + localSiteId = site.id, + remoteSiteId = site.siteId, + selfHostedSiteId = site.selfHostedSiteId, + isPluginExplicitlySelected = isPluginExplicitlySelected + ) + } } data class PersistentOnboardingData( diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index 7c1fe4ee3a9..6f8e3856a25 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -1115,6 +1115,24 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { assertThat((result as PreferredPluginResult.Success).type).isEqualTo(PluginType.WOOCOMMERCE_PAYMENTS) } + //region - Multiple Plugins detected tests + + @Test + fun `when onboarding not completed, then clear pluginExplicitlySelected flag`() = testBlocking { + whenever(wooStore.getStoreCountryCode(site)).thenReturn("unsupported country abc") + + checker.getOnboardingState() + + val captor = argumentCaptor() + verify(appPrefsWrapper).setIsCardReaderPluginExplicitlySelectedFlag( + anyInt(), + anyLong(), + anyLong(), + captor.capture(), + ) + assertThat(captor.firstValue).isFalse() + } + private fun buildPaymentAccountResult( status: WCPaymentAccountResult.WCPaymentAccountStatus = WCPaymentAccountResult.WCPaymentAccountStatus.COMPLETE, hasPendingRequirements: Boolean = false, From 6c75d2dd77adfaf645ad83f9ae308b6f19fb8200 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 22 Jun 2022 12:13:26 +0530 Subject: [PATCH 017/173] Do not clear plugin explicitly selected flag when the onboarding fails because of pending requirements --- .../CardReaderOnboardingCheckerTest.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index 6f8e3856a25..72aa7b96e79 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -21,6 +21,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test +import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyLong import org.mockito.kotlin.any @@ -1133,6 +1134,26 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { assertThat(captor.firstValue).isFalse() } + @Test + fun `when onboarding has pending requirements, then do not clear pluginExplicitlySelected flag`() = testBlocking { + whenever(wcInPersonPaymentsStore.loadAccount(any(), any())).thenReturn( + buildPaymentAccountResult( + WCPaymentAccountResult.WCPaymentAccountStatus.RESTRICTED, + hasPendingRequirements = true, + hadOverdueRequirements = false + ) + ) + + checker.getOnboardingState() + + verify(appPrefsWrapper, never()).setIsCardReaderPluginExplicitlySelectedFlag( + anyInt(), + anyLong(), + anyLong(), + anyBoolean(), + ) + } + private fun buildPaymentAccountResult( status: WCPaymentAccountResult.WCPaymentAccountStatus = WCPaymentAccountResult.WCPaymentAccountStatus.COMPLETE, hasPendingRequirements: Boolean = false, From f4082e6f2a1d334949b2d1b4547840dc0da0e947 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 22 Jun 2022 12:15:29 +0530 Subject: [PATCH 018/173] Do not clear plugin explicitly selected flag when the onboarding completes successfully --- .../CardReaderOnboardingCheckerTest.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index 72aa7b96e79..44b47bebf46 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -1154,6 +1154,24 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { ) } + @Test + fun `when onboarding completed, then do not clear pluginExplicitlySelected flag`() = testBlocking { + whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(null) + + checker.getOnboardingState() + + verify(appPrefsWrapper, never()).setIsCardReaderPluginExplicitlySelectedFlag( + anyInt(), + anyLong(), + anyLong(), + anyBoolean(), + ) + } + private fun buildPaymentAccountResult( status: WCPaymentAccountResult.WCPaymentAccountStatus = WCPaymentAccountResult.WCPaymentAccountStatus.COMPLETE, hasPendingRequirements: Boolean = false, From 1c5639c07fdfdc512b0cb7bda7bdeeeb90f61de1 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 22 Jun 2022 12:24:46 +0530 Subject: [PATCH 019/173] Add IPP payment gateway feature flag to CardReaderOnboardingChecker.kt. Do not clear plugin explicitly selected flag when the IPP payment gateway feature flag is disabled. --- .../onboarding/CardReaderOnboardingChecker.kt | 6 +++++- .../CardReaderOnboardingCheckerTest.kt | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index 9ac479d5f11..9c978c1ec29 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -15,6 +15,7 @@ import com.woocommerce.android.tools.NetworkStatus import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.cardreader.CardReaderCountryConfigProvider import com.woocommerce.android.ui.cardreader.CardReaderTrackingInfoKeeper +import com.woocommerce.android.ui.cardreader.IppSelectPaymentGateway import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.GenericError import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.NoConnectionError import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.OnboardingCompleted @@ -73,6 +74,7 @@ class CardReaderOnboardingChecker @Inject constructor( private val networkStatus: NetworkStatus, private val cardReaderTrackingInfoKeeper: CardReaderTrackingInfoKeeper, private val cardReaderCountryConfigProvider: CardReaderCountryConfigProvider, + private val ippSelectPaymentGateway: IppSelectPaymentGateway, ) { suspend fun getOnboardingState(): CardReaderOnboardingState { if (!networkStatus.isConnected()) return NoConnectionError @@ -83,7 +85,9 @@ class CardReaderOnboardingChecker @Inject constructor( is OnboardingCompleted -> CARD_READER_ONBOARDING_COMPLETED to it.version is StripeAccountPendingRequirement -> CARD_READER_ONBOARDING_PENDING to it.version else -> { - updatePluginExplicitlySelectedFlag(false) + if (ippSelectPaymentGateway.isEnabled()) { + updatePluginExplicitlySelectedFlag(false) + } CARD_READER_ONBOARDING_NOT_COMPLETED to null } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index 44b47bebf46..35e76234320 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -14,6 +14,7 @@ import com.woocommerce.android.tools.NetworkStatus import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.cardreader.CardReaderCountryConfigProvider import com.woocommerce.android.ui.cardreader.CardReaderTrackingInfoKeeper +import com.woocommerce.android.ui.cardreader.IppSelectPaymentGateway import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.PluginIsNotSupportedInTheCountry import com.woocommerce.android.ui.cardreader.onboarding.PluginType.STRIPE_EXTENSION_GATEWAY import com.woocommerce.android.viewmodel.BaseUnitTest @@ -55,6 +56,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { private val appPrefsWrapper: AppPrefsWrapper = mock() private val cardReaderTrackingInfoKeeper: CardReaderTrackingInfoKeeper = mock() private val cardReaderCountryConfigProvider: CardReaderCountryConfigProvider = mock() + private val ippSelectPaymentGateway: IppSelectPaymentGateway = mock() private val site = SiteModel() @@ -74,6 +76,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { networkStatus, cardReaderTrackingInfoKeeper, cardReaderCountryConfigProvider, + ippSelectPaymentGateway, ) whenever(networkStatus.isConnected()).thenReturn(true) whenever(selectedSite.get()).thenReturn(site) @@ -91,6 +94,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { .thenReturn(CardReaderConfigForUSA) whenever(cardReaderCountryConfigProvider.provideCountryConfigFor("CA")) .thenReturn(CardReaderConfigForCanada) + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(false) } @Test @@ -1120,6 +1124,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { @Test fun `when onboarding not completed, then clear pluginExplicitlySelected flag`() = testBlocking { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) whenever(wooStore.getStoreCountryCode(site)).thenReturn("unsupported country abc") checker.getOnboardingState() @@ -1134,6 +1139,21 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { assertThat(captor.firstValue).isFalse() } + @Test + fun `given feature flag is disabled, when onboarding not completed, then do not clear flag`() = testBlocking { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(false) + whenever(wooStore.getStoreCountryCode(site)).thenReturn("unsupported country abc") + + checker.getOnboardingState() + + verify(appPrefsWrapper, never()).setIsCardReaderPluginExplicitlySelectedFlag( + anyInt(), + anyLong(), + anyLong(), + anyBoolean(), + ) + } + @Test fun `when onboarding has pending requirements, then do not clear pluginExplicitlySelected flag`() = testBlocking { whenever(wcInPersonPaymentsStore.loadAccount(any(), any())).thenReturn( From 1bcc29484e26d36e14c08a6cd5783dd68100fc76 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 22 Jun 2022 12:42:28 +0530 Subject: [PATCH 020/173] Add ChoosePaymentProvider state. Return ChoosePaymentProvider state when both wcpay and stripe plugins are installed and activated and payment gateway feature flag is enabled --- .../ui/cardreader/CardReaderTracker.kt | 2 ++ .../onboarding/CardReaderOnboardingChecker.kt | 21 +++++++++++++++++++ .../CardReaderOnboardingViewModel.kt | 2 ++ .../CardReaderOnboardingCheckerTest.kt | 15 +++++++++++++ 4 files changed, 40 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt index b508ac7f4b3..befcda8da64 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt @@ -140,6 +140,8 @@ class CardReaderTracker @Inject constructor( is CardReaderOnboardingState.GenericError -> "generic_error" is CardReaderOnboardingState.NoConnectionError -> "no_connection_error" is CardReaderOnboardingState.WcpayAndStripeActivated -> "wcpay_and_stripe_installed_and_activated" + CardReaderOnboardingState.ChoosePaymentProvider -> + "wcpay_and_stripe_installed_and_activated_choose_payment_provider" } private fun getPluginNameReasonPrefix(pluginType: PluginType): String { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index 9c978c1ec29..67f97f6700a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -16,6 +16,7 @@ import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.cardreader.CardReaderCountryConfigProvider import com.woocommerce.android.ui.cardreader.CardReaderTrackingInfoKeeper import com.woocommerce.android.ui.cardreader.IppSelectPaymentGateway +import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.ChoosePaymentProvider import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.GenericError import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.NoConnectionError import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.OnboardingCompleted @@ -128,6 +129,10 @@ class CardReaderOnboardingChecker @Inject constructor( return PluginIsNotSupportedInTheCountry(pluginType, countryCode!!) } } + val isPluginExplicitlySelected = isPluginExplicitlySelected() + if (ippSelectPaymentGateway.isEnabled() && !isPluginExplicitlySelected) { + return ChoosePaymentProvider + } return WcpayAndStripeActivated } @@ -300,6 +305,15 @@ class CardReaderOnboardingChecker @Inject constructor( isPluginExplicitlySelected = isPluginExplicitlySelected ) } + + private fun isPluginExplicitlySelected(): Boolean { + val site = selectedSite.get() + return appPrefsWrapper.isCardReaderPluginExplicitlySelected( + localSiteId = site.id, + remoteSiteId = site.siteId, + selfHostedSiteId = site.selfHostedSiteId, + ) + } } data class PersistentOnboardingData( @@ -385,6 +399,13 @@ sealed class CardReaderOnboardingState( @Parcelize object WcpayAndStripeActivated : CardReaderOnboardingState() + /** + * Both plugins are installed and activated on the site. Merchant needs to choose their preferred payment + * provider in this state. + */ + @Parcelize + object ChoosePaymentProvider : CardReaderOnboardingState() + /** * This is a bit special case: WCPay is set to "dev mode" but the connected Stripe account is in live mode. * Connecting to a reader or accepting payments is not supported in this state. diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index f5eaae868de..26239de45aa 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -15,6 +15,7 @@ import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.cardreader.CardReaderTracker import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingParams.Check import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingParams.Failed +import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.ChoosePaymentProvider import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.GenericError import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.NoConnectionError import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.OnboardingCompleted @@ -199,6 +200,7 @@ class CardReaderOnboardingViewModel @Inject constructor( ::onLearnMoreClicked ) WcpayAndStripeActivated -> updateUiWithWcPayAndStripeActivated() + ChoosePaymentProvider -> TODO() }.exhaustive } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index 35e76234320..3c8b275da7c 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -1192,6 +1192,21 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { ) } + @Test + fun `given feature flag is enabled, when wcpay and stripe activated, then ChoosePaymentProvider returned`() = + testBlocking { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + + val result = checker.getOnboardingState() + + assertThat(result).isEqualTo(CardReaderOnboardingState.ChoosePaymentProvider) + } + private fun buildPaymentAccountResult( status: WCPaymentAccountResult.WCPaymentAccountStatus = WCPaymentAccountResult.WCPaymentAccountStatus.COMPLETE, hasPendingRequirements: Boolean = false, From aa8fbe59151be3c67dddb0721a55d1911d3057ad Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 22 Jun 2022 15:12:53 +0530 Subject: [PATCH 021/173] refactor code --- .../ui/cardreader/onboarding/CardReaderOnboardingChecker.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index 67f97f6700a..035e2c75620 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -129,8 +129,7 @@ class CardReaderOnboardingChecker @Inject constructor( return PluginIsNotSupportedInTheCountry(pluginType, countryCode!!) } } - val isPluginExplicitlySelected = isPluginExplicitlySelected() - if (ippSelectPaymentGateway.isEnabled() && !isPluginExplicitlySelected) { + if (ippSelectPaymentGateway.isEnabled() && !isPluginExplicitlySelected()) { return ChoosePaymentProvider } return WcpayAndStripeActivated From f775e3682b33de16f6582bb950b5a59328f0b56f Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 22 Jun 2022 15:47:10 +0530 Subject: [PATCH 022/173] end region in CardReaderOnboardingCheckerTest.kt --- .../ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index 3c8b275da7c..326a41c0c51 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -1207,6 +1207,8 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { assertThat(result).isEqualTo(CardReaderOnboardingState.ChoosePaymentProvider) } + //endregion + private fun buildPaymentAccountResult( status: WCPaymentAccountResult.WCPaymentAccountStatus = WCPaymentAccountResult.WCPaymentAccountStatus.COMPLETE, hasPendingRequirements: Boolean = false, From 7922340cfb7cb58a9839210a1e7114f12d23f3db Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 22 Jun 2022 15:49:47 +0530 Subject: [PATCH 023/173] rename ChoosePaymentProvider to ChoosePaymentGatewayProvider for better readability --- .../woocommerce/android/ui/cardreader/CardReaderTracker.kt | 2 +- .../ui/cardreader/onboarding/CardReaderOnboardingChecker.kt | 6 +++--- .../cardreader/onboarding/CardReaderOnboardingViewModel.kt | 4 ++-- .../onboarding/CardReaderOnboardingCheckerTest.kt | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt index befcda8da64..5678910719f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt @@ -140,7 +140,7 @@ class CardReaderTracker @Inject constructor( is CardReaderOnboardingState.GenericError -> "generic_error" is CardReaderOnboardingState.NoConnectionError -> "no_connection_error" is CardReaderOnboardingState.WcpayAndStripeActivated -> "wcpay_and_stripe_installed_and_activated" - CardReaderOnboardingState.ChoosePaymentProvider -> + CardReaderOnboardingState.ChoosePaymentGatewayProvider -> "wcpay_and_stripe_installed_and_activated_choose_payment_provider" } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index 035e2c75620..da78d6d31d2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -16,7 +16,7 @@ import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.cardreader.CardReaderCountryConfigProvider import com.woocommerce.android.ui.cardreader.CardReaderTrackingInfoKeeper import com.woocommerce.android.ui.cardreader.IppSelectPaymentGateway -import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.ChoosePaymentProvider +import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.ChoosePaymentGatewayProvider import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.GenericError import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.NoConnectionError import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.OnboardingCompleted @@ -130,7 +130,7 @@ class CardReaderOnboardingChecker @Inject constructor( } } if (ippSelectPaymentGateway.isEnabled() && !isPluginExplicitlySelected()) { - return ChoosePaymentProvider + return ChoosePaymentGatewayProvider } return WcpayAndStripeActivated } @@ -403,7 +403,7 @@ sealed class CardReaderOnboardingState( * provider in this state. */ @Parcelize - object ChoosePaymentProvider : CardReaderOnboardingState() + object ChoosePaymentGatewayProvider : CardReaderOnboardingState() /** * This is a bit special case: WCPay is set to "dev mode" but the connected Stripe account is in live mode. diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index 26239de45aa..b55711096c8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -15,7 +15,7 @@ import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.cardreader.CardReaderTracker import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingParams.Check import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingParams.Failed -import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.ChoosePaymentProvider +import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.ChoosePaymentGatewayProvider import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.GenericError import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.NoConnectionError import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.OnboardingCompleted @@ -200,7 +200,7 @@ class CardReaderOnboardingViewModel @Inject constructor( ::onLearnMoreClicked ) WcpayAndStripeActivated -> updateUiWithWcPayAndStripeActivated() - ChoosePaymentProvider -> TODO() + ChoosePaymentGatewayProvider -> TODO() }.exhaustive } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index 326a41c0c51..49c55d7f5ad 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -1204,7 +1204,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { val result = checker.getOnboardingState() - assertThat(result).isEqualTo(CardReaderOnboardingState.ChoosePaymentProvider) + assertThat(result).isEqualTo(CardReaderOnboardingState.ChoosePaymentGatewayProvider) } //endregion From 54f8dad191db81cfaaba9fc1a3a0ec81f341f053 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Thu, 23 Jun 2022 16:05:29 +0530 Subject: [PATCH 024/173] Provide PluginType as a dependency. --- .../kotlin/com/woocommerce/android/di/CardReaderModule.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt index e421bd2bc62..4319668a162 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt @@ -8,6 +8,7 @@ import com.woocommerce.android.cardreader.CardReaderStore.CapturePaymentResponse import com.woocommerce.android.cardreader.LogWrapper import com.woocommerce.android.cardreader.internal.config.CardReaderConfigFactory import com.woocommerce.android.tools.SelectedSite +import com.woocommerce.android.ui.cardreader.onboarding.PluginType import com.woocommerce.android.ui.cardreader.onboarding.toInPersonPaymentsPluginType import com.woocommerce.android.util.CapturePaymentResponseMapper import com.woocommerce.android.util.WooLog @@ -84,4 +85,7 @@ class CardReaderModule { @Provides @Reusable fun provideCardReaderConfigFactory() = CardReaderConfigFactory() + + @Provides + fun providePluginType() = PluginType.valueOf("") } From 69e9bd10301a5e437d6d632a3e5b493bd2cce03e Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Thu, 23 Jun 2022 16:05:49 +0530 Subject: [PATCH 025/173] refactoring CardReaderOnboardingChecker.kt --- .../onboarding/CardReaderOnboardingChecker.kt | 58 +++++++++- .../CardReaderOnboardingCheckerTest.kt | 109 ++++++++++++++++-- 2 files changed, 151 insertions(+), 16 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index da78d6d31d2..f92c628258e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -76,6 +76,7 @@ class CardReaderOnboardingChecker @Inject constructor( private val cardReaderTrackingInfoKeeper: CardReaderTrackingInfoKeeper, private val cardReaderCountryConfigProvider: CardReaderCountryConfigProvider, private val ippSelectPaymentGateway: IppSelectPaymentGateway, + private val userSelectedPlugin: PluginType? = null, ) { suspend fun getOnboardingState(): CardReaderOnboardingState { if (!networkStatus.isConnected()) return NoConnectionError @@ -129,13 +130,18 @@ class CardReaderOnboardingChecker @Inject constructor( return PluginIsNotSupportedInTheCountry(pluginType, countryCode!!) } } - if (ippSelectPaymentGateway.isEnabled() && !isPluginExplicitlySelected()) { - return ChoosePaymentGatewayProvider + if (ippSelectPaymentGateway.isEnabled()) { + if (hasUserAlreadySelectedThePlugin()) { + updatePluginExplicitlySelectedFlag(true) + } else { + return getMultipleGatewayProviderState() + } + } else { + return WcpayAndStripeActivated } - return WcpayAndStripeActivated } - val preferredPlugin = getPreferredPlugin(stripePluginInfo, wcPayPluginInfo) + val preferredPlugin = getUserSelectedPluginOrActivatedPlugin(wcPayPluginInfo, stripePluginInfo) if (!isPluginInstalled(preferredPlugin)) when (preferredPlugin.type) { WOOCOMMERCE_PAYMENTS -> return WcpayNotInstalled @@ -194,6 +200,44 @@ class CardReaderOnboardingChecker @Inject constructor( ) } + private fun hasUserAlreadySelectedThePlugin(): Boolean { + if (userSelectedPlugin != null) { + return true + } + return false + } + + private fun getMultipleGatewayProviderState(): CardReaderOnboardingState { + return when { + !isPluginExplicitlySelected() && + !hasUserAlreadySelectedThePlugin() -> ChoosePaymentGatewayProvider + else -> throw IllegalStateException( + "Developer error: plugin selected flag is true even when the user hasn't selected the plugin" + ) + } + } + + private fun getUserSelectedPluginOrActivatedPlugin( + wcPayPluginInfo: SitePluginModel?, + stripePluginInfo: SitePluginModel?, + ): PluginWrapper { + return when { + hasUserAlreadySelectedThePlugin() -> { + getUserSelectedPluginWrapper(wcPayPluginInfo, stripePluginInfo) + } + else -> { + getPreferredPlugin(stripePluginInfo, wcPayPluginInfo) + } + } + } + + private fun getUserSelectedPluginWrapper( + wcPayPluginInfo: SitePluginModel?, + stripePluginInfo: SitePluginModel?, + ): PluginWrapper { + return PluginWrapper(userSelectedPlugin!!, userSelectedPlugin.getPluginInfo(wcPayPluginInfo, stripePluginInfo)) + } + private fun isPluginSupportedInCountry( pluginType: PluginType, cardReaderConfig: CardReaderConfigForSupportedCountry @@ -336,6 +380,12 @@ enum class PluginType { STRIPE_EXTENSION_GATEWAY } +fun PluginType.getPluginInfo(wcPayPluginInfo: SitePluginModel?, stripePluginInfo: SitePluginModel?) = + when (this) { + WOOCOMMERCE_PAYMENTS -> wcPayPluginInfo + STRIPE_EXTENSION_GATEWAY -> stripePluginInfo + } + private fun PluginType.toSupportedExtensionType() = when (this) { WOOCOMMERCE_PAYMENTS -> SupportedExtensionType.WC_PAY diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index 49c55d7f5ad..0d5eceb7a73 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -67,17 +67,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { @Before fun setUp() = testBlocking { - checker = CardReaderOnboardingChecker( - selectedSite, - appPrefsWrapper, - wooStore, - wcInPersonPaymentsStore, - coroutinesTestRule.testDispatchers, - networkStatus, - cardReaderTrackingInfoKeeper, - cardReaderCountryConfigProvider, - ippSelectPaymentGateway, - ) + checker = initOnboardingChecker() whenever(networkStatus.isConnected()).thenReturn(true) whenever(selectedSite.get()).thenReturn(site) whenever(wooStore.getStoreCountryCode(site)).thenReturn(countryCode) @@ -97,6 +87,21 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(false) } + private fun initOnboardingChecker(pluginType: PluginType? = null): CardReaderOnboardingChecker { + return CardReaderOnboardingChecker( + selectedSite, + appPrefsWrapper, + wooStore, + wcInPersonPaymentsStore, + coroutinesTestRule.testDispatchers, + networkStatus, + cardReaderTrackingInfoKeeper, + cardReaderCountryConfigProvider, + ippSelectPaymentGateway, + pluginType + ) + } + @Test fun `when not connected to network, then NO_CONNECTION returned`() = testBlocking { whenever(networkStatus.isConnected()).thenReturn(false) @@ -483,7 +488,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { val result = checker.getOnboardingState() assertThat((result as PluginIsNotSupportedInTheCountry).preferredPlugin).isEqualTo( - PluginType.STRIPE_EXTENSION_GATEWAY + STRIPE_EXTENSION_GATEWAY ) } @@ -1207,6 +1212,86 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { assertThat(result).isEqualTo(CardReaderOnboardingState.ChoosePaymentGatewayProvider) } + @Test + fun `given no plugin selected & selected flag false,when multiple plugins, then ChoosePaymentProvider returned `() = + testBlocking { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + whenever( + appPrefsWrapper.isCardReaderPluginExplicitlySelected( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(false) + + val result = checker.getOnboardingState() + + assertThat(result).isEqualTo(CardReaderOnboardingState.ChoosePaymentGatewayProvider) + } + + @Test(expected = IllegalStateException::class) + fun `given no plugin selected and selected flag true, when multiple plugins, then throw exception`() = + testBlocking { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + whenever( + appPrefsWrapper.isCardReaderPluginExplicitlySelected( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(true) + + checker.getOnboardingState() + } + + @Test + fun `given plugin selected, when multiple plugins, then set plugin flag`() = + testBlocking { + val checker = initOnboardingChecker(PluginType.WOOCOMMERCE_PAYMENTS) + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + + checker.getOnboardingState() + + verify(appPrefsWrapper).setIsCardReaderPluginExplicitlySelectedFlag( + anyInt(), + anyLong(), + anyLong(), + eq(true) + ) + } + + @Test + fun `when onboarding fails, then clear isPluginExplicitlySelected flag`() = + testBlocking { + val checker = initOnboardingChecker(PluginType.WOOCOMMERCE_PAYMENTS) + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.getStoreCountryCode(site)).thenReturn("unsupported country abc") + + checker.getOnboardingState() + + verify(appPrefsWrapper).setIsCardReaderPluginExplicitlySelectedFlag( + anyInt(), + anyLong(), + anyLong(), + eq(false) + ) + } + //endregion private fun buildPaymentAccountResult( From d189300038c365be4c0416647faa2fd83aa1054d Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Thu, 23 Jun 2022 16:08:24 +0530 Subject: [PATCH 026/173] fix detekt errors --- .../ui/cardreader/onboarding/CardReaderOnboardingChecker.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index f92c628258e..a63d4f93698 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -209,8 +209,7 @@ class CardReaderOnboardingChecker @Inject constructor( private fun getMultipleGatewayProviderState(): CardReaderOnboardingState { return when { - !isPluginExplicitlySelected() && - !hasUserAlreadySelectedThePlugin() -> ChoosePaymentGatewayProvider + !isPluginExplicitlySelected() && !hasUserAlreadySelectedThePlugin() -> ChoosePaymentGatewayProvider else -> throw IllegalStateException( "Developer error: plugin selected flag is true even when the user hasn't selected the plugin" ) From b23c574746b4f39d6716f55ed1ff77889c6d7de5 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 23 Jun 2022 16:50:35 +0100 Subject: [PATCH 027/173] Replace the cancel button with a cross icon --- .../android/ui/shipping/InstallWCShippingFlow.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index a098b1b7fae..ceab1d257b6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -22,9 +22,11 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.Icon +import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.outlined.Info import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -43,7 +45,6 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.woocommerce.android.R import com.woocommerce.android.ui.compose.component.WCColoredButton -import com.woocommerce.android.ui.compose.component.WCTextButton import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.InstallationState import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.InstallationState.PreInstallation @@ -79,6 +80,12 @@ private fun PreInstallationContent(viewState: PreInstallation, transition: Trans vertical = dimensionResource(id = R.dimen.major_150) ) ) { + IconButton(onClick = viewState.onCancelClick) { + Icon( + imageVector = Icons.Default.Clear, + contentDescription = stringResource(id = R.string.cancel) + ) + } Column( verticalArrangement = Arrangement.Center, modifier = Modifier @@ -86,9 +93,6 @@ private fun PreInstallationContent(viewState: PreInstallation, transition: Trans .verticalScroll(rememberScrollState()) .offset(y = -offset.dp) ) { - WCTextButton(onClick = viewState.onCancelClick) { - Text(text = stringResource(id = R.string.cancel)) - } SpacerWithMinHeight(1f, dimensionResource(id = R.dimen.major_100)) Box( modifier = Modifier From 706788c2201d7390b5c6291296bcb14c8a6608da Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 23 Jun 2022 20:02:34 +0100 Subject: [PATCH 028/173] Add an installation state and refactor how animations work --- .../ui/shipping/InstallWCShippingFlow.kt | 201 ++++++++++++------ .../shipping/InstallWCShippingOnboarding.kt | 43 ++-- .../ui/shipping/InstallWCShippingScreen.kt | 30 ++- .../ui/shipping/InstallWCShippingViewModel.kt | 28 ++- 4 files changed, 196 insertions(+), 106 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index ceab1d257b6..e7d11d1aea6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -1,9 +1,24 @@ +@file:OptIn(ExperimentalAnimationApi::class) + package com.woocommerce.android.ui.shipping +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.AnimatedVisibilityScope +import androidx.compose.animation.Crossfade +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.EnterTransition.Companion +import androidx.compose.animation.ExitTransition +import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.animation.core.ExperimentalTransitionApi import androidx.compose.animation.core.Transition import androidx.compose.animation.core.animateInt +import androidx.compose.animation.core.createChildTransition import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInVertically import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -35,6 +50,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource @@ -44,34 +60,26 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.woocommerce.android.R +import com.woocommerce.android.R.string import com.woocommerce.android.ui.compose.component.WCColoredButton import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground +import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.InstallationState +import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.InstallationState.InstallationOngoing import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.InstallationState.PreInstallation +@OptIn(ExperimentalTransitionApi::class) @Composable -fun InstallWCShippingFlow(viewState: InstallationState, transition: Transition? = null) { +fun AnimatedVisibilityScope.InstallWCShippingFlow(viewState: InstallationState) { when (viewState) { - is PreInstallation -> PreInstallationContent(viewState, transition) + is PreInstallation -> PreInstallationContent(viewState) + is InstallationOngoing -> TODO() } } @Composable -private fun PreInstallationContent(viewState: PreInstallation, transition: Transition? = null) { - val offset by transition?.animateInt( - transitionSpec = { - tween( - durationMillis = 500, - delayMillis = 500, - // Ensure a bit of elasticity at the end of the animation - easing = CubicBezierEasing(0.7f, 0.6f, 0.74f, 1.3f) - ) - }, - label = "offset" - ) { - if (it) 0 else 120 - } ?: remember { mutableStateOf(0) } - +private fun AnimatedVisibilityScope.PreInstallationContent(viewState: InstallationState.PreInstallation) { + val initialOffset = with(LocalDensity.current) { 120.dp.roundToPx() } Column( modifier = Modifier .fillMaxSize() @@ -80,18 +88,32 @@ private fun PreInstallationContent(viewState: PreInstallation, transition: Trans vertical = dimensionResource(id = R.dimen.major_150) ) ) { - IconButton(onClick = viewState.onCancelClick) { - Icon( - imageVector = Icons.Default.Clear, - contentDescription = stringResource(id = R.string.cancel) - ) + (viewState as? PreInstallation)?.let { + IconButton(onClick = viewState.onCancelClick) { + Icon( + imageVector = Icons.Default.Clear, + contentDescription = stringResource(id = R.string.cancel) + ) + } } Column( verticalArrangement = Arrangement.Center, modifier = Modifier .weight(1f) .verticalScroll(rememberScrollState()) - .offset(y = -offset.dp) + .animateEnterExit( + enter = slideInVertically( + animationSpec = + tween( + durationMillis = 500, + delayMillis = 500, + // Ensure a bit of elasticity at the end of the animation + easing = CubicBezierEasing(0.7f, 0.6f, 0.74f, 1.3f) + ), + initialOffsetY = { -initialOffset } + ), + exit = ExitTransition.None + ) ) { SpacerWithMinHeight(1f, dimensionResource(id = R.dimen.major_100)) Box( @@ -114,49 +136,89 @@ private fun PreInstallationContent(viewState: PreInstallation, transition: Trans ) } Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_150))) - Text( - text = stringResource(id = R.string.install_wc_shipping_preinstall_title), - style = MaterialTheme.typography.h4, - fontWeight = FontWeight.Bold - ) - Text( - text = stringResource(id = viewState.extensionsName), - style = MaterialTheme.typography.h4, - fontWeight = FontWeight.Bold, - color = colorResource(id = R.color.woo_purple_50) - ) - Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_150))) - Text( - text = viewState.siteName, - style = MaterialTheme.typography.h4 - ) + MainContent(viewState) + SpacerWithMinHeight(0.75f, dimensionResource(id = R.dimen.major_100)) + AnimatedVisibility(visible = viewState is PreInstallation) { + InstallationInfoLink { (viewState as? PreInstallation)?.onInfoClick?.invoke() } + } SpacerWithMinHeight(0.75f, dimensionResource(id = R.dimen.major_100)) - Row( - horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.minor_100)), + } + (viewState as? PreInstallation)?.let { + WCColoredButton( + onClick = viewState.onProceedClick, modifier = Modifier - .clickable(onClick = viewState.onInfoClick) + .fillMaxWidth() + .animateEnterExit( + enter = slideInVertically( + animationSpec = + tween( + durationMillis = 500, + delayMillis = 500, + // Ensure a bit of elasticity at the end of the animation + easing = CubicBezierEasing(0.7f, 0.6f, 0.74f, 1.3f) + ), + initialOffsetY = { initialOffset } + ), + exit = ExitTransition.None + ) ) { - Icon( - imageVector = Icons.Outlined.Info, - contentDescription = null, - tint = colorResource(id = R.color.link_text) - ) - Text( - style = MaterialTheme.typography.subtitle1, - color = colorResource(id = R.color.link_text), - text = stringResource(id = R.string.install_wc_shipping_installation_info), - ) + Text(text = stringResource(id = R.string.install_wc_shipping_proceed_button)) } - SpacerWithMinHeight(0.75f, dimensionResource(id = R.dimen.major_100)) } - WCColoredButton( - onClick = viewState.onProceedClick, - modifier = Modifier - .fillMaxWidth() - .offset(y = offset.dp) - ) { - Text(text = stringResource(id = R.string.install_wc_shipping_proceed_button)) + } +} + +@OptIn(ExperimentalAnimationApi::class) +@Composable +private fun AnimatedVisibilityScope.MainContent(viewState: InstallationState) { + Column { + val text = when (viewState) { + is PreInstallation -> stringResource(id = string.install_wc_shipping_preinstall_title) + is InstallationOngoing -> "Installing" } + Text( + text = text, + style = MaterialTheme.typography.h4, + fontWeight = FontWeight.Bold, + modifier = Modifier.animateEnterExit( + enter = if (viewState is InstallationOngoing) { + fadeIn(tween(500, delayMillis = 100)) + } else EnterTransition.None, + exit = ExitTransition.None + ) + ) + + Text( + text = stringResource(id = viewState.extensionsName), + style = MaterialTheme.typography.h4, + fontWeight = FontWeight.Bold, + color = colorResource(id = R.color.woo_purple_50) + ) + Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_150))) + Text( + text = viewState.siteName, + style = MaterialTheme.typography.h4 + ) + } +} + +@Composable +private fun InstallationInfoLink(onClick: () -> Unit) { + Row( + horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.minor_100)), + modifier = Modifier + .clickable(onClick = onClick) + ) { + Icon( + imageVector = Icons.Outlined.Info, + contentDescription = null, + tint = colorResource(id = R.color.link_text) + ) + Text( + style = MaterialTheme.typography.subtitle1, + color = colorResource(id = R.color.link_text), + text = stringResource(id = R.string.install_wc_shipping_installation_info), + ) } } @@ -170,14 +232,17 @@ private fun ColumnScope.SpacerWithMinHeight(weight: Float, minHeight: Dp) { @Composable private fun PreInstallationPreview() { WooThemeWithBackground { - PreInstallationContent( - viewState = PreInstallation( - extensionsName = R.string.install_wc_shipping_extension_name, - siteName = "Site", - onCancelClick = {}, - onProceedClick = {}, - onInfoClick = {} + AnimatedContent(targetState = Unit) { + InstallWCShippingFlow( + viewState = PreInstallation( + extensionsName = R.string.install_wc_shipping_extension_name, + siteName = "Site", + siteUrl = "URL", + onCancelClick = {}, + onProceedClick = {}, + onInfoClick = {} + ) ) - ) + } } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingOnboarding.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingOnboarding.kt index a9624ef3dc1..9520aedc633 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingOnboarding.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingOnboarding.kt @@ -1,9 +1,12 @@ +@file:OptIn(ExperimentalAnimationApi::class) + package com.woocommerce.android.ui.shipping -import androidx.compose.animation.core.LinearOutSlowInEasing -import androidx.compose.animation.core.Transition -import androidx.compose.animation.core.animateInt +import androidx.compose.animation.AnimatedVisibilityScope +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.tween +import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -12,7 +15,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -21,9 +23,9 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource @@ -39,10 +41,9 @@ import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.InstallWCS import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.Onboarding @Composable -fun InstallWcShippingOnboarding( - viewState: Onboarding, - transition: Transition -) { +fun AnimatedVisibilityScope.InstallWcShippingOnboarding(viewState: Onboarding) { + val targetExitOffset = with(LocalDensity.current) { 120.dp.roundToPx() } + Column( modifier = Modifier .fillMaxSize() @@ -51,18 +52,19 @@ fun InstallWcShippingOnboarding( end = dimensionResource(id = R.dimen.major_200) ) ) { - val offset by transition.animateInt( - transitionSpec = { tween(durationMillis = 500, easing = LinearOutSlowInEasing) }, - label = "offset" - ) { - if (it) 0 else 120 - } Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier .weight(1f) .verticalScroll(rememberScrollState()) - .offset(y = -offset.dp) + .animateEnterExit( + enter = EnterTransition.None, + exit = slideOutVertically( + animationSpec = + tween(durationMillis = 500), + targetOffsetY = { -targetExitOffset } + ) + ) ) { Text( modifier = Modifier.padding(top = dimensionResource(id = R.dimen.major_350)), @@ -93,7 +95,14 @@ fun InstallWcShippingOnboarding( top = dimensionResource(id = R.dimen.major_200), bottom = dimensionResource(id = R.dimen.major_200), ) - .offset(y = offset.dp) + .animateEnterExit( + enter = EnterTransition.None, + exit = slideOutVertically( + animationSpec = + tween(durationMillis = 500), + targetOffsetY = { targetExitOffset } + ) + ) ) { WCColoredButton( modifier = Modifier.fillMaxWidth(), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt index d8ee7fc6cec..f9954a2f5ac 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt @@ -1,8 +1,7 @@ package com.woocommerce.android.ui.shipping +import android.annotation.SuppressLint import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.EnterTransition -import androidx.compose.animation.ExitTransition import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.ExperimentalTransitionApi import androidx.compose.animation.core.LinearOutSlowInEasing @@ -16,11 +15,19 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.woocommerce.android.R +import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.InstallationState +import kotlinx.coroutines.delay @Composable fun InstallWCShippingScreen(viewModel: InstallWCShippingViewModel) { @@ -43,24 +50,15 @@ fun InstallWCShippingScreen(viewState: ViewState) { fadeIn(tween(500, delayMillis = 500)) .with(fadeOut(tween(500, easing = LinearOutSlowInEasing))) } else { - // TODO - EnterTransition.None.with(ExitTransition.None) + // No-op animation, just defining durations + fadeIn(tween(500), initialAlpha = 1f) + .with(fadeOut(tween(500), targetAlpha = 1f)) } } ) { targetState -> when (targetState) { - is ViewState.Onboarding -> InstallWcShippingOnboarding( - viewState = targetState, - transition = transition.createChildTransition(label = "OnboardingTransition") { - it is ViewState.Onboarding - } - ) - is InstallationState -> InstallWCShippingFlow( - viewState = targetState, - transition = transition.createChildTransition(label = "InstallationTransition") { - it is InstallationState - } - ) + is ViewState.Onboarding -> InstallWcShippingOnboarding(viewState = targetState) + is InstallationState -> InstallWCShippingFlow(viewState = targetState) } } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingViewModel.kt index 030e7ccbf6e..9b202d9ad14 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingViewModel.kt @@ -37,7 +37,6 @@ class InstallWCShippingViewModel @Inject constructor( title = R.string.install_wc_shipping_flow_onboarding_screen_title, subtitle = R.string.install_wc_shipping_flow_onboarding_screen_subtitle, bullets = getBulletPointsForInstallingWcShippingFlow(), - linkUrl = WC_SHIPPING_INFO_URL, onInfoLinkClicked = { onLinkClicked(WC_SHIPPING_INFO_URL) }, onInstallClicked = ::onInstallWcShippingClicked, onDismissFlowClicked = ::onDismissWcShippingFlowClicked @@ -47,11 +46,18 @@ class InstallWCShippingViewModel @Inject constructor( siteName = selectedSite.get().let { site -> site.displayName?.takeIf { it.isNotBlank() } ?: site.name.orEmpty() }, + siteUrl = selectedSite.get().url.orEmpty(), onCancelClick = ::onDismissWcShippingFlowClicked, - onProceedClick = { /*TODO*/ }, + onProceedClick = ::onStartInstallation, onInfoClick = { onLinkClicked("https://url") } // TODO ) - Step.Installation -> TODO() + Step.Installation -> ViewState.InstallationState.InstallationOngoing( + extensionsName = R.string.install_wc_shipping_extension_name, + siteName = selectedSite.get().let { site -> + site.displayName?.takeIf { it.isNotBlank() } ?: site.name.orEmpty() + }, + siteUrl = selectedSite.get().url.orEmpty() + ) Step.PostInstallationSuccess -> TODO() is Step.PostInstallationFailure -> TODO() } @@ -88,6 +94,10 @@ class InstallWCShippingViewModel @Inject constructor( triggerEvent(OpenLinkEvent(url)) } + private fun onStartInstallation() { + step.value = Step.Installation + } + private sealed interface Step : Parcelable { @Parcelize object Onboarding : Step @@ -110,7 +120,6 @@ class InstallWCShippingViewModel @Inject constructor( @StringRes val title: Int, @StringRes val subtitle: Int, val bullets: List, - val linkUrl: String, val onInstallClicked: () -> Unit = {}, val onDismissFlowClicked: () -> Unit = {}, val onInfoLinkClicked: () -> Unit = {} @@ -118,14 +127,23 @@ class InstallWCShippingViewModel @Inject constructor( sealed class InstallationState : ViewState { abstract val extensionsName: Int + abstract val siteName: String + abstract val siteUrl: String data class PreInstallation( @StringRes override val extensionsName: Int, - val siteName: String, + override val siteName: String, + override val siteUrl: String, val onCancelClick: () -> Unit, val onProceedClick: () -> Unit, val onInfoClick: () -> Unit ) : InstallationState() + + data class InstallationOngoing( + @StringRes override val extensionsName: Int, + override val siteName: String, + override val siteUrl: String, + ) : InstallationState() } } From 55fee2c9fd571447e36a0ca4ec709e14cb83f173 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 23 Jun 2022 20:45:01 +0100 Subject: [PATCH 029/173] Animation between pre-install and install screens --- .../ui/shipping/InstallWCShippingFlow.kt | 129 ++++++++++++++---- .../ui/shipping/InstallWCShippingScreen.kt | 59 +++++++- 2 files changed, 158 insertions(+), 30 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index e7d11d1aea6..9933d40b70f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -3,18 +3,12 @@ package com.woocommerce.android.ui.shipping import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibilityScope -import androidx.compose.animation.Crossfade import androidx.compose.animation.EnterTransition -import androidx.compose.animation.EnterTransition.Companion import androidx.compose.animation.ExitTransition import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.CubicBezierEasing import androidx.compose.animation.core.ExperimentalTransitionApi -import androidx.compose.animation.core.Transition -import androidx.compose.animation.core.animateInt -import androidx.compose.animation.core.createChildTransition import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -30,7 +24,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState @@ -44,9 +37,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.outlined.Info import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -60,10 +50,8 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.woocommerce.android.R -import com.woocommerce.android.R.string import com.woocommerce.android.ui.compose.component.WCColoredButton import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground -import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.InstallationState import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.InstallationState.InstallationOngoing import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.InstallationState.PreInstallation @@ -73,7 +61,7 @@ import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState. fun AnimatedVisibilityScope.InstallWCShippingFlow(viewState: InstallationState) { when (viewState) { is PreInstallation -> PreInstallationContent(viewState) - is InstallationOngoing -> TODO() + is InstallationOngoing -> InstallationContent(viewState) } } @@ -88,13 +76,11 @@ private fun AnimatedVisibilityScope.PreInstallationContent(viewState: Installati vertical = dimensionResource(id = R.dimen.major_150) ) ) { - (viewState as? PreInstallation)?.let { - IconButton(onClick = viewState.onCancelClick) { - Icon( - imageVector = Icons.Default.Clear, - contentDescription = stringResource(id = R.string.cancel) - ) - } + IconButton(onClick = viewState.onCancelClick) { + Icon( + imageVector = Icons.Default.Clear, + contentDescription = stringResource(id = R.string.cancel) + ) } Column( verticalArrangement = Arrangement.Center, @@ -137,11 +123,20 @@ private fun AnimatedVisibilityScope.PreInstallationContent(viewState: Installati } Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_150))) MainContent(viewState) - SpacerWithMinHeight(0.75f, dimensionResource(id = R.dimen.major_100)) - AnimatedVisibility(visible = viewState is PreInstallation) { - InstallationInfoLink { (viewState as? PreInstallation)?.onInfoClick?.invoke() } + Box( + modifier = Modifier.weight(1.5f), + contentAlignment = Alignment.Center + ) { + InstallationInfoLink( + onClick = viewState.onInfoClick, + modifier = Modifier + .padding(vertical = dimensionResource(id = R.dimen.major_100)) + .animateEnterExit( + enter = EnterTransition.None, + exit = fadeOut(tween(500)) + ) + ) } - SpacerWithMinHeight(0.75f, dimensionResource(id = R.dimen.major_100)) } (viewState as? PreInstallation)?.let { WCColoredButton( @@ -168,42 +163,102 @@ private fun AnimatedVisibilityScope.PreInstallationContent(viewState: Installati } } +@Composable +private fun AnimatedVisibilityScope.InstallationContent(viewState: InstallationOngoing) { + Column( + verticalArrangement = Arrangement.Center, + modifier = Modifier + .fillMaxSize() + .padding( + horizontal = dimensionResource(id = R.dimen.major_100), + vertical = dimensionResource(id = R.dimen.major_150) + ) + ) { + // fill equivalent space as the cross-icon + Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_300))) + SpacerWithMinHeight(1f, dimensionResource(id = R.dimen.major_100)) + Box( + modifier = Modifier + .clip(CircleShape) + .border( + width = dimensionResource(id = R.dimen.major_75), + color = colorResource(id = R.color.woo_purple_20), + shape = CircleShape + ) + .size(dimensionResource(id = R.dimen.image_major_120)) + ) { + Icon( + painter = painterResource(id = R.drawable.ic_arrow_forward_rounded), + contentDescription = null, + tint = colorResource(id = R.color.woo_purple_50), + modifier = Modifier + .align(Alignment.Center) + .size(dimensionResource(id = R.dimen.image_major_64)) + ) + } + Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_150))) + MainContent(viewState) + Box(modifier = Modifier.weight(1.5f)) { + Text( + text = viewState.siteUrl, + style = MaterialTheme.typography.body1, + modifier = Modifier + .padding(vertical = dimensionResource(id = R.dimen.major_100)) + .animateEnterExit(enter = fadeIn(tween(400, delayMillis = 600), initialAlpha = 0.5f)) + ) + } + // fill equivalent space as the proceed-button + Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_300))) + } +} + @OptIn(ExperimentalAnimationApi::class) @Composable private fun AnimatedVisibilityScope.MainContent(viewState: InstallationState) { Column { val text = when (viewState) { - is PreInstallation -> stringResource(id = string.install_wc_shipping_preinstall_title) + is PreInstallation -> stringResource(id = R.string.install_wc_shipping_preinstall_title) is InstallationOngoing -> "Installing" } Text( text = text, style = MaterialTheme.typography.h4, fontWeight = FontWeight.Bold, + // Animate the step title when starting the installation modifier = Modifier.animateEnterExit( enter = if (viewState is InstallationOngoing) { - fadeIn(tween(500, delayMillis = 100)) + fadeIn(tween(600, delayMillis = 400)) } else EnterTransition.None, exit = ExitTransition.None ) ) + // Animate the extension and site names when starting the installation + val extensionAndNameModifier = Modifier.animateEnterExit( + enter = if (viewState is InstallationOngoing) { + fadeIn(tween(400, delayMillis = 600), initialAlpha = 0.5f) + } else EnterTransition.None, + exit = ExitTransition.None + ) + Text( text = stringResource(id = viewState.extensionsName), style = MaterialTheme.typography.h4, fontWeight = FontWeight.Bold, - color = colorResource(id = R.color.woo_purple_50) + color = colorResource(id = R.color.woo_purple_50), + modifier = extensionAndNameModifier ) Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_150))) Text( text = viewState.siteName, - style = MaterialTheme.typography.h4 + style = MaterialTheme.typography.h4, + modifier = extensionAndNameModifier ) } } @Composable -private fun InstallationInfoLink(onClick: () -> Unit) { +private fun InstallationInfoLink(onClick: () -> Unit, modifier: Modifier = Modifier) { Row( horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.minor_100)), modifier = Modifier @@ -246,3 +301,19 @@ private fun PreInstallationPreview() { } } } + +@Preview +@Composable +private fun InstallationOngoingPreview() { + WooThemeWithBackground { + AnimatedContent(targetState = Unit) { + InstallationContent( + viewState = InstallationOngoing( + extensionsName = R.string.install_wc_shipping_extension_name, + siteName = "Site", + siteUrl = "URL" + ) + ) + } + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt index f9954a2f5ac..201b54f03bf 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt @@ -5,7 +5,6 @@ import androidx.compose.animation.AnimatedContent import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.ExperimentalTransitionApi import androidx.compose.animation.core.LinearOutSlowInEasing -import androidx.compose.animation.core.createChildTransition import androidx.compose.animation.core.tween import androidx.compose.animation.core.updateTransition import androidx.compose.animation.fadeIn @@ -63,3 +62,61 @@ fun InstallWCShippingScreen(viewState: ViewState) { } } } + +@SuppressLint("RememberReturnType") +@Preview +@Composable +private fun PreviewInstallWCShippingScreen() { + val states = remember { + mutableListOf() + } + + var state by remember { + mutableStateOf(states.getOrNull(0)) + } + + remember { + states.add( + ViewState.Onboarding( + title = R.string.install_wc_shipping_flow_onboarding_screen_title, + subtitle = R.string.install_wc_shipping_flow_onboarding_screen_subtitle, + bullets = emptyList(), + onInstallClicked = { state = states[1] } + ) + ) + + states.add( + InstallationState.PreInstallation( + extensionsName = R.string.install_wc_shipping_extension_name, + siteName = "Site", + siteUrl = "URL", + onCancelClick = {}, + onProceedClick = { state = states[2] }, + onInfoClick = {} + ) + ) + + states.add( + InstallationState.InstallationOngoing( + extensionsName = R.string.install_wc_shipping_extension_name, + siteName = "Site", + siteUrl = "URL" + ) + ) + + state = states[0] + } + + LaunchedEffect(state) { + if (state is InstallationState.InstallationOngoing) { + delay(5000) + state = states[0] + } + } + + WooThemeWithBackground { + state?.let { + InstallWCShippingScreen(viewState = it) + } + } +} From c150bf45fa38311c8068aaaffa2737f5ceac87ac Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 23 Jun 2022 20:58:14 +0100 Subject: [PATCH 030/173] Add a TODO comment about starting the installation --- .../ui/shipping/InstallWCShippingViewModel.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingViewModel.kt index 9b202d9ad14..6e1eb44264a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingViewModel.kt @@ -7,12 +7,16 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asLiveData import com.woocommerce.android.R import com.woocommerce.android.tools.SelectedSite +import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.Step.Installation import com.woocommerce.android.viewmodel.MultiLiveEvent import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import com.woocommerce.android.viewmodel.ScopedViewModel import com.woocommerce.android.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize import javax.inject.Inject @@ -31,6 +35,16 @@ class InstallWCShippingViewModel @Inject constructor( .map { prepareStep(it) } .asLiveData() + init { + launch { + // Wait for installation step + step.filter { it == Installation } + .first() + + // TODO launch plugin installation + } + } + private fun prepareStep(step: Step): ViewState { return when (step) { Step.Onboarding -> ViewState.Onboarding( From 136668a1b8b81ee89e9158e14f451f61549e8097 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Fri, 24 Jun 2022 20:30:34 +0100 Subject: [PATCH 031/173] Use None as parent animation between pre-install and installation --- .../android/ui/shipping/InstallWCShippingScreen.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt index 201b54f03bf..5a5ccbb96f6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt @@ -2,6 +2,9 @@ package com.woocommerce.android.ui.shipping import android.annotation.SuppressLint import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import androidx.compose.animation.ExitTransition.Companion import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.ExperimentalTransitionApi import androidx.compose.animation.core.LinearOutSlowInEasing @@ -49,9 +52,8 @@ fun InstallWCShippingScreen(viewState: ViewState) { fadeIn(tween(500, delayMillis = 500)) .with(fadeOut(tween(500, easing = LinearOutSlowInEasing))) } else { - // No-op animation, just defining durations - fadeIn(tween(500), initialAlpha = 1f) - .with(fadeOut(tween(500), targetAlpha = 1f)) + // No-op animation, each screen will define animations for specific components separately + EnterTransition.None.with(ExitTransition.None) } } ) { targetState -> From 85d9ca3cb2b6b805af185ab17cffddfd0dc50942 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Fri, 24 Jun 2022 21:51:39 +0100 Subject: [PATCH 032/173] Adjust animation durations --- .../woocommerce/android/ui/shipping/InstallWCShippingFlow.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index 9933d40b70f..6930d6fd20a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -9,6 +9,7 @@ import androidx.compose.animation.ExitTransition import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.CubicBezierEasing import androidx.compose.animation.core.ExperimentalTransitionApi +import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -227,7 +228,7 @@ private fun AnimatedVisibilityScope.MainContent(viewState: InstallationState) { // Animate the step title when starting the installation modifier = Modifier.animateEnterExit( enter = if (viewState is InstallationOngoing) { - fadeIn(tween(600, delayMillis = 400)) + fadeIn(tween(400, delayMillis = 600, easing = LinearEasing)) } else EnterTransition.None, exit = ExitTransition.None ) @@ -236,7 +237,7 @@ private fun AnimatedVisibilityScope.MainContent(viewState: InstallationState) { // Animate the extension and site names when starting the installation val extensionAndNameModifier = Modifier.animateEnterExit( enter = if (viewState is InstallationOngoing) { - fadeIn(tween(400, delayMillis = 600), initialAlpha = 0.5f) + fadeIn(tween(200, delayMillis = 800, easing = LinearEasing), initialAlpha = 0.5f) } else EnterTransition.None, exit = ExitTransition.None ) From eafe4a8d148c30ab9fc2d2b7169032b570574303 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 27 Jun 2022 09:40:07 +0530 Subject: [PATCH 033/173] remove PluginType from CardReaderOnboardingChecker.kt constructor parameter and pass it as a parameter for getOnboardingState() function. --- .../android/di/CardReaderModule.kt | 3 -- .../onboarding/CardReaderOnboardingChecker.kt | 26 +++++----- .../CardReaderOnboardingFragment.kt | 5 +- .../CardReaderOnboardingViewModel.kt | 6 +-- .../CardReaderOnboardingCheckerTest.kt | 49 +++++++++++-------- 5 files changed, 50 insertions(+), 39 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt index 4319668a162..8da808d9ee4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt @@ -85,7 +85,4 @@ class CardReaderModule { @Provides @Reusable fun provideCardReaderConfigFactory() = CardReaderConfigFactory() - - @Provides - fun providePluginType() = PluginType.valueOf("") } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index a63d4f93698..b78634e86db 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -76,12 +76,11 @@ class CardReaderOnboardingChecker @Inject constructor( private val cardReaderTrackingInfoKeeper: CardReaderTrackingInfoKeeper, private val cardReaderCountryConfigProvider: CardReaderCountryConfigProvider, private val ippSelectPaymentGateway: IppSelectPaymentGateway, - private val userSelectedPlugin: PluginType? = null, ) { - suspend fun getOnboardingState(): CardReaderOnboardingState { + suspend fun getOnboardingState(pluginType: PluginType? = null): CardReaderOnboardingState { if (!networkStatus.isConnected()) return NoConnectionError - return fetchOnboardingState() + return fetchOnboardingState(pluginType) .also { val (status, version) = when (it) { is OnboardingCompleted -> CARD_READER_ONBOARDING_COMPLETED to it.version @@ -112,7 +111,7 @@ class CardReaderOnboardingChecker @Inject constructor( } @Suppress("ReturnCount", "ComplexMethod", "LongMethod") - private suspend fun fetchOnboardingState(): CardReaderOnboardingState { + private suspend fun fetchOnboardingState(pluginType: PluginType?): CardReaderOnboardingState { val countryCode = getStoreCountryCode() cardReaderTrackingInfoKeeper.setCountry(countryCode) val cardReaderConfig = cardReaderCountryConfigProvider.provideCountryConfigFor(countryCode) @@ -131,17 +130,17 @@ class CardReaderOnboardingChecker @Inject constructor( } } if (ippSelectPaymentGateway.isEnabled()) { - if (hasUserAlreadySelectedThePlugin()) { + if (hasUserAlreadySelectedThePlugin(pluginType)) { updatePluginExplicitlySelectedFlag(true) } else { - return getMultipleGatewayProviderState() + return getMultipleGatewayProviderState(pluginType) } } else { return WcpayAndStripeActivated } } - val preferredPlugin = getUserSelectedPluginOrActivatedPlugin(wcPayPluginInfo, stripePluginInfo) + val preferredPlugin = getUserSelectedPluginOrActivatedPlugin(pluginType, wcPayPluginInfo, stripePluginInfo) if (!isPluginInstalled(preferredPlugin)) when (preferredPlugin.type) { WOOCOMMERCE_PAYMENTS -> return WcpayNotInstalled @@ -200,16 +199,17 @@ class CardReaderOnboardingChecker @Inject constructor( ) } - private fun hasUserAlreadySelectedThePlugin(): Boolean { + private fun hasUserAlreadySelectedThePlugin(userSelectedPlugin: PluginType?): Boolean { if (userSelectedPlugin != null) { return true } return false } - private fun getMultipleGatewayProviderState(): CardReaderOnboardingState { + private fun getMultipleGatewayProviderState(pluginType: PluginType?): CardReaderOnboardingState { return when { - !isPluginExplicitlySelected() && !hasUserAlreadySelectedThePlugin() -> ChoosePaymentGatewayProvider + !isPluginExplicitlySelected() && !hasUserAlreadySelectedThePlugin(pluginType) -> + ChoosePaymentGatewayProvider else -> throw IllegalStateException( "Developer error: plugin selected flag is true even when the user hasn't selected the plugin" ) @@ -217,12 +217,13 @@ class CardReaderOnboardingChecker @Inject constructor( } private fun getUserSelectedPluginOrActivatedPlugin( + pluginType: PluginType?, wcPayPluginInfo: SitePluginModel?, stripePluginInfo: SitePluginModel?, ): PluginWrapper { return when { - hasUserAlreadySelectedThePlugin() -> { - getUserSelectedPluginWrapper(wcPayPluginInfo, stripePluginInfo) + hasUserAlreadySelectedThePlugin(pluginType) -> { + getUserSelectedPluginWrapper(pluginType, wcPayPluginInfo, stripePluginInfo) } else -> { getPreferredPlugin(stripePluginInfo, wcPayPluginInfo) @@ -231,6 +232,7 @@ class CardReaderOnboardingChecker @Inject constructor( } private fun getUserSelectedPluginWrapper( + userSelectedPlugin: PluginType?, wcPayPluginInfo: SitePluginModel?, stripePluginInfo: SitePluginModel?, ): PluginWrapper { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt index c0c551bb2fb..014f1e10cc4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt @@ -264,7 +264,10 @@ sealed class CardReaderOnboardingParams : Parcelable { abstract val cardReaderFlowParam: CardReaderFlowParam @Parcelize - data class Check(override val cardReaderFlowParam: CardReaderFlowParam) : CardReaderOnboardingParams() + data class Check( + override val cardReaderFlowParam: CardReaderFlowParam, + val pluginType: PluginType? = null + ) : CardReaderOnboardingParams() @Parcelize data class Failed( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index b55711096c8..6d5ddddb738 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -87,15 +87,15 @@ class CardReaderOnboardingViewModel @Inject constructor( init { when (val onboardingParam = arguments.cardReaderOnboardingParam) { - is Check -> refreshState() + is Check -> refreshState(onboardingParam.pluginType) is Failed -> showOnboardingState(onboardingParam.onboardingState) }.exhaustive } - private fun refreshState() { + private fun refreshState(pluginType: PluginType? = null) { launch { viewState.value = OnboardingViewState.LoadingState - val state = cardReaderChecker.getOnboardingState() + val state = cardReaderChecker.getOnboardingState(pluginType) cardReaderTracker.trackOnboardingState(state) showOnboardingState(state) } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index 0d5eceb7a73..c5d2f4d9085 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -67,7 +67,17 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { @Before fun setUp() = testBlocking { - checker = initOnboardingChecker() + checker = CardReaderOnboardingChecker( + selectedSite, + appPrefsWrapper, + wooStore, + wcInPersonPaymentsStore, + coroutinesTestRule.testDispatchers, + networkStatus, + cardReaderTrackingInfoKeeper, + cardReaderCountryConfigProvider, + ippSelectPaymentGateway, + ) whenever(networkStatus.isConnected()).thenReturn(true) whenever(selectedSite.get()).thenReturn(site) whenever(wooStore.getStoreCountryCode(site)).thenReturn(countryCode) @@ -87,21 +97,6 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(false) } - private fun initOnboardingChecker(pluginType: PluginType? = null): CardReaderOnboardingChecker { - return CardReaderOnboardingChecker( - selectedSite, - appPrefsWrapper, - wooStore, - wcInPersonPaymentsStore, - coroutinesTestRule.testDispatchers, - networkStatus, - cardReaderTrackingInfoKeeper, - cardReaderCountryConfigProvider, - ippSelectPaymentGateway, - pluginType - ) - } - @Test fun `when not connected to network, then NO_CONNECTION returned`() = testBlocking { whenever(networkStatus.isConnected()).thenReturn(false) @@ -1257,7 +1252,6 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { @Test fun `given plugin selected, when multiple plugins, then set plugin flag`() = testBlocking { - val checker = initOnboardingChecker(PluginType.WOOCOMMERCE_PAYMENTS) whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) @@ -1265,7 +1259,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) .thenReturn(buildWCPayPluginInfo(isActive = true)) - checker.getOnboardingState() + checker.getOnboardingState(PluginType.WOOCOMMERCE_PAYMENTS) verify(appPrefsWrapper).setIsCardReaderPluginExplicitlySelectedFlag( anyInt(), @@ -1276,9 +1270,8 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { } @Test - fun `when onboarding fails, then clear isPluginExplicitlySelected flag`() = + fun `given payment gateway feature flag, when onboarding fails, then clear isPluginExplicitlySelected flag`() = testBlocking { - val checker = initOnboardingChecker(PluginType.WOOCOMMERCE_PAYMENTS) whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) whenever(wooStore.getStoreCountryCode(site)).thenReturn("unsupported country abc") @@ -1292,6 +1285,22 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { ) } + @Test + fun `given gateway feature flag false, when onboarding fails, then dont clear isPluginExplicitlySelected flag`() = + testBlocking { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(false) + whenever(wooStore.getStoreCountryCode(site)).thenReturn("unsupported country abc") + + checker.getOnboardingState() + + verify(appPrefsWrapper, never()).setIsCardReaderPluginExplicitlySelectedFlag( + anyInt(), + anyLong(), + anyLong(), + anyBoolean() + ) + } + //endregion private fun buildPaymentAccountResult( From 5e037dd47430f902b8bcc9a5a66d790ce7589ea1 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 27 Jun 2022 09:41:28 +0530 Subject: [PATCH 034/173] remove unused imports --- .../main/kotlin/com/woocommerce/android/di/CardReaderModule.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt index 8da808d9ee4..e421bd2bc62 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/CardReaderModule.kt @@ -8,7 +8,6 @@ import com.woocommerce.android.cardreader.CardReaderStore.CapturePaymentResponse import com.woocommerce.android.cardreader.LogWrapper import com.woocommerce.android.cardreader.internal.config.CardReaderConfigFactory import com.woocommerce.android.tools.SelectedSite -import com.woocommerce.android.ui.cardreader.onboarding.PluginType import com.woocommerce.android.ui.cardreader.onboarding.toInPersonPaymentsPluginType import com.woocommerce.android.util.CapturePaymentResponseMapper import com.woocommerce.android.util.WooLog From 21abd16ad49cd79912d10c3fc3e608216705abe7 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 27 Jun 2022 12:13:02 +0530 Subject: [PATCH 035/173] refactor CardReaderOnboardingChecker.kt --- .../onboarding/CardReaderOnboardingChecker.kt | 46 ++++++----- .../CardReaderOnboardingCheckerTest.kt | 80 ++++++++++++++----- 2 files changed, 85 insertions(+), 41 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index b78634e86db..8ce3afe33e9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -130,17 +130,20 @@ class CardReaderOnboardingChecker @Inject constructor( } } if (ippSelectPaymentGateway.isEnabled()) { - if (hasUserAlreadySelectedThePlugin(pluginType)) { - updatePluginExplicitlySelectedFlag(true) - } else { - return getMultipleGatewayProviderState(pluginType) + when { + isUserComingFromChoosePaymentGatewayScreen(pluginType) -> { + updatePluginExplicitlySelectedFlag(true) + } + !isPluginExplicitlySelected() -> { + return ChoosePaymentGatewayProvider + } } } else { return WcpayAndStripeActivated } } - val preferredPlugin = getUserSelectedPluginOrActivatedPlugin(pluginType, wcPayPluginInfo, stripePluginInfo) + val preferredPlugin = getUserSelectedPluginOrActivatedPlugin(wcPayPluginInfo, stripePluginInfo) if (!isPluginInstalled(preferredPlugin)) when (preferredPlugin.type) { WOOCOMMERCE_PAYMENTS -> return WcpayNotInstalled @@ -199,31 +202,32 @@ class CardReaderOnboardingChecker @Inject constructor( ) } - private fun hasUserAlreadySelectedThePlugin(userSelectedPlugin: PluginType?): Boolean { + private fun isUserComingFromChoosePaymentGatewayScreen(userSelectedPlugin: PluginType?): Boolean { if (userSelectedPlugin != null) { return true } return false } - private fun getMultipleGatewayProviderState(pluginType: PluginType?): CardReaderOnboardingState { - return when { - !isPluginExplicitlySelected() && !hasUserAlreadySelectedThePlugin(pluginType) -> - ChoosePaymentGatewayProvider - else -> throw IllegalStateException( - "Developer error: plugin selected flag is true even when the user hasn't selected the plugin" - ) - } - } - private fun getUserSelectedPluginOrActivatedPlugin( - pluginType: PluginType?, wcPayPluginInfo: SitePluginModel?, stripePluginInfo: SitePluginModel?, ): PluginWrapper { return when { - hasUserAlreadySelectedThePlugin(pluginType) -> { - getUserSelectedPluginWrapper(pluginType, wcPayPluginInfo, stripePluginInfo) + isPluginExplicitlySelected() -> { + val site = selectedSite.get() + val pluginType = appPrefsWrapper.getCardReaderPreferredPlugin( + localSiteId = site.id, + remoteSiteId = site.siteId, + selfHostedSiteId = site.selfHostedSiteId, + ) + pluginType?.let { + getUserSelectedPluginWrapper(it, wcPayPluginInfo, stripePluginInfo) + } ?: run { + throw IllegalStateException( + "Developer Error: Plugin type cannot be null when the plugin explicitly selected flag is true" + ) + } } else -> { getPreferredPlugin(stripePluginInfo, wcPayPluginInfo) @@ -232,11 +236,11 @@ class CardReaderOnboardingChecker @Inject constructor( } private fun getUserSelectedPluginWrapper( - userSelectedPlugin: PluginType?, + userSelectedPlugin: PluginType, wcPayPluginInfo: SitePluginModel?, stripePluginInfo: SitePluginModel?, ): PluginWrapper { - return PluginWrapper(userSelectedPlugin!!, userSelectedPlugin.getPluginInfo(wcPayPluginInfo, stripePluginInfo)) + return PluginWrapper(userSelectedPlugin, userSelectedPlugin.getPluginInfo(wcPayPluginInfo, stripePluginInfo)) } private fun isPluginSupportedInCountry( diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index c5d2f4d9085..fc74bf2d9e8 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -1229,26 +1229,6 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { assertThat(result).isEqualTo(CardReaderOnboardingState.ChoosePaymentGatewayProvider) } - @Test(expected = IllegalStateException::class) - fun `given no plugin selected and selected flag true, when multiple plugins, then throw exception`() = - testBlocking { - whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) - whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) - whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) - .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) - whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) - .thenReturn(buildWCPayPluginInfo(isActive = true)) - whenever( - appPrefsWrapper.isCardReaderPluginExplicitlySelected( - anyInt(), - anyLong(), - anyLong(), - ) - ).thenReturn(true) - - checker.getOnboardingState() - } - @Test fun `given plugin selected, when multiple plugins, then set plugin flag`() = testBlocking { @@ -1301,6 +1281,66 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { ) } + @Test + fun `given plugin selected, when navigating to onboarding, then select the plugin from shared preference`() = + testBlocking { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + whenever( + appPrefsWrapper.isCardReaderPluginExplicitlySelected( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(true) + whenever( + appPrefsWrapper.getCardReaderPreferredPlugin( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(STRIPE_EXTENSION_GATEWAY) + + checker.getOnboardingState() + + verify(appPrefsWrapper).getCardReaderPreferredPlugin( + anyInt(), + anyLong(), + anyLong(), + ) + } + + @Test(expected = IllegalStateException::class) + fun `given plugin selected flag is true, when no plugin found in shared preference , then throw exception`() = + testBlocking { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + whenever( + appPrefsWrapper.isCardReaderPluginExplicitlySelected( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(true) + whenever( + appPrefsWrapper.getCardReaderPreferredPlugin( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(null) + + checker.getOnboardingState() + } + //endregion private fun buildPaymentAccountResult( From 79d74353a9dac9ab5da65c00334bbd9cf1476fef Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 27 Jun 2022 12:47:11 +0530 Subject: [PATCH 036/173] Clear selected plugin flag when single plugin is installed. Refactored some tests. --- .../onboarding/CardReaderOnboardingChecker.kt | 2 + .../CardReaderOnboardingCheckerTest.kt | 68 +++++++++++++++++-- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index 8ce3afe33e9..6e868bc55f8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -141,6 +141,8 @@ class CardReaderOnboardingChecker @Inject constructor( } else { return WcpayAndStripeActivated } + } else { + updatePluginExplicitlySelectedFlag(false) } val preferredPlugin = getUserSelectedPluginOrActivatedPlugin(wcPayPluginInfo, stripePluginInfo) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index fc74bf2d9e8..bff7ee258d1 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -1123,7 +1123,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { //region - Multiple Plugins detected tests @Test - fun `when onboarding not completed, then clear pluginExplicitlySelected flag`() = testBlocking { + fun `given feature flag is enabled, when onboarding not completed, then clear plugin flag`() = testBlocking { whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) whenever(wooStore.getStoreCountryCode(site)).thenReturn("unsupported country abc") @@ -1155,7 +1155,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { } @Test - fun `when onboarding has pending requirements, then do not clear pluginExplicitlySelected flag`() = testBlocking { + fun `given multiple plugins, when pending requirements, then don't clear plugin selected flag`() = testBlocking { whenever(wcInPersonPaymentsStore.loadAccount(any(), any())).thenReturn( buildPaymentAccountResult( WCPaymentAccountResult.WCPaymentAccountStatus.RESTRICTED, @@ -1163,6 +1163,26 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { hadOverdueRequirements = false ) ) + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + whenever( + appPrefsWrapper.isCardReaderPluginExplicitlySelected( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(true) + whenever( + appPrefsWrapper.getCardReaderPreferredPlugin( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(STRIPE_EXTENSION_GATEWAY) checker.getOnboardingState() @@ -1175,12 +1195,27 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { } @Test - fun `when onboarding completed, then do not clear pluginExplicitlySelected flag`() = testBlocking { + fun `given multiple plugins, when onboarding completed, then don't clear plugin selected flag`() = testBlocking { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) .thenReturn(buildWCPayPluginInfo(isActive = true)) whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) - .thenReturn(null) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever( + appPrefsWrapper.isCardReaderPluginExplicitlySelected( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(true) + whenever( + appPrefsWrapper.getCardReaderPreferredPlugin( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(STRIPE_EXTENSION_GATEWAY) checker.getOnboardingState() @@ -1188,7 +1223,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { anyInt(), anyLong(), anyLong(), - anyBoolean(), + eq(false), ) } @@ -1208,7 +1243,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { } @Test - fun `given no plugin selected & selected flag false,when multiple plugins, then ChoosePaymentProvider returned `() = + fun `given no plugin selected & selected flag false,when multiple plugins,then ChoosePaymentProvider returned `() = testBlocking { whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) @@ -1249,6 +1284,25 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { ) } + @Test + fun `given single plugin, when onboarding checks, then clear plugin selected flag`() = + testBlocking { + whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(null) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + + checker.getOnboardingState() + + verify(appPrefsWrapper).setIsCardReaderPluginExplicitlySelectedFlag( + anyInt(), + anyLong(), + anyLong(), + eq(false) + ) + } + @Test fun `given payment gateway feature flag, when onboarding fails, then clear isPluginExplicitlySelected flag`() = testBlocking { @@ -1266,7 +1320,7 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { } @Test - fun `given gateway feature flag false, when onboarding fails, then dont clear isPluginExplicitlySelected flag`() = + fun `given gateway feature flag false, when onboarding fails, then don't clear isPluginExplicitlySelected flag`() = testBlocking { whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(false) whenever(wooStore.getStoreCountryCode(site)).thenReturn("unsupported country abc") From d33fd6f1bde881acbd72812d9481960ca4c436d8 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 27 Jun 2022 12:51:41 +0530 Subject: [PATCH 037/173] Clear selected plugin flag when single plugin is installed -> Only when ipp payment gateway feature flag is enabled. --- .../onboarding/CardReaderOnboardingChecker.kt | 4 +++- .../CardReaderOnboardingCheckerTest.kt | 22 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index 6e868bc55f8..1c210bdbf10 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -142,7 +142,9 @@ class CardReaderOnboardingChecker @Inject constructor( return WcpayAndStripeActivated } } else { - updatePluginExplicitlySelectedFlag(false) + if (ippSelectPaymentGateway.isEnabled()) { + updatePluginExplicitlySelectedFlag(false) + } } val preferredPlugin = getUserSelectedPluginOrActivatedPlugin(wcPayPluginInfo, stripePluginInfo) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index bff7ee258d1..759905751c8 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -1285,8 +1285,9 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { } @Test - fun `given single plugin, when onboarding checks, then clear plugin selected flag`() = + fun `given single plugin, when payment gateway feature is enabled, then clear plugin selected flag`() = testBlocking { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) .thenReturn(null) @@ -1303,6 +1304,25 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { ) } + @Test + fun `given single plugin, when payment gateway feature is disabled, then don't clear plugin selected flag`() = + testBlocking { + whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(null) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + + checker.getOnboardingState() + + verify(appPrefsWrapper, never()).setIsCardReaderPluginExplicitlySelectedFlag( + anyInt(), + anyLong(), + anyLong(), + anyBoolean(), + ) + } + @Test fun `given payment gateway feature flag, when onboarding fails, then clear isPluginExplicitlySelected flag`() = testBlocking { From 3eb3f6376a611801cae10f7235e2919295f119d3 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 27 Jun 2022 15:13:37 +0530 Subject: [PATCH 038/173] Add test case which verifies that we are storing the preferred plugin when the onboarding screen is entered via choose payment gateway screen. --- .../onboarding/CardReaderOnboardingChecker.kt | 5 +++ .../CardReaderOnboardingCheckerTest.kt | 40 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt index 1c210bdbf10..7074383bfa0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingChecker.kt @@ -132,6 +132,11 @@ class CardReaderOnboardingChecker @Inject constructor( if (ippSelectPaymentGateway.isEnabled()) { when { isUserComingFromChoosePaymentGatewayScreen(pluginType) -> { + updateSharedPreferences( + CARD_READER_ONBOARDING_NOT_COMPLETED, + pluginType, + null + ) updatePluginExplicitlySelectedFlag(true) } !isPluginExplicitlySelected() -> { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt index 759905751c8..3c748097c14 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingCheckerTest.kt @@ -1388,6 +1388,46 @@ class CardReaderOnboardingCheckerTest : BaseUnitTest() { ) } + @Test + fun `when navigating to onboarding via payment gateway screen, then store the plugin to the shared preference`() = + testBlocking { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.fetchSitePlugins(site)).thenReturn(WooResult(listOf())) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(site, WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + whenever( + appPrefsWrapper.isCardReaderPluginExplicitlySelected( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(true) + whenever( + appPrefsWrapper.getCardReaderPreferredPlugin( + anyInt(), + anyLong(), + anyLong(), + ) + ).thenReturn(PluginType.WOOCOMMERCE_PAYMENTS) + + checker.getOnboardingState(PluginType.WOOCOMMERCE_PAYMENTS) + + verify(appPrefsWrapper).setCardReaderOnboardingData( + anyInt(), + anyLong(), + anyLong(), + eq( + PersistentOnboardingData( + CARD_READER_ONBOARDING_NOT_COMPLETED, + PluginType.WOOCOMMERCE_PAYMENTS, + null + ) + ) + ) + } + @Test(expected = IllegalStateException::class) fun `given plugin selected flag is true, when no plugin found in shared preference , then throw exception`() = testBlocking { From 20527c4dcbc97fd778ea3a298781a509919457ae Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 27 Jun 2022 16:50:21 +0530 Subject: [PATCH 039/173] Inject WooStore and IPP payment gateway feature flag as dependency into the CardReaderHubViewModel.kt --- .../android/ui/cardreader/hub/CardReaderHubViewModel.kt | 4 ++++ .../ui/cardreader/hub/CardReaderHubViewModelTest.kt | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt index 4ce189c06a4..03ced16997e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt @@ -10,6 +10,7 @@ import com.woocommerce.android.R import com.woocommerce.android.model.UiString import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.cardreader.InPersonPaymentsCanadaFeatureFlag +import com.woocommerce.android.ui.cardreader.IppSelectPaymentGateway import com.woocommerce.android.ui.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.cardreader.onboarding.PluginType.STRIPE_EXTENSION_GATEWAY import com.woocommerce.android.ui.cardreader.onboarding.PluginType.WOOCOMMERCE_PAYMENTS @@ -17,6 +18,7 @@ import com.woocommerce.android.viewmodel.MultiLiveEvent import com.woocommerce.android.viewmodel.ScopedViewModel import com.woocommerce.android.viewmodel.navArgs import dagger.hilt.android.lifecycle.HiltViewModel +import org.wordpress.android.fluxc.store.WooCommerceStore import javax.inject.Inject @HiltViewModel @@ -25,6 +27,8 @@ class CardReaderHubViewModel @Inject constructor( private val inPersonPaymentsCanadaFeatureFlag: InPersonPaymentsCanadaFeatureFlag, private val appPrefsWrapper: AppPrefsWrapper, private val selectedSite: SelectedSite, + private val wooStore: WooCommerceStore, + private val ippSelectPaymentGateway: IppSelectPaymentGateway, ) : ScopedViewModel(savedState) { private val arguments: CardReaderHubFragmentArgs by savedState.navArgs() diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt index feda89e3c76..027632f1e56 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt @@ -7,6 +7,7 @@ import com.woocommerce.android.initSavedStateHandle import com.woocommerce.android.model.UiString import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.cardreader.InPersonPaymentsCanadaFeatureFlag +import com.woocommerce.android.ui.cardreader.IppSelectPaymentGateway import com.woocommerce.android.ui.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.cardreader.onboarding.PluginType.STRIPE_EXTENSION_GATEWAY import com.woocommerce.android.ui.cardreader.onboarding.PluginType.WOOCOMMERCE_PAYMENTS @@ -18,6 +19,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.store.WooCommerceStore class CardReaderHubViewModelTest : BaseUnitTest() { private lateinit var viewModel: CardReaderHubViewModel @@ -29,6 +31,8 @@ class CardReaderHubViewModelTest : BaseUnitTest() { private val selectedSite: SelectedSite = mock { on(it.get()).thenReturn(SiteModel()) } + private val wooStore: WooCommerceStore = mock() + private val ippSelectPaymentGateway: IppSelectPaymentGateway = mock() private val countryCode = "US" private val savedState = CardReaderHubFragmentArgs( @@ -201,7 +205,9 @@ class CardReaderHubViewModelTest : BaseUnitTest() { savedState, inPersonPaymentsCanadaFeatureFlag, appPrefsWrapper, - selectedSite + selectedSite, + wooStore, + ippSelectPaymentGateway ) } } From 5d55bdfd14723a269b0181d15a58d42624603fe0 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 27 Jun 2022 17:59:42 +0530 Subject: [PATCH 040/173] Add visibility logic for showing Payment Provider row in the CardReaderHubViewModel.kt --- .../cardreader/hub/CardReaderHubViewModel.kt | 64 +++++++++++++------ WooCommerce/src/main/res/values/strings.xml | 1 + .../hub/CardReaderHubViewModelTest.kt | 38 ++++++++++- 3 files changed, 82 insertions(+), 21 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt index 03ced16997e..fe5dfac422e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt @@ -18,6 +18,7 @@ import com.woocommerce.android.viewmodel.MultiLiveEvent import com.woocommerce.android.viewmodel.ScopedViewModel import com.woocommerce.android.viewmodel.navArgs import dagger.hilt.android.lifecycle.HiltViewModel +import org.wordpress.android.fluxc.model.plugin.SitePluginModel import org.wordpress.android.fluxc.store.WooCommerceStore import javax.inject.Inject @@ -32,6 +33,33 @@ class CardReaderHubViewModel @Inject constructor( ) : ScopedViewModel(savedState) { private val arguments: CardReaderHubFragmentArgs by savedState.navArgs() + private val cardReaderHubListWhenSinglePluginInstalled = mutableListOf( + CardReaderHubListItemViewState( + icon = R.drawable.ic_shopping_cart, + label = UiString.UiStringRes(R.string.card_reader_purchase_card_reader), + onItemClicked = ::onPurchaseCardReaderClicked + ), + CardReaderHubListItemViewState( + icon = R.drawable.ic_manage_card_reader, + label = UiString.UiStringRes(R.string.card_reader_manage_card_reader), + onItemClicked = ::onManageCardReaderClicked + ), + CardReaderHubListItemViewState( + icon = R.drawable.ic_card_reader_manual, + label = UiString.UiStringRes(R.string.settings_card_reader_manuals), + onItemClicked = ::onCardReaderManualsClicked + ) + ) + + private val cardReaderHubListWhenMultiplePluginsInstalled = cardReaderHubListWhenSinglePluginInstalled + + mutableListOf( + CardReaderHubListItemViewState( + icon = R.drawable.ic_card_reader_manual, + label = UiString.UiStringRes(R.string.card_reader_manage_payment_provider), + onItemClicked = ::onCardReaderManualsClicked + ) + ) + private val cardReaderPurchaseUrl: String by lazy { if (inPersonPaymentsCanadaFeatureFlag.isEnabled()) { // todo fix the URL when decided @@ -53,25 +81,23 @@ class CardReaderHubViewModel @Inject constructor( createInitialState() ) - private fun createInitialState() = CardReaderHubViewState.Content( - mutableListOf( - CardReaderHubListItemViewState( - icon = R.drawable.ic_shopping_cart, - label = UiString.UiStringRes(R.string.card_reader_purchase_card_reader), - onItemClicked = ::onPurchaseCardReaderClicked - ), - CardReaderHubListItemViewState( - icon = R.drawable.ic_manage_card_reader, - label = UiString.UiStringRes(R.string.card_reader_manage_card_reader), - onItemClicked = ::onManageCardReaderClicked - ), - CardReaderHubListItemViewState( - icon = R.drawable.ic_card_reader_manual, - label = UiString.UiStringRes(R.string.settings_card_reader_manuals), - onItemClicked = ::onCardReaderManualsClicked - ) - ) - ) + private fun createInitialState(): CardReaderHubViewState.Content { + val wcPayPluginInfo = wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_PAYMENTS) + val stripePluginInfo = wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY) + + return if (isBothPluginsActivated(wcPayPluginInfo, stripePluginInfo) && ippSelectPaymentGateway.isEnabled()) { + CardReaderHubViewState.Content(cardReaderHubListWhenMultiplePluginsInstalled) + } else { + CardReaderHubViewState.Content(cardReaderHubListWhenSinglePluginInstalled) + } + } + + private fun isBothPluginsActivated( + wcPayPluginInfo: SitePluginModel?, + stripePluginInfo: SitePluginModel? + ) = isPluginActivated(wcPayPluginInfo) && isPluginActivated(stripePluginInfo) + + private fun isPluginActivated(pluginInfo: SitePluginModel?): Boolean = pluginInfo?.isActive == true val viewStateData: LiveData = viewState diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index f82c83b606c..a3b9a9fcfe5 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -917,6 +917,7 @@ --> Manage Card Reader Order Card Reader + Payment Provider BBPOS Chipper™ 2X BT Stripe M2 WisePad 3 diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt index 027632f1e56..2a06c2ca6d4 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt @@ -19,6 +19,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.model.plugin.SitePluginModel import org.wordpress.android.fluxc.store.WooCommerceStore class CardReaderHubViewModelTest : BaseUnitTest() { @@ -35,6 +36,9 @@ class CardReaderHubViewModelTest : BaseUnitTest() { private val ippSelectPaymentGateway: IppSelectPaymentGateway = mock() private val countryCode = "US" + private val wcPayPluginVersion = "3.3.0" + private val stripePluginVersion = "6.6.0" + private val savedState = CardReaderHubFragmentArgs( storeCountryCode = countryCode, cardReaderFlowParam = CardReaderFlowParam.CardReadersHub, @@ -103,7 +107,6 @@ class CardReaderHubViewModelTest : BaseUnitTest() { @Test fun `given ipp canada disabled, when user clicks on purchase card reader, then app opens external webview`() { whenever(inPersonPaymentsCanadaFeatureFlag.isEnabled()).thenReturn(false) - initViewModel() (viewModel.viewStateData.value as CardReaderHubViewModel.CardReaderHubViewState.Content).rows .find { @@ -121,7 +124,6 @@ class CardReaderHubViewModelTest : BaseUnitTest() { @Test fun `given ipp canada enabled, when user clicks on purchase card reader, then app opens external webview`() { whenever(inPersonPaymentsCanadaFeatureFlag.isEnabled()).thenReturn(true) - initViewModel() (viewModel.viewStateData.value as CardReaderHubViewModel.CardReaderHubViewState.Content).rows .find { @@ -200,6 +202,22 @@ class CardReaderHubViewModelTest : BaseUnitTest() { ) } + @Test + fun `given payment gateway flag enabled, when multiple plugins installed, then payment provider row is shown`() { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + + initViewModel() + + assertThat((viewModel.viewStateData.value as CardReaderHubViewModel.CardReaderHubViewState.Content).rows) + .anyMatch { + it.label == UiString.UiStringRes(R.string.card_reader_manage_payment_provider) + } + } + private fun initViewModel() { viewModel = CardReaderHubViewModel( savedState, @@ -210,4 +228,20 @@ class CardReaderHubViewModelTest : BaseUnitTest() { ippSelectPaymentGateway ) } + + private fun buildWCPayPluginInfo( + isActive: Boolean = true, + version: String = wcPayPluginVersion + ) = SitePluginModel().apply { + this.version = version + this.setIsActive(isActive) + } + + private fun buildStripeExtensionPluginInfo( + isActive: Boolean = true, + version: String = stripePluginVersion + ) = SitePluginModel().apply { + this.version = version + this.setIsActive(isActive) + } } From e56859aa3a647a1c14547192932b38f7ba3ad9e8 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 27 Jun 2022 18:02:56 +0530 Subject: [PATCH 041/173] Add test to verify that payment provider row is not visible when the ipp payment gateway feature flag is disabled. --- .../cardreader/hub/CardReaderHubViewModelTest.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt index 2a06c2ca6d4..fc614e0e2ca 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt @@ -218,6 +218,22 @@ class CardReaderHubViewModelTest : BaseUnitTest() { } } + @Test + fun `given payment flag disabled, when multiple plugins installed, then payment provider row is not shown`() { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(false) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + + initViewModel() + + assertThat((viewModel.viewStateData.value as CardReaderHubViewModel.CardReaderHubViewState.Content).rows) + .noneMatch { + it.label == UiString.UiStringRes(R.string.card_reader_manage_payment_provider) + } + } + private fun initViewModel() { viewModel = CardReaderHubViewModel( savedState, From 5dba9366d242bde4da90c3babc2b356edb807952 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 27 Jun 2022 18:06:10 +0530 Subject: [PATCH 042/173] Add test to verify that payment provider row is not visible when single plugin is installed and activated --- .../cardreader/hub/CardReaderHubViewModelTest.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt index fc614e0e2ca..cf2f884361f 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt @@ -234,6 +234,21 @@ class CardReaderHubViewModelTest : BaseUnitTest() { } } + @Test + fun `given payment gateway flag enabled, when single plugin installed, then payment provider row is not shown`() { + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = false)) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + + initViewModel() + + assertThat((viewModel.viewStateData.value as CardReaderHubViewModel.CardReaderHubViewState.Content).rows) + .noneMatch { + it.label == UiString.UiStringRes(R.string.card_reader_manage_payment_provider) + } + } + private fun initViewModel() { viewModel = CardReaderHubViewModel( savedState, From 71d529d562f7ce9f95bf5c96431a2a4f67729c72 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Mon, 27 Jun 2022 14:15:09 +0100 Subject: [PATCH 043/173] Remove unused imports --- .../woocommerce/android/ui/shipping/InstallWCShippingScreen.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt index 5a5ccbb96f6..472c1008cc2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt @@ -4,7 +4,6 @@ import android.annotation.SuppressLint import androidx.compose.animation.AnimatedContent import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition -import androidx.compose.animation.ExitTransition.Companion import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.ExperimentalTransitionApi import androidx.compose.animation.core.LinearOutSlowInEasing From 2b3618ba07697109a7a91ce50d11b8ff63be0244 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Mon, 27 Jun 2022 17:20:29 +0100 Subject: [PATCH 044/173] Add animation for the loading indicator --- .../ui/shipping/InstallWCShippingFlow.kt | 143 ++++++++++++++---- 1 file changed, 113 insertions(+), 30 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index 6930d6fd20a..c71e86cb830 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -10,11 +10,16 @@ import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.CubicBezierEasing import androidx.compose.animation.core.ExperimentalTransitionApi import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.infiniteRepeatable +import androidx.compose.animation.core.keyframes +import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInVertically -import androidx.compose.foundation.border +import androidx.compose.foundation.Canvas import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -28,7 +33,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.Icon import androidx.compose.material.IconButton @@ -38,9 +42,19 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.outlined.Info import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.dimensionResource @@ -103,16 +117,13 @@ private fun AnimatedVisibilityScope.PreInstallationContent(viewState: Installati ) ) { SpacerWithMinHeight(1f, dimensionResource(id = R.dimen.major_100)) - Box( - modifier = Modifier - .clip(CircleShape) - .border( - width = dimensionResource(id = R.dimen.major_75), - color = colorResource(id = R.color.woo_purple_20), - shape = CircleShape - ) - .size(dimensionResource(id = R.dimen.image_major_120)) - ) { + Box { + InstallationLoadingIndicator( + showLoadingIndicator = false, + modifier = Modifier + .size(dimensionResource(id = R.dimen.image_major_120)) + ) + Icon( painter = painterResource(id = R.drawable.ic_arrow_forward_rounded), contentDescription = null, @@ -178,25 +189,52 @@ private fun AnimatedVisibilityScope.InstallationContent(viewState: InstallationO // fill equivalent space as the cross-icon Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_300))) SpacerWithMinHeight(1f, dimensionResource(id = R.dimen.major_100)) - Box( - modifier = Modifier - .clip(CircleShape) - .border( - width = dimensionResource(id = R.dimen.major_75), - color = colorResource(id = R.color.woo_purple_20), - shape = CircleShape - ) - .size(dimensionResource(id = R.dimen.image_major_120)) - ) { - Icon( - painter = painterResource(id = R.drawable.ic_arrow_forward_rounded), - contentDescription = null, - tint = colorResource(id = R.color.woo_purple_50), - modifier = Modifier - .align(Alignment.Center) - .size(dimensionResource(id = R.dimen.image_major_64)) + + Box(modifier = Modifier.size(dimensionResource(id = R.dimen.image_major_120))) { + var isCursorVisible by remember { mutableStateOf(true) } + var isShowingLoadingIndicator by remember { mutableStateOf(false) } + + LaunchedEffect(Unit) { + isCursorVisible = false + } + val alpha by animateFloatAsState( + targetValue = if (isCursorVisible) 1f else 0f, + animationSpec = tween(1000, delayMillis = 1000), + finishedListener = { + isShowingLoadingIndicator = true + } ) + val rotation by animateFloatAsState( + targetValue = if (isCursorVisible) 0f else 180f, + animationSpec = keyframes { + if (isCursorVisible) return@keyframes + durationMillis = 2000 + 0f at 1000 + -20f at 1100 + 180f at 2000 + } + ) + + Box { + InstallationLoadingIndicator( + showLoadingIndicator = isShowingLoadingIndicator, + modifier = Modifier + .size(dimensionResource(id = R.dimen.image_major_120)) + ) + + Icon( + painter = painterResource(id = R.drawable.ic_arrow_forward_rounded), + contentDescription = null, + tint = colorResource(id = R.color.woo_purple_50), + modifier = Modifier + .align(Alignment.Center) + .alpha(alpha) + .rotate(rotation) + .size(dimensionResource(id = R.dimen.image_major_64)) + ) + } } + Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_150))) MainContent(viewState) Box(modifier = Modifier.weight(1.5f)) { @@ -284,6 +322,51 @@ private fun ColumnScope.SpacerWithMinHeight(weight: Float, minHeight: Dp) { Spacer(modifier = Modifier.weight(weight)) } +@Composable +private fun InstallationLoadingIndicator(showLoadingIndicator: Boolean, modifier: Modifier = Modifier) { + val stroke = with(LocalDensity.current) { + Stroke(width = dimensionResource(id = R.dimen.major_75).toPx(), cap = StrokeCap.Round) + } + + val circleColor = colorResource(id = R.color.woo_purple_20) + val progressColor = colorResource(id = R.color.woo_purple_50) + + val startAngle by if (showLoadingIndicator) { + val transition = rememberInfiniteTransition() + + transition.animateFloat( + -90f, + 270f, + infiniteRepeatable( + animation = tween(1332, easing = LinearEasing) + ) + ) + } else { + remember { mutableStateOf(-90f) } + } + + Canvas(modifier) { + val size = size.width - stroke.width + + drawCircle( + color = circleColor, + radius = (size) / 2, + style = stroke + ) + if (showLoadingIndicator) { + drawArc( + color = progressColor, + startAngle = startAngle, + sweepAngle = 30f, + useCenter = false, + size = Size(size, size), + topLeft = Offset(stroke.width / 2, stroke.width / 2), + style = stroke + ) + } + } +} + @Preview @Composable private fun PreInstallationPreview() { From 946f23a5c85af03ba311bd626b59a7e52c0cc058 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Mon, 27 Jun 2022 18:28:14 +0100 Subject: [PATCH 045/173] Improve the extension and site name animation --- .../ui/shipping/InstallWCShippingFlow.kt | 59 +++++++++++-------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index c71e86cb830..cb90eb94862 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -46,6 +46,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -135,20 +136,18 @@ private fun AnimatedVisibilityScope.PreInstallationContent(viewState: Installati } Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_150))) MainContent(viewState) - Box( - modifier = Modifier.weight(1.5f), - contentAlignment = Alignment.Center - ) { - InstallationInfoLink( - onClick = viewState.onInfoClick, - modifier = Modifier - .padding(vertical = dimensionResource(id = R.dimen.major_100)) - .animateEnterExit( - enter = EnterTransition.None, - exit = fadeOut(tween(500)) - ) - ) - } + SpacerWithMinHeight(0.75f, dimensionResource(id = R.dimen.major_100)) + + InstallationInfoLink( + onClick = viewState.onInfoClick, + modifier = Modifier + .animateEnterExit( + enter = EnterTransition.None, + exit = fadeOut(tween(500)) + ) + ) + + SpacerWithMinHeight(0.75f, dimensionResource(id = R.dimen.major_100)) } (viewState as? PreInstallation)?.let { WCColoredButton( @@ -181,6 +180,7 @@ private fun AnimatedVisibilityScope.InstallationContent(viewState: InstallationO verticalArrangement = Arrangement.Center, modifier = Modifier .fillMaxSize() + .verticalScroll(rememberScrollState()) .padding( horizontal = dimensionResource(id = R.dimen.major_100), vertical = dimensionResource(id = R.dimen.major_150) @@ -191,8 +191,8 @@ private fun AnimatedVisibilityScope.InstallationContent(viewState: InstallationO SpacerWithMinHeight(1f, dimensionResource(id = R.dimen.major_100)) Box(modifier = Modifier.size(dimensionResource(id = R.dimen.image_major_120))) { - var isCursorVisible by remember { mutableStateOf(true) } - var isShowingLoadingIndicator by remember { mutableStateOf(false) } + var isCursorVisible by rememberSaveable { mutableStateOf(true) } + var isShowingLoadingIndicator by rememberSaveable { mutableStateOf(false) } LaunchedEffect(Unit) { isCursorVisible = false @@ -237,15 +237,14 @@ private fun AnimatedVisibilityScope.InstallationContent(viewState: InstallationO Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_150))) MainContent(viewState) - Box(modifier = Modifier.weight(1.5f)) { - Text( - text = viewState.siteUrl, - style = MaterialTheme.typography.body1, - modifier = Modifier - .padding(vertical = dimensionResource(id = R.dimen.major_100)) - .animateEnterExit(enter = fadeIn(tween(400, delayMillis = 600), initialAlpha = 0.5f)) - ) - } + Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_125))) + Text( + text = viewState.siteUrl, + style = MaterialTheme.typography.body1, + modifier = Modifier + .animateEnterExit(enter = fadeIn(tween(400, delayMillis = 600), initialAlpha = 0.5f)) + ) + SpacerWithMinHeight(1.5f, dimensionResource(id = R.dimen.major_100)) // fill equivalent space as the proceed-button Spacer(modifier = Modifier.height(dimensionResource(id = R.dimen.major_300))) } @@ -275,7 +274,15 @@ private fun AnimatedVisibilityScope.MainContent(viewState: InstallationState) { // Animate the extension and site names when starting the installation val extensionAndNameModifier = Modifier.animateEnterExit( enter = if (viewState is InstallationOngoing) { - fadeIn(tween(200, delayMillis = 800, easing = LinearEasing), initialAlpha = 0.5f) + fadeIn( + keyframes { + durationMillis = 1000 + 1f at 0 + 0.5f at 200 + 0.5f at 800 + 1f at 1000 + } + ) } else EnterTransition.None, exit = ExitTransition.None ) From 939d6cd96d90610c4f7d71be6b2e91c45cc2693f Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Mon, 27 Jun 2022 18:54:25 +0100 Subject: [PATCH 046/173] Remove the usages of the rememberSaveable It causes issues as the value is remembered beyond the scope of the step itself --- .../woocommerce/android/ui/shipping/InstallWCShippingFlow.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index cb90eb94862..5e706349135 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -46,7 +46,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -191,8 +190,8 @@ private fun AnimatedVisibilityScope.InstallationContent(viewState: InstallationO SpacerWithMinHeight(1f, dimensionResource(id = R.dimen.major_100)) Box(modifier = Modifier.size(dimensionResource(id = R.dimen.image_major_120))) { - var isCursorVisible by rememberSaveable { mutableStateOf(true) } - var isShowingLoadingIndicator by rememberSaveable { mutableStateOf(false) } + var isCursorVisible by remember { mutableStateOf(true) } + var isShowingLoadingIndicator by remember { mutableStateOf(false) } LaunchedEffect(Unit) { isCursorVisible = false From 416ed0e3d7221e89f9fcd859d3b201bfc282ec4e Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Mon, 27 Jun 2022 19:11:31 +0100 Subject: [PATCH 047/173] Link arrow animations to the transition This avoid restarting them on screen rotation --- .../ui/shipping/InstallWCShippingFlow.kt | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index 5e706349135..172e7a4cfee 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -4,6 +4,7 @@ package com.woocommerce.android.ui.shipping import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedVisibilityScope +import androidx.compose.animation.EnterExitState.PreEnter import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition import androidx.compose.animation.ExperimentalAnimationApi @@ -11,7 +12,6 @@ import androidx.compose.animation.core.CubicBezierEasing import androidx.compose.animation.core.ExperimentalTransitionApi import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.animateFloat -import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.infiniteRepeatable import androidx.compose.animation.core.keyframes import androidx.compose.animation.core.rememberInfiniteTransition @@ -42,11 +42,10 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.outlined.Info import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha @@ -190,29 +189,33 @@ private fun AnimatedVisibilityScope.InstallationContent(viewState: InstallationO SpacerWithMinHeight(1f, dimensionResource(id = R.dimen.major_100)) Box(modifier = Modifier.size(dimensionResource(id = R.dimen.image_major_120))) { - var isCursorVisible by remember { mutableStateOf(true) } - var isShowingLoadingIndicator by remember { mutableStateOf(false) } - - LaunchedEffect(Unit) { - isCursorVisible = false - } - val alpha by animateFloatAsState( - targetValue = if (isCursorVisible) 1f else 0f, - animationSpec = tween(1000, delayMillis = 1000), - finishedListener = { - isShowingLoadingIndicator = true + val alpha by transition.animateFloat( + transitionSpec = { tween(1000, delayMillis = 1000) }, + label = "arrowAlpha" + ) { + when (it) { + PreEnter -> 1f + else -> 0f } - ) - val rotation by animateFloatAsState( - targetValue = if (isCursorVisible) 0f else 180f, - animationSpec = keyframes { - if (isCursorVisible) return@keyframes - durationMillis = 2000 - 0f at 1000 - -20f at 1100 - 180f at 2000 + } + + val rotation by transition.animateFloat( + transitionSpec = { + keyframes { + durationMillis = 2000 + 0f at 1000 + -20f at 1100 + 180f at 2000 + } + }, + label = "arrowAlpha" + ) { + when (it) { + PreEnter -> 0f + else -> 180f } - ) + } + val isShowingLoadingIndicator by derivedStateOf { alpha == 0f } Box { InstallationLoadingIndicator( From 60598996a1c9e652121ff9d7bcc12b00aa8eebef Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 27 Jun 2022 16:01:24 -0400 Subject: [PATCH 048/173] Include role="all" in the search customers request --- .../ui/orders/creation/customerlist/CustomerListRepository.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/customerlist/CustomerListRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/customerlist/CustomerListRepository.kt index ce1647a608e..e37c473413b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/customerlist/CustomerListRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/customerlist/CustomerListRepository.kt @@ -44,7 +44,8 @@ class CustomerListRepository @Inject constructor( ): List? = customerStore.fetchCustomers( site = selectedSite.get(), - searchQuery = searchQuery + searchQuery = searchQuery, + role = "all" ).takeUnless { it.isError }?.model fun getCustomerByRemoteId(remoteId: Long): WCCustomerModel? = From 6e250573e9ff923acabec9189d0a82bf1eaee68c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 09:14:48 +0000 Subject: [PATCH 049/173] Bump mockito-inline from 4.5.1 to 4.6.1 Bumps [mockito-inline](https://github.com/mockito/mockito) from 4.5.1 to 4.6.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v4.5.1...v4.6.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-inline dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f95deae0134..e2b143e403b 100644 --- a/build.gradle +++ b/build.gradle @@ -116,7 +116,7 @@ ext { assertjVersion = '3.11.1' espressoVersion = '3.4.0' mockitoKotlinVersion = '4.0.0' - mockitoVersion = '4.5.1' + mockitoVersion = '4.6.1' } // Onboarding and dev env setup tasks From 51ac13dd7f7bc7ef751c8555ac3811c3777b29a9 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Tue, 28 Jun 2022 15:44:02 +0300 Subject: [PATCH 050/173] Analysis: Enable all warnings as errors for quick login module This 'allWarningsAsErrors' configuration is currently applied on the module level in order to make sure that, as the overall 'Kotlin Warnings as Errors' work is progressing, no new warnings are added to this module, which is already free of warnings. When the overall 'Kotlin Warnings as Errors' work is complete on all modules, then this module level 'allWarningsAsErrors' configuration will be replaced by a root level 'allWarningsAsErrors' configuration that will be applied by default to all modules from there after. --- quicklogin/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/quicklogin/build.gradle b/quicklogin/build.gradle index 3dfcaceaf1f..0dff2e639b9 100644 --- a/quicklogin/build.gradle +++ b/quicklogin/build.gradle @@ -65,6 +65,9 @@ android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 + kotlinOptions { + allWarningsAsErrors = true + } } kotlinOptions { jvmTarget = '1.8' From 3e3c5d290b9a01ffddd52d3bddceeb7def034228 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 28 Jun 2022 12:16:48 -0400 Subject: [PATCH 051/173] Added analytics events for customer search --- .../com/woocommerce/android/analytics/AnalyticsEvent.kt | 2 ++ .../ui/orders/creation/customerlist/CustomerListViewModel.kt | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt index 05a15d99663..eec15138f9b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt @@ -195,6 +195,8 @@ enum class AnalyticsEvent(val siteless: Boolean = false) { ORDER_CREATION_SUCCESS, ORDER_CREATION_FAILED, ORDER_SYNC_FAILED, + ORDER_CREATION_CUSTOMER_SEARCH, + ORDER_CREATION_CUSTOMER_ADDED, // -- Refunds CREATE_ORDER_REFUND_NEXT_BUTTON_TAPPED, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/customerlist/CustomerListViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/customerlist/CustomerListViewModel.kt index 327b7b75764..1811a59877e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/customerlist/CustomerListViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/customerlist/CustomerListViewModel.kt @@ -6,6 +6,8 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import com.woocommerce.android.AppConstants import com.woocommerce.android.R +import com.woocommerce.android.analytics.AnalyticsEvent +import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.model.Address import com.woocommerce.android.model.AmbiguousLocation import com.woocommerce.android.model.Location @@ -41,6 +43,7 @@ class CustomerListViewModel @Inject constructor( } fun onCustomerClick(customerRemoteId: Long) { + AnalyticsTracker.track(AnalyticsEvent.ORDER_CREATION_CUSTOMER_ADDED) launch { customerListRepository.getCustomerByRemoteId(customerRemoteId)?.let { wcCustomer -> val shippingAddress = OrderAddress.Shipping( @@ -115,6 +118,7 @@ class CustomerListViewModel @Inject constructor( searchJob?.cancel() searchJob = launch { delay(AppConstants.SEARCH_TYPING_DELAY_MS) + AnalyticsTracker.track(AnalyticsEvent.ORDER_CREATION_CUSTOMER_SEARCH) searchCustomerList(query) } } else { From 506951ceab83dc1d1afca0cdb2377470e9877d89 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 28 Jun 2022 12:21:28 -0400 Subject: [PATCH 052/173] Enable customer search in release builds --- .../main/kotlin/com/woocommerce/android/util/FeatureFlag.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt index 08ef598a75d..4d4ecb89bf4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt @@ -30,9 +30,8 @@ enum class FeatureFlag { WC_SHIPPING_BANNER, IPP_SELECT_PAYMENT_GATEWAY, UNIFIED_ORDER_EDITING -> PackageUtils.isDebugBuild() - // order creation customer search is awaiting backend changes before being enabled ORDER_CREATION_CUSTOMER_SEARCH -> { - UNIFIED_ORDER_EDITING.isEnabled() && PackageUtils.isDebugBuild() + UNIFIED_ORDER_EDITING.isEnabled() } } } From 3df5ab6da51510b827564d3a2e964fb872a559d2 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 28 Jun 2022 19:05:52 -0400 Subject: [PATCH 053/173] Introduce new state showPaymentPluginSelectionState to the Fragment --- .../CardReaderOnboardingFragment.kt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt index 014f1e10cc4..a13a35f201e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt @@ -13,6 +13,7 @@ import com.woocommerce.android.databinding.FragmentCardReaderOnboardingBothPlugi import com.woocommerce.android.databinding.FragmentCardReaderOnboardingGenericErrorBinding import com.woocommerce.android.databinding.FragmentCardReaderOnboardingLoadingBinding import com.woocommerce.android.databinding.FragmentCardReaderOnboardingNetworkErrorBinding +import com.woocommerce.android.databinding.FragmentCardReaderOnboardingSelectPaymentGatewayBinding import com.woocommerce.android.databinding.FragmentCardReaderOnboardingStripeBinding import com.woocommerce.android.databinding.FragmentCardReaderOnboardingUnsupportedBinding import com.woocommerce.android.databinding.FragmentCardReaderOnboardingWcpayBinding @@ -106,9 +107,35 @@ class CardReaderOnboardingFragment : BaseFragment(R.layout.fragment_card_reader_ showStripeExtensionErrorState(layout, state) is CardReaderOnboardingViewModel.OnboardingViewState.WcPayAndStripeInstalledState -> showBothPluginsInstalledState(layout, state) + is CardReaderOnboardingViewModel.OnboardingViewState.SelectPaymentPluginState -> + showPaymentPluginSelectionState(layout,state) }.exhaustive } + private fun showPaymentPluginSelectionState( + view: View, + state: CardReaderOnboardingViewModel.OnboardingViewState.SelectPaymentPluginState + ) { + val binding = FragmentCardReaderOnboardingSelectPaymentGatewayBinding.bind(view) + UiHelpers.setTextOrHide(binding.textHeader, state.headerLabel) + UiHelpers.setTextOrHide(binding.hintLabel, state.hintLabel) + UiHelpers.setImageOrHideInLandscape(binding.cardIllustration, state.cardIllustration) + UiHelpers.setImageOrHideInLandscape(binding.icSelectWcPay, state.icWcPayLogo) + UiHelpers.setImageOrHideInLandscape(binding.icCheckmarkWcPay, state.icCheckmarkWcPay) + UiHelpers.setImageOrHideInLandscape(binding.icSelectStripe, state.icStripeLogo) + UiHelpers.setImageOrHideInLandscape(binding.icCheckmarkStripe, state.icCheckmarkStripe) + + binding.selectWcPayButton.setOnClickListener { + state.onWcPayOptionClicked.invoke() + } + binding.selectStripeButton.setOnClickListener { + state.onStripeOptionClicked.invoke() + } + binding.confirmPaymentMethod.setOnClickListener { + state.onConfirmPaymentMethodClicked.invoke() + } + } + private fun showBothPluginsInstalledState( view: View, state: CardReaderOnboardingViewModel.OnboardingViewState.WcPayAndStripeInstalledState From a72b4f756a5463dcd2dfb733b9d2680eb38802e1 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 28 Jun 2022 19:06:50 -0400 Subject: [PATCH 054/173] Connect Screen to the VM --- .../CardReaderOnboardingViewModel.kt | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index 6d5ddddb738..f0896f0fcbb 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -200,10 +200,30 @@ class CardReaderOnboardingViewModel @Inject constructor( ::onLearnMoreClicked ) WcpayAndStripeActivated -> updateUiWithWcPayAndStripeActivated() - ChoosePaymentGatewayProvider -> TODO() + ChoosePaymentGatewayProvider -> updateUiWithSelectPaymentPlugin() }.exhaustive } + private fun updateUiWithSelectPaymentPlugin() { + launch { + val userInfo = userEligibilityFetcher.fetchUserInfo() + val canManagePlugins = userInfo?.getUserRoles()?.contains(ADMINISTRATOR) ?: false + + viewState.value = + OnboardingViewState.SelectPaymentPluginState( + hintLabel = if (canManagePlugins) { + UiString.UiStringRes(R.string.card_reader_onboarding_both_plugins_activated_hint_admin) + } else { + UiString.UiStringRes(R.string.card_reader_onboarding_both_plugins_activated_hint_store_owner) + }, + onWcPayOptionClicked = ::onContactSupportClicked, + onStripeOptionClicked = ::onLearnMoreClicked, + onConfirmPaymentMethodClicked = ::refreshState + ) + } + } + + private fun updateUiWithWcPayAndStripeActivated() { launch { val userInfo = userEligibilityFetcher.fetchUserInfo() @@ -312,6 +332,27 @@ class CardReaderOnboardingViewModel @Inject constructor( val illustration = R.drawable.img_products_error } + data class SelectPaymentPluginState( + val hintLabel: UiString, + val onWcPayOptionClicked: (() -> Unit), + val onStripeOptionClicked: (() -> Unit), + val onConfirmPaymentMethodClicked: (() -> Unit), + ) : OnboardingViewState(R.layout.fragment_card_reader_onboarding_select_payment_gateway) { + val cardIllustration = R.drawable.ic_credit_card_give + val headerLabel = UiString.UiStringRes(R.string.card_reader_onboarding_choose_payment_provider) + val choosePluginHintLabel = UiString.UiStringRes(R.string.card_reader_onboarding_choose_plugin_hint) + + val selectWcPayButtonLabel = UiString.UiStringRes(R.string.card_reader_onboarding_choose_wcpayment_button) + val icWcPayLogo = R.drawable.ic_wcpay + val icCheckmarkWcPay = R.drawable.ic_menu_action_mode_check + val selectStripeButtonLabel = UiString.UiStringRes(R.string.card_reader_onboarding_choose_stripe_button) + val icStripeLogo = R.drawable.ic_stripe + val icCheckmarkStripe = R.drawable.ic_menu_action_mode_check + val confirmPaymentMethodButtonLabel = UiString + .UiStringRes(R.string.card_reader_onboarding_confirm_payment_method_button) + + } + data class WcPayAndStripeInstalledState( val hintLabel: UiString, val onContactSupportActionClicked: (() -> Unit), From a29fd08d59296d23789e993b008e40d5d4d92805 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 29 Jun 2022 09:09:13 +0530 Subject: [PATCH 055/173] Add payment provider svg --- .../src/main/res/drawable/ic_payment_provider.xml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 WooCommerce/src/main/res/drawable/ic_payment_provider.xml diff --git a/WooCommerce/src/main/res/drawable/ic_payment_provider.xml b/WooCommerce/src/main/res/drawable/ic_payment_provider.xml new file mode 100644 index 00000000000..f9e8668b802 --- /dev/null +++ b/WooCommerce/src/main/res/drawable/ic_payment_provider.xml @@ -0,0 +1,9 @@ + + + From 814789d2abff154d152609194a351ca7685d7c66 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 29 Jun 2022 09:09:43 +0530 Subject: [PATCH 056/173] replace with proper icon and proper click listener for payment provider row --- .../android/ui/cardreader/hub/CardReaderHubViewModel.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt index fe5dfac422e..f4a85aee757 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt @@ -54,9 +54,9 @@ class CardReaderHubViewModel @Inject constructor( private val cardReaderHubListWhenMultiplePluginsInstalled = cardReaderHubListWhenSinglePluginInstalled + mutableListOf( CardReaderHubListItemViewState( - icon = R.drawable.ic_card_reader_manual, + icon = R.drawable.ic_payment_provider, label = UiString.UiStringRes(R.string.card_reader_manage_payment_provider), - onItemClicked = ::onCardReaderManualsClicked + onItemClicked = ::onCardReaderPaymentProviderClicked ) ) @@ -113,6 +113,10 @@ class CardReaderHubViewModel @Inject constructor( triggerEvent(CardReaderHubEvents.NavigateToCardReaderManualsScreen) } + private fun onCardReaderPaymentProviderClicked() { + TODO("Not Implemented") + } + sealed class CardReaderHubEvents : MultiLiveEvent.Event() { data class NavigateToCardReaderDetail(val cardReaderFlowParam: CardReaderFlowParam) : CardReaderHubEvents() data class NavigateToPurchaseCardReaderFlow(val url: String) : CardReaderHubEvents() From 4328a60ccfd6401f85886d9ed0a0f01ce10ccace Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 29 Jun 2022 09:23:38 +0530 Subject: [PATCH 057/173] Add test to verify payment provider icon is shown --- .../cardreader/hub/CardReaderHubViewModelTest.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt index cf2f884361f..18628fffc9f 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt @@ -218,6 +218,22 @@ class CardReaderHubViewModelTest : BaseUnitTest() { } } + @Test + fun `given payment gateway flag enabled, when multiple plugins installed, then payment provider icon is shown`() { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + + initViewModel() + + assertThat((viewModel.viewStateData.value as CardReaderHubViewModel.CardReaderHubViewState.Content).rows) + .anyMatch { + it.icon == R.drawable.ic_payment_provider + } + } + @Test fun `given payment flag disabled, when multiple plugins installed, then payment provider row is not shown`() { whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(false) From 03596b4bf00184810b72416c750715608387c6dc Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 29 Jun 2022 09:24:01 +0530 Subject: [PATCH 058/173] Add test to verify payment provider when clicked, throws NotImplementedError --- .../cardreader/hub/CardReaderHubViewModelTest.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt index 18628fffc9f..dd65a7ccf8c 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt @@ -234,6 +234,21 @@ class CardReaderHubViewModelTest : BaseUnitTest() { } } + @Test(expected = NotImplementedError::class) + fun `given multiple plugins installed, when payment provider clicked, then throw exception`() { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + + initViewModel() + (viewModel.viewStateData.value as CardReaderHubViewModel.CardReaderHubViewState.Content).rows + .find { + it.label == UiString.UiStringRes(R.string.card_reader_manage_payment_provider) + }!!.onItemClicked.invoke() + } + @Test fun `given payment flag disabled, when multiple plugins installed, then payment provider row is not shown`() { whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(false) From 9549771dbd8233f11c601bd8b3190e0b4324eb11 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 29 Jun 2022 11:54:39 +0530 Subject: [PATCH 059/173] refactor test --- .../com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt index 8ba67fbe5cf..b5a43daf691 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt @@ -333,7 +333,7 @@ class MyStoreViewModelTest : BaseUnitTest() { ) ) - sut.onStatsGranularityChanged(ANY_SELECTED_STATS_GRANULARITY) + whenViewModelIsCreated() (sut.topPerformersState.value as MyStoreViewModel.TopPerformersViewState.Content) .topPerformers[0].onClick.invoke(1L) From 55624175f81c92ca8365a3ce2068ff7ed996fdb8 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Wed, 29 Jun 2022 11:56:52 +0530 Subject: [PATCH 060/173] remove unnecessary code --- .../com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt index b5a43daf691..72a05e26162 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/MyStoreViewModelTest.kt @@ -323,7 +323,6 @@ class MyStoreViewModelTest : BaseUnitTest() { } givenCurrencyFormatter(BigDecimal("0.0"), "USD") givenResourceProvider() - whenViewModelIsCreated() givenNetworkConnectivity(connected = true) givenToPerformersResult( GetTopPerformers.TopPerformersResult.TopPerformersSuccess( From 619a9b71ecaa3ba5ed6de74a0cdfd874158db0e9 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 29 Jun 2022 10:55:33 +0100 Subject: [PATCH 061/173] Fix usage of the modifier argument --- .../woocommerce/android/ui/shipping/InstallWCShippingFlow.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index 172e7a4cfee..ef62224da1e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -309,7 +309,7 @@ private fun AnimatedVisibilityScope.MainContent(viewState: InstallationState) { private fun InstallationInfoLink(onClick: () -> Unit, modifier: Modifier = Modifier) { Row( horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.minor_100)), - modifier = Modifier + modifier = modifier .clickable(onClick = onClick) ) { Icon( From 0fbd272112c9474652c55e0f3fc7fa236fbef75c Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 29 Jun 2022 10:58:27 +0100 Subject: [PATCH 062/173] Cleanup the usages of the OptIn --- .../woocommerce/android/ui/shipping/InstallWCShippingFlow.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index ef62224da1e..98d1964da3e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -1,5 +1,4 @@ @file:OptIn(ExperimentalAnimationApi::class) - package com.woocommerce.android.ui.shipping import androidx.compose.animation.AnimatedContent @@ -9,7 +8,6 @@ import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.CubicBezierEasing -import androidx.compose.animation.core.ExperimentalTransitionApi import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.infiniteRepeatable @@ -70,7 +68,6 @@ import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState. import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.InstallationState.InstallationOngoing import com.woocommerce.android.ui.shipping.InstallWCShippingViewModel.ViewState.InstallationState.PreInstallation -@OptIn(ExperimentalTransitionApi::class) @Composable fun AnimatedVisibilityScope.InstallWCShippingFlow(viewState: InstallationState) { when (viewState) { @@ -252,7 +249,6 @@ private fun AnimatedVisibilityScope.InstallationContent(viewState: InstallationO } } -@OptIn(ExperimentalAnimationApi::class) @Composable private fun AnimatedVisibilityScope.MainContent(viewState: InstallationState) { Column { From 3d3b43cd43607b7094d0ebf26bf3e589da2b5b5b Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 29 Jun 2022 11:06:19 -0300 Subject: [PATCH 063/173] change sync strategy based on flow --- .../ui/orders/creation/AutoSyncOrder.kt | 69 ++++++++++++++++++ .../orders/creation/AutoSyncPriceModifier.kt | 72 +++++++++++++++++++ .../ui/orders/creation/CreateUpdateOrder.kt | 57 +++++++++++++++ .../orders/creation/OrderCreationViewModel.kt | 6 ++ 4 files changed, 204 insertions(+) create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt new file mode 100644 index 00000000000..738c0ee18c9 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt @@ -0,0 +1,69 @@ +package com.woocommerce.android.ui.orders.creation + +import com.woocommerce.android.extensions.areSameAs +import com.woocommerce.android.extensions.isEqualTo +import com.woocommerce.android.model.Order +import com.woocommerce.android.util.CoroutineDispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import javax.inject.Inject + +class AutoSyncOrder @Inject constructor( + dispatchers: CoroutineDispatchers, + orderCreationRepository: OrderCreationRepository +) : CreateUpdateOrder(dispatchers, orderCreationRepository) { + private fun areEquivalent(old: Order, new: Order): Boolean { + // Make sure to update the prices only when items did change + val hasSameItems = old.items + .filter { + // Check only non-zero quantities, to avoid circular update when removing products + it.quantity > 0 + } + .areSameAs(new.items) { newItem -> + // TODO M3: we need probably to compare the totals too, to account for discounts + this.productId == newItem.productId && + this.variationId == newItem.variationId && + this.quantity == newItem.quantity + } + + val hasSameShippingLines = old.shippingLines + .filter { + // Check only non-removed shipping lines to avoid circular update when removing + it.methodId != null + } + .areSameAs(new.shippingLines) { newLine -> + this.methodId == newLine.methodId && + this.methodTitle == newLine.methodTitle && + this.total isEqualTo newLine.total + } + + val hasSameFeeLines = old.feesLines + .filter { it.name != null } + .areSameAs(new.feesLines) { newLine -> + this.name == newLine.name && + this.total isEqualTo newLine.total + } + + val hasSameStatus = old.status == new.status + + val hasSameCustomerInfo = old.billingAddress == new.billingAddress && + old.shippingAddress == new.shippingAddress && + old.customerNote == new.customerNote && + old.shippingPhone == new.shippingPhone + + return hasSameItems && + hasSameShippingLines && + hasSameFeeLines && + hasSameStatus && + hasSameCustomerInfo + } + + @OptIn(ExperimentalCoroutinesApi::class) + override fun invoke(changes: Flow, retryTrigger: Flow): Flow { + return super.invoke( + changes.distinctUntilChanged(::areEquivalent), + retryTrigger + ) + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt new file mode 100644 index 00000000000..a2fb1b0c6d0 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt @@ -0,0 +1,72 @@ +package com.woocommerce.android.ui.orders.creation + +import com.woocommerce.android.extensions.areSameAs +import com.woocommerce.android.extensions.isEqualTo +import com.woocommerce.android.model.Order +import com.woocommerce.android.util.CoroutineDispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import javax.inject.Inject + +class AutoSyncPriceModifier @Inject constructor( + dispatchers: CoroutineDispatchers, + orderCreationRepository: OrderCreationRepository +) : CreateUpdateOrder(dispatchers, orderCreationRepository) { + /** + * Anything that can be modified during the Order Creation flow that can affect + * the Order total price should be accounted here + */ + private fun Order.containsPriceModifiers() = + items.isNotEmpty() || feesLines.isNotEmpty() || shippingLines.isNotEmpty() + + private fun arePriceModifiersEquivalent(old: Order, new: Order): Boolean { + // Make sure to update the prices only when items did change + val hasSameItems = old.items + .filter { + // Check only non-zero quantities, to avoid circular update when removing products + it.quantity > 0 + } + .areSameAs(new.items) { newItem -> + // TODO M3: we need probably to compare the totals too, to account for discounts + this.productId == newItem.productId && + this.variationId == newItem.variationId && + this.quantity == newItem.quantity + } + + val hasSameShippingLines = old.shippingLines + .filter { + // Check only non-removed shipping lines to avoid circular update when removing + it.methodId != null + } + .areSameAs(new.shippingLines) { newLine -> + this.methodId == newLine.methodId && + this.methodTitle == newLine.methodTitle && + this.total isEqualTo newLine.total + } + + val hasSameFeeLines = old.feesLines + .filter { it.name != null } + .areSameAs(new.feesLines) { newLine -> + this.name == newLine.name && + this.total isEqualTo newLine.total + } + + return hasSameItems && + hasSameShippingLines && + hasSameFeeLines && + old.shippingAddress.isSamePhysicalAddress(new.shippingAddress) && + old.billingAddress.isSamePhysicalAddress(new.billingAddress) + } + + @OptIn(ExperimentalCoroutinesApi::class) + override fun invoke(changes: Flow, retryTrigger: Flow): Flow { + return super.invoke( + changes + .filter { it.containsPriceModifiers() } + .distinctUntilChanged(::arePriceModifiersEquivalent), + retryTrigger + ) + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt new file mode 100644 index 00000000000..cab4b4149a9 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt @@ -0,0 +1,57 @@ +package com.woocommerce.android.ui.orders.creation + +import com.woocommerce.android.model.Order +import com.woocommerce.android.util.CoroutineDispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.onStart + +open class CreateUpdateOrder( + protected val dispatchers: CoroutineDispatchers, + protected val orderCreationRepository: OrderCreationRepository +) { + companion object { + const val DEBOUNCE_DURATION_MS = 500L + } + + private fun createOrUpdateDraft(order: Order) = flow { + emit(OrderUpdateStatus.Ongoing) + orderCreationRepository.createOrUpdateDraft(order) + .fold( + onSuccess = { emit(OrderUpdateStatus.Succeeded(it)) }, + onFailure = { emit(OrderUpdateStatus.Failed) } + ) + } + + sealed interface OrderUpdateStatus { + object PendingDebounce : OrderUpdateStatus + object Ongoing : OrderUpdateStatus + data class Succeeded(val order: Order) : OrderUpdateStatus + object Failed : OrderUpdateStatus + } + + @OptIn(ExperimentalCoroutinesApi::class) + open operator fun invoke(changes: Flow, retryTrigger: Flow): Flow { + return changes + .flowOn(dispatchers.computation) + .flatMapLatest { + val debouncedChanges = flow { + // We can't use `debounce` directly, because we want to cancel any current update + // when we get new changes, hence the use of `flatMapLatest` + `delay` + delay(DEBOUNCE_DURATION_MS) + emit(it) + } + debouncedChanges + .combine(retryTrigger.onStart { emit(Unit) }) { draft, _ -> draft } + .flatMapLatest { createOrUpdateDraft(it) } + .onStart { emit(OrderUpdateStatus.PendingDebounce) } + .distinctUntilChanged() + } + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt index 3599c41f113..8852b256b49 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt @@ -105,6 +105,12 @@ class OrderCreationViewModel @Inject constructor( private val retryOrderDraftUpdateTrigger = MutableSharedFlow(extraBufferCapacity = 1) + private val createOrUpdateOrder = + when (mode) { + Mode.Creation -> AutoSyncPriceModifier(dispatchers, orderCreationRepository) + is Mode.Edit -> AutoSyncOrder(dispatchers, orderCreationRepository) + } + fun getProductUIModelFromItem(item: Order.Item) = runBlocking { mapItemToProductUiModel(item) } From 43a98ade7a6c61811dfb91ef9ae4149c56e9bd51 Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 29 Jun 2022 11:07:24 -0300 Subject: [PATCH 064/173] fix unit tests --- .../orders/creation/OrderCreationViewModel.kt | 49 +++++++++-------- ...raftTests.kt => CreateUpdateOrderTests.kt} | 30 +++++------ ...eationFocusedOrderCreationViewModelTest.kt | 52 +++++-------------- .../EditFocusedOrderCreationViewModelTest.kt | 15 ++---- .../creation/UnifiedOrderEditViewModelTest.kt | 11 ++-- 5 files changed, 61 insertions(+), 96 deletions(-) rename WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/{CreateOrUpdateOrderDraftTests.kt => CreateUpdateOrderTests.kt} (76%) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt index 8852b256b49..5b61f662077 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt @@ -1,6 +1,7 @@ package com.woocommerce.android.ui.orders.creation import android.os.Parcelable +import androidx.annotation.VisibleForTesting import androidx.lifecycle.LiveData import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asLiveData @@ -28,7 +29,7 @@ import com.woocommerce.android.model.Order import com.woocommerce.android.model.Order.OrderStatus import com.woocommerce.android.model.Order.ShippingLine import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewOrderStatusSelector -import com.woocommerce.android.ui.orders.creation.CreateOrUpdateOrderDraft.OrderDraftUpdateStatus +import com.woocommerce.android.ui.orders.creation.CreateUpdateOrder.OrderUpdateStatus import com.woocommerce.android.ui.orders.creation.navigation.OrderCreationNavigationTarget.AddProduct import com.woocommerce.android.ui.orders.creation.navigation.OrderCreationNavigationTarget.EditCustomer import com.woocommerce.android.ui.orders.creation.navigation.OrderCreationNavigationTarget.EditCustomerNote @@ -68,7 +69,6 @@ class OrderCreationViewModel @Inject constructor( private val orderDetailRepository: OrderDetailRepository, private val orderCreationRepository: OrderCreationRepository, private val mapItemToProductUiModel: MapItemToProductUiModel, - private val createOrUpdateOrderDraft: CreateOrUpdateOrderDraft, private val createOrderItem: CreateOrderItem, parameterRepository: ParameterRepository ) : ScopedViewModel(savedState) { @@ -299,28 +299,31 @@ class OrderCreationViewModel @Inject constructor( */ private fun monitorOrderChanges() { viewModelScope.launch { - createOrUpdateOrderDraft(_orderDraft.drop(1), retryOrderDraftUpdateTrigger) - .collect { updateStatus -> - when (updateStatus) { - OrderDraftUpdateStatus.PendingDebounce -> - viewState = viewState.copy(willUpdateOrderDraft = true, showOrderUpdateSnackbar = false) - OrderDraftUpdateStatus.Ongoing -> - viewState = viewState.copy(willUpdateOrderDraft = false, isUpdatingOrderDraft = true) - OrderDraftUpdateStatus.Failed -> - viewState = viewState.copy(isUpdatingOrderDraft = false, showOrderUpdateSnackbar = true) - is OrderDraftUpdateStatus.Succeeded -> { - viewState = viewState.copy( - isUpdatingOrderDraft = false, - showOrderUpdateSnackbar = false, - isEditable = updateStatus.order.isEditable || mode is Mode.Creation - ) - _orderDraft.update { currentDraft -> - // Keep the user's selected status - updateStatus.order.copy(status = currentDraft.status) - } - } - } + createOrUpdateOrder(_orderDraft.drop(1), retryOrderDraftUpdateTrigger) + .collect { updateStatus -> onOrderStatusChange(updateStatus) } + } + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + fun onOrderStatusChange(updateStatus: OrderUpdateStatus) { + when (updateStatus) { + OrderUpdateStatus.PendingDebounce -> + viewState = viewState.copy(willUpdateOrderDraft = true, showOrderUpdateSnackbar = false) + OrderUpdateStatus.Ongoing -> + viewState = viewState.copy(willUpdateOrderDraft = false, isUpdatingOrderDraft = true) + OrderUpdateStatus.Failed -> + viewState = viewState.copy(isUpdatingOrderDraft = false, showOrderUpdateSnackbar = true) + is OrderUpdateStatus.Succeeded -> { + viewState = viewState.copy( + isUpdatingOrderDraft = false, + showOrderUpdateSnackbar = false, + isEditable = updateStatus.order.isEditable || mode is Mode.Creation + ) + _orderDraft.update { currentDraft -> + // Keep the user's selected status + updateStatus.order.copy(status = currentDraft.status) } + } } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreateOrUpdateOrderDraftTests.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrderTests.kt similarity index 76% rename from WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreateOrUpdateOrderDraftTests.kt rename to WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrderTests.kt index c6f76c107ef..17f9d99250a 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreateOrUpdateOrderDraftTests.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrderTests.kt @@ -2,7 +2,7 @@ package com.woocommerce.android.ui.orders.creation import com.woocommerce.android.model.Order import com.woocommerce.android.ui.orders.OrderTestUtils -import com.woocommerce.android.ui.orders.creation.CreateOrUpdateOrderDraft.OrderDraftUpdateStatus +import com.woocommerce.android.ui.orders.creation.CreateUpdateOrder.OrderUpdateStatus import com.woocommerce.android.util.InlineClassesAnswer import com.woocommerce.android.util.advanceTimeAndRun import com.woocommerce.android.viewmodel.BaseUnitTest @@ -24,7 +24,7 @@ import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import java.math.BigDecimal -class CreateOrUpdateOrderDraftTests : BaseUnitTest() { +class CreateUpdateOrderTests : BaseUnitTest() { private val orderCreationRepository = mock { onBlocking { createOrUpdateDraft(any()) } doAnswer InlineClassesAnswer { val order = it.arguments.first() as Order @@ -35,14 +35,14 @@ class CreateOrUpdateOrderDraftTests : BaseUnitTest() { private val orderDraftChanges = MutableStateFlow(order) private val retryTrigger = MutableSharedFlow(extraBufferCapacity = 1) - private val sut: CreateOrUpdateOrderDraft = CreateOrUpdateOrderDraft( + private val sut: CreateUpdateOrder = CreateUpdateOrder( dispatchers = coroutinesTestRule.testDispatchers, orderCreationRepository = orderCreationRepository ) @Test fun `when there are changes, then update the draft order`() = testBlocking { - val updateStatuses = mutableListOf() + val updateStatuses = mutableListOf() val job = sut(orderDraftChanges, retryTrigger) .onEach { updateStatuses.add(it) } .launchIn(this) @@ -50,10 +50,10 @@ class CreateOrUpdateOrderDraftTests : BaseUnitTest() { advanceUntilIdle() assertThat(updateStatuses.size).isEqualTo(3) - assertThat(updateStatuses[0]).isEqualTo(OrderDraftUpdateStatus.PendingDebounce) - assertThat(updateStatuses[1]).isEqualTo(OrderDraftUpdateStatus.Ongoing) - assertThat(updateStatuses[2]).isInstanceOf(OrderDraftUpdateStatus.Succeeded::class.java) - with(updateStatuses[2] as OrderDraftUpdateStatus.Succeeded) { + assertThat(updateStatuses[0]).isEqualTo(OrderUpdateStatus.PendingDebounce) + assertThat(updateStatuses[1]).isEqualTo(OrderUpdateStatus.Ongoing) + assertThat(updateStatuses[2]).isInstanceOf(OrderUpdateStatus.Succeeded::class.java) + with(updateStatuses[2] as OrderUpdateStatus.Succeeded) { assertThat(order) .isEqualTo(orderCreationRepository.createOrUpdateDraft(orderDraftChanges.value).getOrThrow()) } @@ -64,7 +64,7 @@ class CreateOrUpdateOrderDraftTests : BaseUnitTest() { @Test fun `when the update fails, then notify the observer`() = testBlocking { whenever(orderCreationRepository.createOrUpdateDraft(any())).doReturn(Result.failure(Exception())) - val updateStatuses = mutableListOf() + val updateStatuses = mutableListOf() val job = sut(orderDraftChanges, retryTrigger) .onEach { updateStatuses.add(it) } .launchIn(this) @@ -72,9 +72,9 @@ class CreateOrUpdateOrderDraftTests : BaseUnitTest() { advanceUntilIdle() assertThat(updateStatuses.size).isEqualTo(3) - assertThat(updateStatuses[0]).isEqualTo(OrderDraftUpdateStatus.PendingDebounce) - assertThat(updateStatuses[1]).isEqualTo(OrderDraftUpdateStatus.Ongoing) - assertThat(updateStatuses[2]).isInstanceOf(OrderDraftUpdateStatus.Failed::class.java) + assertThat(updateStatuses[0]).isEqualTo(OrderUpdateStatus.PendingDebounce) + assertThat(updateStatuses[1]).isEqualTo(OrderUpdateStatus.Ongoing) + assertThat(updateStatuses[2]).isInstanceOf(OrderUpdateStatus.Failed::class.java) job.cancel() } @@ -89,7 +89,7 @@ class CreateOrUpdateOrderDraftTests : BaseUnitTest() { } verify(orderCreationRepository, never()).createOrUpdateDraft(any()) - advanceTimeAndRun(CreateOrUpdateOrderDraft.DEBOUNCE_DURATION_MS) + advanceTimeAndRun(CreateUpdateOrder.DEBOUNCE_DURATION_MS) verify(orderCreationRepository, times(1)).createOrUpdateDraft(any()) job.cancel() @@ -106,7 +106,7 @@ class CreateOrUpdateOrderDraftTests : BaseUnitTest() { } ) - val updateStatuses = mutableListOf() + val updateStatuses = mutableListOf() val job = sut(orderDraftChanges, retryTrigger) .onEach { updateStatuses.add(it) } .launchIn(this) @@ -122,7 +122,7 @@ class CreateOrUpdateOrderDraftTests : BaseUnitTest() { advanceUntilIdle() assertThat(updateStatuses.size).isEqualTo(5) - assertThat(updateStatuses.last()).isInstanceOf(OrderDraftUpdateStatus.Succeeded::class.java) + assertThat(updateStatuses.last()).isInstanceOf(OrderUpdateStatus.Succeeded::class.java) job.cancel() } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreationFocusedOrderCreationViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreationFocusedOrderCreationViewModelTest.kt index fefadbdc5f2..ddefc02e838 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreationFocusedOrderCreationViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreationFocusedOrderCreationViewModelTest.kt @@ -4,10 +4,10 @@ import com.woocommerce.android.R import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewOrderStatusSelector -import com.woocommerce.android.ui.orders.creation.CreateOrUpdateOrderDraft.OrderDraftUpdateStatus.Failed -import com.woocommerce.android.ui.orders.creation.CreateOrUpdateOrderDraft.OrderDraftUpdateStatus.Ongoing -import com.woocommerce.android.ui.orders.creation.CreateOrUpdateOrderDraft.OrderDraftUpdateStatus.PendingDebounce -import com.woocommerce.android.ui.orders.creation.CreateOrUpdateOrderDraft.OrderDraftUpdateStatus.Succeeded +import com.woocommerce.android.ui.orders.creation.CreateUpdateOrder.OrderUpdateStatus.Failed +import com.woocommerce.android.ui.orders.creation.CreateUpdateOrder.OrderUpdateStatus.Ongoing +import com.woocommerce.android.ui.orders.creation.CreateUpdateOrder.OrderUpdateStatus.PendingDebounce +import com.woocommerce.android.ui.orders.creation.CreateUpdateOrder.OrderUpdateStatus.Succeeded import com.woocommerce.android.ui.orders.creation.OrderCreationViewModel.Mode import com.woocommerce.android.ui.orders.creation.OrderCreationViewModel.Mode.Creation import com.woocommerce.android.ui.orders.creation.OrderCreationViewModel.ViewState @@ -22,14 +22,11 @@ import com.woocommerce.android.viewmodel.MultiLiveEvent.Event import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowDialog import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.flowOf import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.fail import org.junit.Test -import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock -import org.mockito.kotlin.verify import org.wordpress.android.fluxc.network.rest.wpcom.wc.order.CoreOrderStatus import java.math.BigDecimal @@ -37,11 +34,6 @@ import java.math.BigDecimal class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest() { override val mode: Mode = Creation - @Test - fun `when initializing the view model, then register the orderDraft flowState`() { - verify(createOrUpdateOrderUseCase).invoke(any(), any()) - } - @Test fun `when submitting customer note, then update orderDraft liveData`() { var orderDraft: Order? = null @@ -541,12 +533,8 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( @Test fun `when OrderDraftUpdateStatus is WillStart, then adjust view state to reflect the loading preparation`() { - createOrUpdateOrderUseCase = mock { - onBlocking { invoke(any(), any()) } doReturn flowOf(PendingDebounce) - } - createSut() - var viewState: ViewState? = null + sut.onOrderStatusChange(PendingDebounce) sut.viewStateData.observeForever { _, new -> viewState = new @@ -560,13 +548,10 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( @Test fun `when OrderDraftUpdateStatus is Ongoing, then adjust view state to reflect the loading`() { - createOrUpdateOrderUseCase = mock { - onBlocking { invoke(any(), any()) } doReturn flowOf(Ongoing) - } - createSut() - var viewState: ViewState? = null + sut.onOrderStatusChange(Ongoing) + sut.viewStateData.observeForever { _, new -> viewState = new } @@ -580,10 +565,6 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( @Test fun `when OrderDraftUpdateStatus is Succeeded, then adjust view state to reflect the loading end`() { val modifiedOrderValue = defaultOrderValue.copy(id = 999) - createOrUpdateOrderUseCase = mock { - onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(modifiedOrderValue)) - } - createSut() var viewState: ViewState? = null var orderDraft: Order? = null @@ -596,6 +577,8 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( orderDraft = it } + sut.onOrderStatusChange(Succeeded(modifiedOrderValue)) + assertThat(viewState).isNotNull assertThat(viewState?.willUpdateOrderDraft).isFalse assertThat(viewState?.isUpdatingOrderDraft).isFalse @@ -607,13 +590,10 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( @Test fun `when OrderDraftUpdateStatus is Failed, then adjust view state to reflect the failure`() { - createOrUpdateOrderUseCase = mock { - onBlocking { invoke(any(), any()) } doReturn flowOf(Failed) - } - createSut() - var viewState: ViewState? = null + sut.onOrderStatusChange(Failed) + sut.viewStateData.observeForever { _, new -> viewState = new } @@ -701,28 +681,22 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( @Test fun `when isEditable is true on the create flow the order is editable`() { // When the order is on Creation mode is always editable - createOrUpdateOrderUseCase = mock { - onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(defaultOrderValue.copy(isEditable = true))) - } - createSut() var lastReceivedState: ViewState? = null sut.viewStateData.liveData.observeForever { lastReceivedState = it } + sut.onOrderStatusChange(Succeeded(defaultOrderValue.copy(isEditable = true))) assertThat(lastReceivedState?.isEditable).isEqualTo(true) } @Test fun `when isEditable is false on the edit flow the order is editable`() { // When the order is on Creation mode is always editable - createOrUpdateOrderUseCase = mock { - onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(defaultOrderValue.copy(isEditable = false))) - } - createSut() var lastReceivedState: ViewState? = null sut.viewStateData.liveData.observeForever { lastReceivedState = it } + sut.onOrderStatusChange(Succeeded(defaultOrderValue.copy(isEditable = false))) assertThat(lastReceivedState?.isEditable).isEqualTo(true) } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreationViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreationViewModelTest.kt index 9253034b9c9..d2068b05ef2 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreationViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreationViewModelTest.kt @@ -1,20 +1,17 @@ package com.woocommerce.android.ui.orders.creation import com.woocommerce.android.model.Order -import com.woocommerce.android.ui.orders.creation.CreateOrUpdateOrderDraft.OrderDraftUpdateStatus.Succeeded +import com.woocommerce.android.ui.orders.creation.CreateUpdateOrder.OrderUpdateStatus.Succeeded import com.woocommerce.android.ui.orders.creation.OrderCreationViewModel.Mode import com.woocommerce.android.ui.orders.creation.OrderCreationViewModel.Mode.Edit import com.woocommerce.android.viewmodel.MultiLiveEvent.Event import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.flowOf import org.assertj.core.api.Assertions.assertThat import org.junit.Test import org.junit.runner.RunWith import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.any import org.mockito.kotlin.doReturn -import org.mockito.kotlin.mock import org.mockito.kotlin.stub @ExperimentalCoroutinesApi @@ -70,27 +67,21 @@ class EditFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest() { @Test fun `when isEditable is true on the edit flow the order is editable`() { - createOrUpdateOrderUseCase = mock { - onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(defaultOrderValue.copy(isEditable = true))) - } - createSut() var lastReceivedState: OrderCreationViewModel.ViewState? = null sut.viewStateData.liveData.observeForever { lastReceivedState = it } + sut.onOrderStatusChange(Succeeded(defaultOrderValue.copy(isEditable = true))) assertThat(lastReceivedState?.isEditable).isEqualTo(true) } @Test fun `when isEditable is false on the edit flow the order is NOT editable`() { - createOrUpdateOrderUseCase = mock { - onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(defaultOrderValue.copy(isEditable = false))) - } - createSut() var lastReceivedState: OrderCreationViewModel.ViewState? = null sut.viewStateData.liveData.observeForever { lastReceivedState = it } + sut.onOrderStatusChange(Succeeded(defaultOrderValue.copy(isEditable = false))) assertThat(lastReceivedState?.isEditable).isEqualTo(false) } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt index a81400524b0..98d4f03da21 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt @@ -3,20 +3,19 @@ package com.woocommerce.android.ui.orders.creation import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import com.woocommerce.android.model.Order -import com.woocommerce.android.ui.orders.creation.CreateOrUpdateOrderDraft.OrderDraftUpdateStatus.Succeeded import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.products.ParameterRepository import com.woocommerce.android.ui.products.ProductStockStatus import com.woocommerce.android.ui.products.models.SiteParameters import com.woocommerce.android.viewmodel.BaseUnitTest import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.flowOf import org.junit.Before import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.spy +import org.mockito.kotlin.stub @ExperimentalCoroutinesApi abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { @@ -24,7 +23,6 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { protected lateinit var viewState: OrderCreationViewModel.ViewState protected lateinit var savedState: SavedStateHandle protected lateinit var mapItemToProductUIModel: MapItemToProductUiModel - protected lateinit var createOrUpdateOrderUseCase: CreateOrUpdateOrderDraft protected lateinit var createOrderItemUseCase: CreateOrderItem protected lateinit var orderCreationRepository: OrderCreationRepository protected lateinit var orderDetailRepository: OrderDetailRepository @@ -48,9 +46,6 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { on { getLiveData(viewState.javaClass.name, viewState) } doReturn MutableLiveData(viewState) on { getLiveData(eq(Order.EMPTY.javaClass.name), any()) } doReturn MutableLiveData(emptyOrder) } - createOrUpdateOrderUseCase = mock { - onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(Order.EMPTY)) - } createOrderItemUseCase = mock { onBlocking { invoke(123, null) } doReturn defaultOrderItem } @@ -68,6 +63,9 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { orderCreationRepository = mock { onBlocking { placeOrder(defaultOrderValue) } doReturn Result.success(defaultOrderValue) } + orderCreationRepository.stub { + onBlocking { createOrUpdateDraft(any()) } doReturn Result.success(defaultOrderValue) + } orderDetailRepository = mock { on { getOrderStatusOptions() } doReturn orderStatusList } @@ -89,7 +87,6 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { orderDetailRepository = orderDetailRepository, orderCreationRepository = orderCreationRepository, mapItemToProductUiModel = mapItemToProductUIModel, - createOrUpdateOrderDraft = createOrUpdateOrderUseCase, createOrderItem = createOrderItemUseCase, parameterRepository = parameterRepository ) From b35caa33169d051507ea00c9fecb625cc9f2609c Mon Sep 17 00:00:00 2001 From: Oguz Kocer Date: Wed, 29 Jun 2022 11:03:20 -0400 Subject: [PATCH 065/173] Update release notes for 9.5 --- WooCommerce/metadata/release_notes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WooCommerce/metadata/release_notes.txt b/WooCommerce/metadata/release_notes.txt index 139597f9cb0..dd88675cb0c 100644 --- a/WooCommerce/metadata/release_notes.txt +++ b/WooCommerce/metadata/release_notes.txt @@ -1,2 +1,4 @@ +We keep adding new functionality to our experimental Coupon Management feature! This release includes editing and deleting coupons along with several improvements on viewing. Turn this feature on for early access in the More tab, Settings, Beta Features. +We also fixed a bug that was making it hard for some of you to search orders. Thanks to everyone who reported this! Your feedback is vital to us! From f79d9e5909f577161405bc655fac760482885bf8 Mon Sep 17 00:00:00 2001 From: Oguz Kocer Date: Wed, 29 Jun 2022 11:03:32 -0400 Subject: [PATCH 066/173] Update `PlayStoreStrings.po` for 9.5 --- WooCommerce/metadata/PlayStoreStrings.pot | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/WooCommerce/metadata/PlayStoreStrings.pot b/WooCommerce/metadata/PlayStoreStrings.pot index 037cdcc2520..faffdcf29a4 100644 --- a/WooCommerce/metadata/PlayStoreStrings.pot +++ b/WooCommerce/metadata/PlayStoreStrings.pot @@ -11,18 +11,19 @@ msgstr "" "Project-Id-Version: Release Notes & Play Store Descriptions\n" #. translators: Release notes for this version to be displayed in the Play Store. Limit to 500 characters including spaces and commas! -msgctxt "release_note_094" +msgctxt "release_note_095" msgid "" -"9.4:\n" -"Even though this release doesn’t have any new features, we still put a lot of love into it! In product details, some third-party extensions were causing the app to crash when viewing variable products. We’ve fixed this crash and made a handful of minor improvements to make your experience smoother.\n" +"9.5:\n" +"We keep adding new functionality to our experimental Coupon Management feature! This release includes editing and deleting coupons along with several improvements on viewing. Turn this feature on for early access in the More tab, Settings, Beta Features.\n" +"\n" +"We also fixed a bug that was making it hard for some of you to search orders. Thanks to everyone who reported this! Your feedback is vital to us!\n" +"\n" msgstr "" -msgctxt "release_note_093" +msgctxt "release_note_094" msgid "" -"9.3:\n" -"Canada, say hello to in-person payments! We are thrilled to announce that in-person payments are now available to Canadian merchants currently using WooCommerce Payments.\n" -"\n" -"This release also contains a few minor improvements. Thank you all again for your amazing feedback. Keep it coming!\n" +"9.4:\n" +"Even though this release doesn’t have any new features, we still put a lot of love into it! In product details, some third-party extensions were causing the app to crash when viewing variable products. We’ve fixed this crash and made a handful of minor improvements to make your experience smoother.\n" msgstr "" #. translators: Short description of the app to be displayed in the Play Store. Limit to 80 characters including spaces and commas! From 661c92059e6a5186e27bbfb3cb1faea20367dc43 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 29 Jun 2022 17:15:29 +0100 Subject: [PATCH 067/173] Check if selected site exists before accessing in MoreMenuRepository --- .../android/ui/moremenu/domain/MoreMenuRepository.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/moremenu/domain/MoreMenuRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/moremenu/domain/MoreMenuRepository.kt index c5cda8a509d..74161a0f015 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/moremenu/domain/MoreMenuRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/moremenu/domain/MoreMenuRepository.kt @@ -24,7 +24,7 @@ class MoreMenuRepository @Inject constructor( suspend fun isInboxEnabled(): Boolean = withContext(Dispatchers.IO) { - if (!FeatureFlag.MORE_MENU_INBOX.isEnabled()) return@withContext false + if (!selectedSite.exists() || !FeatureFlag.MORE_MENU_INBOX.isEnabled()) return@withContext false val currentWooCoreVersion = wooCommerceStore.getSitePlugin(selectedSite.get(), WOO_CORE)?.version ?: "0.0" From 491fbc3552cc151673906a1a31338fc713bfa2b9 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 29 Jun 2022 17:16:42 +0100 Subject: [PATCH 068/173] Remove the locales list hack --- fastlane/Fastfile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 998abb4e1a0..651d75f654e 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -613,11 +613,6 @@ platform :android do map { |locale| locale[:google_play] } end - # Override the locales array with one locale until - # https://github.com/fastlane/fastlane/issues/19521 - # is fixed: - locales = ["en-EN"] - UI.message("Attempting screenshots for locales: #{locales}") screenshot_options = { From 57b6aebbac75280531841e9e14d08cf06cde0c62 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 29 Jun 2022 17:17:03 +0100 Subject: [PATCH 069/173] Fix initialization of LocaleTestRule --- .../com/woocommerce/android/screenshots/ScreenshotTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/screenshots/ScreenshotTest.kt b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/screenshots/ScreenshotTest.kt index 304b5a59d88..e218927355a 100644 --- a/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/screenshots/ScreenshotTest.kt +++ b/WooCommerce/src/androidTest/kotlin/com/woocommerce/android/screenshots/ScreenshotTest.kt @@ -40,11 +40,11 @@ class ScreenshotTest : TestBase() { val composeTestRule = createComposeRule() @get:Rule(order = 3) - var activityRule = ActivityTestRule(MainActivity::class.java) - - @Rule @JvmField val localeTestRule = LocaleTestRule() + @get:Rule(order = 4) + var activityRule = ActivityTestRule(MainActivity::class.java) + @Before fun setUp() { CleanStatusBar.enableWithDefaults() From 4e88778f6fbc584ecf77facb3d48044031b7f5d7 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 29 Jun 2022 17:48:34 +0100 Subject: [PATCH 070/173] Improve detection of test environment --- .../com/woocommerce/android/support/ZendeskHelper.kt | 2 +- .../com/woocommerce/android/util/PackageUtils.kt | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt index 655bb2425a5..8666e1cb408 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt @@ -90,7 +90,7 @@ class ZendeskHelper( enableLogs: Boolean = BuildConfig.DEBUG ) { if (isZendeskEnabled) { - if (PackageUtils.isUITesting()) return + if (PackageUtils.isTesting()) return else error("Zendesk shouldn't be initialized more than once!") } if (zendeskUrl.isEmpty() || applicationId.isEmpty() || oauthClientId.isEmpty()) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt index a2b42000e88..b2c7539c6b8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt @@ -20,7 +20,7 @@ object PackageUtils { fun isTesting(): Boolean { if (isTesting == null) { isTesting = try { - Class.forName("com.woocommerce.android.viewmodel.BaseUnitTest") + Class.forName("org.junit.Test") true } catch (e: ClassNotFoundException) { false @@ -29,15 +29,6 @@ object PackageUtils { return isTesting!! } - fun isUITesting(): Boolean { - return try { - Class.forName("com.woocommerce.android.helpers.TestBase") - true - } catch (e: ClassNotFoundException) { - false - } - } - fun isBetaBuild(context: Context): Boolean { val versionName = getVersionName(context).toLowerCase(Locale.ROOT) return (versionName.contains("beta") || versionName.contains("rc")) From b0b7d01b8ea0836f3eb20a46f73ee14542dd7f93 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 29 Jun 2022 17:53:19 +0100 Subject: [PATCH 071/173] Make sure LeakCanary is not initialized for test/androidTest builds --- WooCommerce/build.gradle | 2 +- WooCommerce/src/debug/AndroidManifest.xml | 29 +++++++++---- .../LeakCanaryInstaller.kt | 42 +++++++++++++++++++ 3 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 WooCommerce/src/debug/kotlin/com.woocommerce.android/LeakCanaryInstaller.kt diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 24cd24eb16d..11b3cf29288 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -263,7 +263,7 @@ dependencies { // See https://github.com/wordpress-mobile/WordPress-FluxC-Android/issues/919 exclude group: 'com.squareup.okhttp3' } - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1' + debugImplementation 'com.squareup.leakcanary:leakcanary-android-core:2.9.1' // Dependencies for local unit tests testImplementation "junit:junit:$jUnitVersion" diff --git a/WooCommerce/src/debug/AndroidManifest.xml b/WooCommerce/src/debug/AndroidManifest.xml index 5ca4765fb2a..7270cef6d1e 100644 --- a/WooCommerce/src/debug/AndroidManifest.xml +++ b/WooCommerce/src/debug/AndroidManifest.xml @@ -1,29 +1,40 @@ - + - - + + - + - + - + + tools:replace="android:name"> + + diff --git a/WooCommerce/src/debug/kotlin/com.woocommerce.android/LeakCanaryInstaller.kt b/WooCommerce/src/debug/kotlin/com.woocommerce.android/LeakCanaryInstaller.kt new file mode 100644 index 00000000000..d1656c793d9 --- /dev/null +++ b/WooCommerce/src/debug/kotlin/com.woocommerce.android/LeakCanaryInstaller.kt @@ -0,0 +1,42 @@ +package com.woocommerce.android + +import android.app.Application +import android.content.ContentProvider +import android.content.ContentValues +import android.database.Cursor +import android.net.Uri +import com.woocommerce.android.util.PackageUtils +import com.woocommerce.android.util.WooLog +import leakcanary.AppWatcher + +internal class LeakCanaryInstaller : ContentProvider() { + override fun onCreate(): Boolean { + if (!PackageUtils.isTesting()) { + WooLog.v(WooLog.T.DEVICE, "Installing LeakCanary") + val application = context!!.applicationContext as Application + AppWatcher.manualInstall(application) + } + return true + } + + override fun query( + uri: Uri, + projectionArg: Array?, + selection: String?, + selectionArgs: Array?, + sortOrder: String? + ): Cursor? = null + + override fun getType(uri: Uri): String? = null + + override fun insert(uri: Uri, contentValues: ContentValues?): Uri? = null + + override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int = 0 + + override fun update( + uri: Uri, + values: ContentValues?, + selection: String?, + selectionArgs: Array? + ): Int = 0 +} From f58825f35d8b9fc9fc22951b62655d77da056bed Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 29 Jun 2022 16:59:11 -0300 Subject: [PATCH 072/173] add linear indicator to the top of the layout --- .../layout/fragment_order_creation_form.xml | 112 +++++++++++------- 1 file changed, 68 insertions(+), 44 deletions(-) diff --git a/WooCommerce/src/main/res/layout/fragment_order_creation_form.xml b/WooCommerce/src/main/res/layout/fragment_order_creation_form.xml index 5431ba11041..2a2b1af4a6e 100644 --- a/WooCommerce/src/main/res/layout/fragment_order_creation_form.xml +++ b/WooCommerce/src/main/res/layout/fragment_order_creation_form.xml @@ -1,55 +1,79 @@ - - + android:indeterminate="true" + app:layout_constraintBottom_toTopOf="@+id/scrollView" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + android:visibility="gone"/> - - - + - - - - - + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + + + + + + + + + + + + - - - From cccce352ad27586200605c364d453d6fe09bd087 Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 29 Jun 2022 17:01:39 -0300 Subject: [PATCH 073/173] editing linear indicator / creating circular indicator --- .../ui/orders/creation/OrderCreationFormFragment.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt index 59448a8f38e..9534cf8a469 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt @@ -2,6 +2,7 @@ package com.woocommerce.android.ui.orders.creation import android.annotation.SuppressLint import android.os.Bundle +import android.transition.TransitionManager import android.view.Menu import android.view.MenuInflater import android.view.MenuItem @@ -227,7 +228,15 @@ class OrderCreationFormFragment : BaseFragment(R.layout.fragment_order_creation_ createOrderMenuItem?.isEnabled = it } new.isIdle.takeIfNotEqualTo(old?.isIdle) { enabled -> - binding.paymentSection.loadingProgress.isVisible = !enabled + TransitionManager.beginDelayedTransition(binding.root) + when(viewModel.mode){ + OrderCreationViewModel.Mode.Creation -> { + binding.paymentSection.loadingProgress.isVisible = !enabled + } + is OrderCreationViewModel.Mode.Edit -> { + binding.loadingProgress.isVisible = !enabled + } + } if (new.isEditable) { binding.paymentSection.shippingButton.isEnabled = enabled binding.paymentSection.feeButton.isEnabled = enabled From 616d436e3685bccd50324fb0ba831d5dc9eb69de Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 29 Jun 2022 17:02:41 -0300 Subject: [PATCH 074/173] indicators hidden by default --- .../src/main/res/layout/order_creation_payment_section.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/res/layout/order_creation_payment_section.xml b/WooCommerce/src/main/res/layout/order_creation_payment_section.xml index d8d1eef0e06..ac587676cd9 100644 --- a/WooCommerce/src/main/res/layout/order_creation_payment_section.xml +++ b/WooCommerce/src/main/res/layout/order_creation_payment_section.xml @@ -42,7 +42,8 @@ android:layout_width="@dimen/major_200" android:layout_height="@dimen/major_200" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + android:visibility="gone"/> From 2fabd15ca34c67b82186e82f45fa2a49f2e75d75 Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 29 Jun 2022 17:05:38 -0300 Subject: [PATCH 075/173] fix detekt warnings --- .../android/ui/orders/creation/OrderCreationFormFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt index 9534cf8a469..0488d312801 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt @@ -229,7 +229,7 @@ class OrderCreationFormFragment : BaseFragment(R.layout.fragment_order_creation_ } new.isIdle.takeIfNotEqualTo(old?.isIdle) { enabled -> TransitionManager.beginDelayedTransition(binding.root) - when(viewModel.mode){ + when (viewModel.mode) { OrderCreationViewModel.Mode.Creation -> { binding.paymentSection.loadingProgress.isVisible = !enabled } From 84ccf245f6eaa7964143ae9a7c47707b87533d89 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 30 Jun 2022 07:22:01 -0400 Subject: [PATCH 076/173] Use named parameters --- .../android/ui/products/ProductListRepository.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListRepository.kt index 8c84605e582..0164fd43767 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListRepository.kt @@ -108,11 +108,11 @@ class ProductListRepository @Inject constructor( offset = if (loadMore) offset + PRODUCT_PAGE_SIZE else 0 lastSearchQuery = searchQuery val payload = WCProductStore.SearchProductsPayload( - selectedSite.get(), - searchQuery, - PRODUCT_PAGE_SIZE, - offset, - productSortingChoice, + site = selectedSite.get(), + searchQuery = searchQuery, + pageSize = PRODUCT_PAGE_SIZE, + offset = offset, + sorting = productSortingChoice, excludedProductIds = excludedProductIds ) dispatcher.dispatch(WCProductActionBuilder.newSearchProductsAction(payload)) From dba4e501c96312316974336665dbf24c56e4b54f Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 30 Jun 2022 15:41:31 +0300 Subject: [PATCH 077/173] Analysis: Remove redundant experimental coroutines api annotations Message: "The opt-in annotation is redundant: no matching experimental API is used" --- .../main/kotlin/com/woocommerce/android/extensions/ViewExt.kt | 3 --- .../com/woocommerce/android/ui/media/MediaFileUploadHandler.kt | 2 -- .../com/woocommerce/android/ui/mystore/domain/GetStats.kt | 2 -- .../shippinglabels/creation/CreateShippingLabelViewModel.kt | 3 --- .../shippinglabels/creation/ShippingLabelsStateMachine.kt | 3 --- 5 files changed, 13 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt index 09c389a24de..be0b47d39bb 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt @@ -20,7 +20,6 @@ import androidx.transition.ChangeBounds import androidx.transition.Transition import androidx.transition.TransitionListenerAdapter import androidx.transition.TransitionManager -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.* @@ -154,7 +153,6 @@ fun ViewGroup.setEnabledRecursive(enabled: Boolean) { * @param handled defines what the [OnTouchListener.onTouch] returns, defaults to returning false */ @SuppressLint("ClickableViewAccessibility") -@ExperimentalCoroutinesApi fun View.touchEvents( handled: (MotionEvent) -> Boolean = { false } ): Flow = callbackFlow { @@ -171,7 +169,6 @@ fun View.touchEvents( /** * Returns a Flow of events that are triggered when a scroll is started on a view. */ -@ExperimentalCoroutinesApi fun View.scrollStartEvents(): Flow { return touchEvents() .map { it.action } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/media/MediaFileUploadHandler.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/media/MediaFileUploadHandler.kt index 2dee41219a8..4bfbd37ef70 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/media/MediaFileUploadHandler.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/media/MediaFileUploadHandler.kt @@ -17,7 +17,6 @@ import com.woocommerce.android.util.StringUtils import com.woocommerce.android.util.WooLog import com.woocommerce.android.viewmodel.ResourceProvider import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.* import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.model.MediaModel @@ -26,7 +25,6 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -@ExperimentalCoroutinesApi class MediaFileUploadHandler @Inject constructor( private val notificationHandler: ProductImagesNotificationHandler, private val worker: ProductImagesUploadWorker, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/domain/GetStats.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/domain/GetStats.kt index 08a3532ed22..2b66faa9760 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/domain/GetStats.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/domain/GetStats.kt @@ -7,7 +7,6 @@ import com.woocommerce.android.ui.mystore.data.StatsRepository.StatsException import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.* import com.woocommerce.android.util.CoroutineDispatchers import com.woocommerce.android.util.FeatureFlag -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.* import org.wordpress.android.fluxc.model.WCRevenueStatsModel import org.wordpress.android.fluxc.store.WCStatsStore.OrderStatsErrorType @@ -20,7 +19,6 @@ class GetStats @Inject constructor( private val appPrefsWrapper: AppPrefsWrapper, private val coroutineDispatchers: CoroutineDispatchers ) { - @ExperimentalCoroutinesApi suspend operator fun invoke(refresh: Boolean, granularity: StatsGranularity): Flow = merge( hasOrders(), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelViewModel.kt index 886b1faf98a..ce226d50e74 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelViewModel.kt @@ -64,8 +64,6 @@ import com.woocommerce.android.viewmodel.ResourceProvider import com.woocommerce.android.viewmodel.ScopedViewModel import com.woocommerce.android.viewmodel.navArgs import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult @@ -79,7 +77,6 @@ import java.text.DecimalFormat import javax.inject.Inject import kotlin.system.measureTimeMillis -@ExperimentalCoroutinesApi @HiltViewModel class CreateShippingLabelViewModel @Inject constructor( savedState: SavedStateHandle, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelsStateMachine.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelsStateMachine.kt index 68176c1f46e..184ca410270 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelsStateMachine.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelsStateMachine.kt @@ -16,7 +16,6 @@ import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelsS import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelsStateMachine.StepStatus.* import com.woocommerce.android.util.WooLog import com.woocommerce.android.util.WooLog.T -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.parcelize.IgnoredOnParcel @@ -93,10 +92,8 @@ import it. class ShippingLabelsStateMachine @Inject constructor() { // the flow can be observed by a ViewModel (similar to LiveData) and it can react by perform actions and update // the view states based on the triggered states and side-effects - @ExperimentalCoroutinesApi private val _transitions = MutableStateFlow(Transition(State.Idle, SideEffect.NoOp)) - @ExperimentalCoroutinesApi val transitions: StateFlow = _transitions // the actual state machine behavior is defined by a DSL using the following format: From eca01a5448fcb8508800035ecdb5e76ce93938f1 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 30 Jun 2022 15:48:10 +0300 Subject: [PATCH 078/173] Analysis: Change direct experimental coroutines api with opt-in Changing the '@ExperimentalCoroutinesApi' to an '@OptIn(ExperimentalCoroutinesApi::class)' or an '@OptIn(FlowPreview::class)' and placing it closer to usage will make it more obvious which Coroutines API is actually experimental and why. Also, this will resolve other such '@OptIn(ExperimentalCoroutinesApi::class)' or '@OptIn(FlowPreview::class)' warnings, which was based on the class as it was marked directly as '@ExperimentalCoroutinesApi' instead of an opt-in. --- .../woocommerce/android/media/ProductImagesUploadWorker.kt | 2 +- .../com/woocommerce/android/push/UnseenReviewsCountHandler.kt | 2 +- .../com/woocommerce/android/ui/mystore/MyStoreFragment.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/media/ProductImagesUploadWorker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/media/ProductImagesUploadWorker.kt index e62e8201581..9a1a13181ba 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/media/ProductImagesUploadWorker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/media/ProductImagesUploadWorker.kt @@ -30,7 +30,6 @@ import javax.inject.Singleton * Uploading media and updating product is done sequentially (using a [Mutex] lock) because our repositories don't * play well with parallel requests, due to the use of a single shared continuation. */ -@ExperimentalCoroutinesApi @Singleton class ProductImagesUploadWorker @Inject constructor( private val mediaFilesRepository: MediaFilesRepository, @@ -76,6 +75,7 @@ class ProductImagesUploadWorker @Inject constructor( .launchIn(appCoroutineScope) } + @OptIn(ExperimentalCoroutinesApi::class) private fun handleServiceStatus() { pendingWorkList .transformLatest { list -> diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/push/UnseenReviewsCountHandler.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/push/UnseenReviewsCountHandler.kt index 685f699dbde..bc3c1005ab8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/push/UnseenReviewsCountHandler.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/push/UnseenReviewsCountHandler.kt @@ -10,13 +10,13 @@ import org.wordpress.android.fluxc.store.NotificationStore import javax.inject.Inject import javax.inject.Singleton -@ExperimentalCoroutinesApi @Singleton class UnseenReviewsCountHandler @Inject constructor( @AppCoroutineScope private val appCoroutineScope: CoroutineScope, private val notificationStore: NotificationStore, selectedSite: SelectedSite ) { + @OptIn(ExperimentalCoroutinesApi::class) private val unseenReviewsCount: SharedFlow = selectedSite.observe() .flatMapLatest { site -> diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreFragment.kt index 05aa5797c4e..18dd8fcb55f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreFragment.kt @@ -47,7 +47,7 @@ import com.woocommerce.android.util.WooLog import com.woocommerce.android.widgets.WCEmptyView.EmptyViewType import com.woocommerce.android.widgets.WooClickableSpan import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity @@ -56,9 +56,9 @@ import java.util.Calendar import javax.inject.Inject import kotlin.math.abs -@ExperimentalCoroutinesApi @AndroidEntryPoint @Suppress("ForbiddenComment") +@OptIn(FlowPreview::class) class MyStoreFragment : TopLevelFragment(R.layout.fragment_my_store) { companion object { val TAG: String = MyStoreFragment::class.java.simpleName From a84836af0e61c90d24dfd14f6837800a4452b60a Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 30 Jun 2022 16:32:16 +0300 Subject: [PATCH 079/173] Analysis: Resolve opt-in experimental coroutine api warnings Warning Message: "This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn (kotlinx.coroutines.ExperimentalCoroutinesApi::class'" Adding the 'OptIn(ExperimentalCoroutinesApi::class)' annotation where needed and closer to usage is the recommended action to resolve these 'ExperimentalCoroutinesApi' warnings. --- .../com/woocommerce/android/media/MediaFilesRepository.kt | 2 ++ .../com/woocommerce/android/ui/coupons/CouponRepository.kt | 2 ++ .../products/categories/selector/ProductCategoryListHandler.kt | 2 ++ .../android/ui/products/selector/ProductListHandler.kt | 2 ++ 4 files changed, 8 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt index 42c66166841..4056b38707a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt @@ -10,6 +10,7 @@ import com.woocommerce.android.util.CoroutineDispatchers import com.woocommerce.android.util.WooLog import com.woocommerce.android.util.WooLog.T import com.woocommerce.android.viewmodel.ResourceProvider +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.* import kotlinx.coroutines.flow.* import kotlinx.coroutines.withContext @@ -51,6 +52,7 @@ class MediaFilesRepository @Inject constructor( } } + @OptIn(ExperimentalCoroutinesApi::class) fun uploadMedia(localMediaModel: MediaModel, stripLocation: Boolean = true): Flow { return callbackFlow { WooLog.d(T.MEDIA, "MediaFilesRepository > Dispatching request to upload ${localMediaModel.filePath}") diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/coupons/CouponRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/coupons/CouponRepository.kt index 331c4baa2be..484fa9c8dc5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/coupons/CouponRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/coupons/CouponRepository.kt @@ -9,6 +9,7 @@ import com.woocommerce.android.model.toAppModel import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.util.DateUtils import com.woocommerce.android.util.WooLog +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map @@ -81,6 +82,7 @@ class CouponRepository @Inject constructor( } } + @OptIn(ExperimentalCoroutinesApi::class) fun observeCoupons(): Flow> = store.observeCoupons(selectedSite.get()).map { it.map { couponDataModel -> couponDataModel.toAppModel() } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/selector/ProductCategoryListHandler.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/selector/ProductCategoryListHandler.kt index 7ba95877b70..254b4406533 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/selector/ProductCategoryListHandler.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/selector/ProductCategoryListHandler.kt @@ -1,6 +1,7 @@ package com.woocommerce.android.ui.products.categories.selector import androidx.annotation.VisibleForTesting +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flatMapLatest @@ -25,6 +26,7 @@ class ProductCategoryListHandler @Inject constructor( private val searchQuery = MutableStateFlow("") private val searchResults = MutableStateFlow(emptyList()) + @OptIn(ExperimentalCoroutinesApi::class) val categories: Flow> = searchQuery.flatMapLatest { query -> if (query.isEmpty()) { repository.observeCategories() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/selector/ProductListHandler.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/selector/ProductListHandler.kt index acd3b3d5621..589953475e0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/selector/ProductListHandler.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/selector/ProductListHandler.kt @@ -1,6 +1,7 @@ package com.woocommerce.android.ui.products.selector import com.woocommerce.android.model.Product +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest @@ -24,6 +25,7 @@ class ProductListHandler @Inject constructor(private val repository: ProductSele private val productFilters = MutableStateFlow(mapOf()) + @OptIn(ExperimentalCoroutinesApi::class) val productsFlow = combine(searchQuery, productFilters) { query, filters -> if (query.isEmpty()) { repository.observeProducts(filters) From 0b422ccb8f8248194ea29fc4922b0c1247332a10 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 30 Jun 2022 16:36:49 +0300 Subject: [PATCH 080/173] Analysis: Change opt-in experimental coroutines api to direct for tests This is done because: 1) Test suites don't need to use '@OptIn(ExperimentalCoroutinesApi::class)' in favor of the direct '@ExperimentalCoroutinesApi' annotation as the test classes are not being called from other places. 2) Of consistency purposes as all other test suites are using '@ExperimentalCoroutinesApi' in favor of '@OptIn(ExperimentalCoroutinesApi::class)'. --- .../kotlin/com/woocommerce/android/push/RegisterDeviceTest.kt | 2 +- .../woocommerce/android/ui/moremenu/MoreMenuViewModelTests.kt | 2 +- .../android/ui/orders/creation/OrderCreationRepositoryTest.kt | 2 +- .../android/ui/products/ProductDetailCardBuilderTest.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/push/RegisterDeviceTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/push/RegisterDeviceTest.kt index caef731d8cd..2815c61ac61 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/push/RegisterDeviceTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/push/RegisterDeviceTest.kt @@ -17,7 +17,7 @@ import org.wordpress.android.fluxc.store.GetDeviceRegistrationStatus import org.wordpress.android.fluxc.store.GetDeviceRegistrationStatus.Status.REGISTERED import org.wordpress.android.fluxc.store.GetDeviceRegistrationStatus.Status.UNREGISTERED -@OptIn(ExperimentalCoroutinesApi::class) +@ExperimentalCoroutinesApi class RegisterDeviceTest : BaseUnitTest() { lateinit var sut: RegisterDevice diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/moremenu/MoreMenuViewModelTests.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/moremenu/MoreMenuViewModelTests.kt index a9e68c8bac2..824fe6cefa1 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/moremenu/MoreMenuViewModelTests.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/moremenu/MoreMenuViewModelTests.kt @@ -18,8 +18,8 @@ import org.wordpress.android.fluxc.model.AccountModel import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.AccountStore +@ExperimentalCoroutinesApi class MoreMenuViewModelTests : BaseUnitTest() { - @OptIn(ExperimentalCoroutinesApi::class) private val unseenReviewsCountHandler: UnseenReviewsCountHandler = mock { on { observeUnseenCount() } doReturn flowOf(0) } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationRepositoryTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationRepositoryTest.kt index b37919839d6..984837dd16c 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationRepositoryTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationRepositoryTest.kt @@ -22,7 +22,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult import org.wordpress.android.fluxc.store.OrderUpdateStore import java.math.BigDecimal -@OptIn(ExperimentalCoroutinesApi::class) +@ExperimentalCoroutinesApi class OrderCreationRepositoryTest : BaseUnitTest() { companion object { const val DEFAULT_ERROR_MESSAGE = "error_message" diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ProductDetailCardBuilderTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ProductDetailCardBuilderTest.kt index c16c776e20d..df245d0a0d4 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ProductDetailCardBuilderTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/products/ProductDetailCardBuilderTest.kt @@ -17,7 +17,7 @@ import org.mockito.kotlin.anyVararg import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock -@OptIn(ExperimentalCoroutinesApi::class) +@ExperimentalCoroutinesApi class ProductDetailCardBuilderTest : BaseUnitTest() { private lateinit var sut: ProductDetailCardBuilder private lateinit var productStub: Product From 53fc8e91d8eb47073ae822d49604aa62ce24432f Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 30 Jun 2022 17:20:32 +0300 Subject: [PATCH 081/173] Analysis: Resolve magic number detekt warnings for view ext Also, with this change the below such entry is removed from the Detekt related 'baseline.xml' file as it is no longer needed: - MagicNumber:ViewExt.kt$300L --- .../kotlin/com/woocommerce/android/extensions/ViewExt.kt | 6 ++++-- config/detekt/baseline.xml | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt index be0b47d39bb..7892fb1302b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt @@ -23,6 +23,8 @@ import androidx.transition.TransitionManager import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.* +private const val EXPAND_COLLAPSE_ANIMATION_DURATION_MILLIS = 300L + fun View.show() { this.visibility = View.VISIBLE } @@ -89,7 +91,7 @@ fun View.collapse(duration: Long = 300L) { fun Group.expand() { if (this.isVisible) return - val animationDuration = 300L + val animationDuration = EXPAND_COLLAPSE_ANIMATION_DURATION_MILLIS val parent = parent as ViewGroup val transition = ChangeBounds() .setDuration(animationDuration) @@ -100,7 +102,7 @@ fun Group.expand() { fun Group.collapse() { if (!this.isVisible) return - val animationDuration = 300L + val animationDuration = EXPAND_COLLAPSE_ANIMATION_DURATION_MILLIS val parent = parent as ConstraintLayout val views = referencedIds.map { parent.getViewById(it) } val originalHeights = views.map { it.layoutParams.height } diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 2d980e167c2..1dedb07e011 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -120,7 +120,6 @@ MagicNumber:TimeGroup.kt$TimeGroup.Companion$2 MagicNumber:UiHelpers.kt$UiHelpers$0.8 MagicNumber:UnreadItemDecoration.kt$UnreadItemDecoration$3 - MagicNumber:ViewExt.kt$300L MagicNumber:ViewUtils.kt$0.5f MagicNumber:WCEmptyView.kt$WCEmptyView$50L MagicNumber:WCMaterialOutlinedEditTextView.kt$WCMaterialOutlinedEditTextView$100 From 9873d44001123ac2d73a160aab3779488d1269e4 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 30 Jun 2022 17:24:50 +0300 Subject: [PATCH 082/173] Analysis: Resolve (no) wildcard imports detekt warnings for view ext Also, with this change the below such entries are removed from the Detekt related 'baseline.xml' file as it is no longer needed: - NoWildcardImports:com.woocommerce.android.extensions.ViewExt.kt:25 - WildcardImport:ViewExt.kt$import kotlinx.coroutines.flow.* --- .../kotlin/com/woocommerce/android/extensions/ViewExt.kt | 6 +++++- config/detekt/baseline.xml | 2 -- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt index 7892fb1302b..076d850ef18 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/ViewExt.kt @@ -21,7 +21,11 @@ import androidx.transition.Transition import androidx.transition.TransitionListenerAdapter import androidx.transition.TransitionManager import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map private const val EXPAND_COLLAPSE_ANIMATION_DURATION_MILLIS = 300L diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 1dedb07e011..2d2c68fd441 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -148,7 +148,6 @@ NoWildcardImports:com.woocommerce.android.cardreader.internal.payments.PaymentManager.kt:20 NoWildcardImports:com.woocommerce.android.extensions.DateExt.kt:10 NoWildcardImports:com.woocommerce.android.extensions.LiveDataExt.kt:3 - NoWildcardImports:com.woocommerce.android.extensions.ViewExt.kt:25 NoWildcardImports:com.woocommerce.android.media.MediaFilesRepository.kt:13 NoWildcardImports:com.woocommerce.android.media.MediaFilesRepository.kt:14 NoWildcardImports:com.woocommerce.android.media.MediaFilesRepository.kt:22 @@ -670,7 +669,6 @@ WildcardImport:VariationDetailFragment.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:VariationDetailViewModel.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:VariationListAdapter.kt$import com.woocommerce.android.ui.products.ProductStockStatus.* - WildcardImport:ViewExt.kt$import kotlinx.coroutines.flow.* WildcardImport:WCMaterialOutlinedCurrencyEditTextView.kt$import org.wordpress.android.fluxc.model.WCSettingsModel.CurrencyPosition.* WildcardImport:WooLogViewerScreen.kt$import androidx.compose.foundation.layout.* WildcardImport:WooLogViewerScreen.kt$import androidx.compose.material.* From b1dbb1bb11e792610ea65f21e2d3d3f2c136a2db Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 30 Jun 2022 17:35:10 +0300 Subject: [PATCH 083/173] Analysis: Resolve (no) wildcard imports detekt warnings for get stats Also, with this change the below such entries are removed from the Detekt related 'baseline.xml' file as it is no longer needed: - NoWildcardImports:com.woocommerce.android.ui.mystore.domain. GetStats.kt:11 - NoWildcardImports:com.woocommerce.android.ui.mystore.domain. GetStats.kt:7 - NoWildcardImports:com.woocommerce.android.ui.mystore.domain. GetStatsTest.kt:7 - WildcardImport:GetStats.kt$import com.woocommerce.android.ui.mystore. domain.GetStats.LoadStatsResult.* - WildcardImport:GetStats.kt$import kotlinx.coroutines.flow.* - WildcardImport:MyStoreViewModel.kt$import com.woocommerce.android.ui. mystore.domain.GetStats.LoadStatsResult.* --- .../android/ui/mystore/domain/GetStats.kt | 25 +++++++------- .../android/ui/mystore/domain/GetStatsTest.kt | 33 +++++++++---------- config/detekt/baseline.xml | 6 ---- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/domain/GetStats.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/domain/GetStats.kt index 2b66faa9760..9b6469087ea 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/domain/GetStats.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/domain/GetStats.kt @@ -4,10 +4,13 @@ import com.woocommerce.android.AppPrefsWrapper import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.mystore.data.StatsRepository import com.woocommerce.android.ui.mystore.data.StatsRepository.StatsException -import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.* import com.woocommerce.android.util.CoroutineDispatchers import com.woocommerce.android.util.FeatureFlag -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.transform import org.wordpress.android.fluxc.model.WCRevenueStatsModel import org.wordpress.android.fluxc.store.WCStatsStore.OrderStatsErrorType import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity @@ -26,13 +29,13 @@ class GetStats @Inject constructor( visitorStats(refresh, granularity) ).flowOn(coroutineDispatchers.computation) - private suspend fun hasOrders(): Flow = + private suspend fun hasOrders(): Flow = statsRepository.checkIfStoreHasNoOrders() .transform { if (it.getOrNull() == true) { - emit(HasOrders(false)) + emit(LoadStatsResult.HasOrders(false)) } else { - emit(HasOrders(true)) + emit(LoadStatsResult.HasOrders(true)) } } @@ -42,14 +45,14 @@ class GetStats @Inject constructor( result.fold( onSuccess = { stats -> appPrefsWrapper.setV4StatsSupported(true) - emit(RevenueStatsSuccess(stats)) + emit(LoadStatsResult.RevenueStatsSuccess(stats)) }, onFailure = { if (isPluginNotActiveError(it)) { appPrefsWrapper.setV4StatsSupported(false) - emit(PluginNotActive) + emit(LoadStatsResult.PluginNotActive) } else { - emit(RevenueStatsError) + emit(LoadStatsResult.RevenueStatsError) } } ) @@ -60,14 +63,14 @@ class GetStats @Inject constructor( statsRepository.fetchVisitorStats(granularity, forceRefresh) .transform { result -> result.fold( - onSuccess = { stats -> emit(VisitorsStatsSuccess(stats)) }, - onFailure = { emit(VisitorsStatsError) } + onSuccess = { stats -> emit(LoadStatsResult.VisitorsStatsSuccess(stats)) }, + onFailure = { emit(LoadStatsResult.VisitorsStatsError) } ) } } else { flow { if (FeatureFlag.JETPACK_CP.isEnabled()) { - emit(IsJetPackCPEnabled) + emit(LoadStatsResult.IsJetPackCPEnabled) } } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/domain/GetStatsTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/domain/GetStatsTest.kt index d595c90811d..be6d295ab21 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/domain/GetStatsTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/mystore/domain/GetStatsTest.kt @@ -4,7 +4,6 @@ import com.woocommerce.android.AppPrefsWrapper import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.mystore.data.StatsRepository import com.woocommerce.android.ui.mystore.data.StatsRepository.StatsException -import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.* import com.woocommerce.android.viewmodel.BaseUnitTest import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.collect @@ -53,10 +52,10 @@ class GetStatsTest : BaseUnitTest() { givenCheckIfStoreHasNoOrdersFlow(Result.success(true)) val result = getStats(refresh = false, granularity = ANY_GRANULARITY) - .filter { it is HasOrders } + .filter { it is GetStats.LoadStatsResult.HasOrders } .first() - assertThat(result).isEqualTo(HasOrders(false)) + assertThat(result).isEqualTo(GetStats.LoadStatsResult.HasOrders(false)) } @Test @@ -65,10 +64,10 @@ class GetStatsTest : BaseUnitTest() { givenCheckIfStoreHasNoOrdersFlow(Result.success(false)) val result = getStats(refresh = false, granularity = ANY_GRANULARITY) - .filter { it is HasOrders } + .filter { it is GetStats.LoadStatsResult.HasOrders } .first() - assertThat(result).isEqualTo(HasOrders(true)) + assertThat(result).isEqualTo(GetStats.LoadStatsResult.HasOrders(true)) } @Test @@ -77,10 +76,10 @@ class GetStatsTest : BaseUnitTest() { givenFetchRevenueStats(Result.success(ANY_REVENUE_STATS)) val result = getStats(refresh = false, granularity = ANY_GRANULARITY) - .filter { it is RevenueStatsSuccess } + .filter { it is GetStats.LoadStatsResult.RevenueStatsSuccess } .first() - assertThat(result).isEqualTo(RevenueStatsSuccess(ANY_REVENUE_STATS)) + assertThat(result).isEqualTo(GetStats.LoadStatsResult.RevenueStatsSuccess(ANY_REVENUE_STATS)) } @Test @@ -89,10 +88,10 @@ class GetStatsTest : BaseUnitTest() { givenFetchRevenueStats(Result.failure(StatsException(GENERIC_ORDER_STATS_ERROR))) val result = getStats(refresh = false, granularity = ANY_GRANULARITY) - .filter { it is RevenueStatsError } + .filter { it is GetStats.LoadStatsResult.RevenueStatsError } .first() - assertThat(result).isEqualTo(RevenueStatsError) + assertThat(result).isEqualTo(GetStats.LoadStatsResult.RevenueStatsError) } @Test @@ -101,10 +100,10 @@ class GetStatsTest : BaseUnitTest() { givenFetchRevenueStats(Result.failure(StatsException(PLUGIN_NOT_ACTIVE_ORDER_STATS_ERROR))) val result = getStats(refresh = false, granularity = ANY_GRANULARITY) - .filter { it is PluginNotActive } + .filter { it is GetStats.LoadStatsResult.PluginNotActive } .first() - assertThat(result).isEqualTo(PluginNotActive) + assertThat(result).isEqualTo(GetStats.LoadStatsResult.PluginNotActive) } @Test @@ -133,10 +132,10 @@ class GetStatsTest : BaseUnitTest() { givenFetchVisitorStats(Result.success(ANY_VISITOR_STATS)) val result = getStats(refresh = false, granularity = ANY_GRANULARITY) - .filter { it is VisitorsStatsSuccess } + .filter { it is GetStats.LoadStatsResult.VisitorsStatsSuccess } .first() - assertThat(result).isEqualTo(VisitorsStatsSuccess(ANY_VISITOR_STATS)) + assertThat(result).isEqualTo(GetStats.LoadStatsResult.VisitorsStatsSuccess(ANY_VISITOR_STATS)) } @Test @@ -145,10 +144,10 @@ class GetStatsTest : BaseUnitTest() { givenFetchVisitorStats(Result.failure(StatsException(GENERIC_ORDER_STATS_ERROR))) val result = getStats(refresh = false, granularity = ANY_GRANULARITY) - .filter { it is VisitorsStatsError } + .filter { it is GetStats.LoadStatsResult.VisitorsStatsError } .first() - assertThat(result).isEqualTo(VisitorsStatsError) + assertThat(result).isEqualTo(GetStats.LoadStatsResult.VisitorsStatsError) } @Test @@ -157,10 +156,10 @@ class GetStatsTest : BaseUnitTest() { givenIsJetpackConnected(true) val result = getStats(refresh = false, granularity = ANY_GRANULARITY) - .filter { it is IsJetPackCPEnabled } + .filter { it is GetStats.LoadStatsResult.IsJetPackCPEnabled } .first() - assertThat(result).isEqualTo(IsJetPackCPEnabled) + assertThat(result).isEqualTo(GetStats.LoadStatsResult.IsJetPackCPEnabled) } private suspend fun givenCheckIfStoreHasNoOrdersFlow(result: Result) { diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 2d2c68fd441..44c272ae4f0 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -225,9 +225,6 @@ NoWildcardImports:com.woocommerce.android.ui.mystore.MyStoreViewModel.kt:29 NoWildcardImports:com.woocommerce.android.ui.mystore.MyStoreViewModelTest.kt:18 NoWildcardImports:com.woocommerce.android.ui.mystore.data.StatsRepository.kt:15 - NoWildcardImports:com.woocommerce.android.ui.mystore.domain.GetStats.kt:11 - NoWildcardImports:com.woocommerce.android.ui.mystore.domain.GetStats.kt:7 - NoWildcardImports:com.woocommerce.android.ui.mystore.domain.GetStatsTest.kt:7 NoWildcardImports:com.woocommerce.android.ui.orders.OrderDetailViewModelTest.kt:20 NoWildcardImports:com.woocommerce.android.ui.orders.OrderDetailViewModelTest.kt:33 NoWildcardImports:com.woocommerce.android.ui.orders.OrderDetailViewModelTest.kt:36 @@ -551,8 +548,6 @@ WildcardImport:EditShippingLabelPackagesViewModel.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:EditShippingLabelPaymentFragment.kt$import com.woocommerce.android.extensions.* WildcardImport:FeatureAnnouncementDialogFragment.kt$import android.view.* - WildcardImport:GetStats.kt$import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.* - WildcardImport:GetStats.kt$import kotlinx.coroutines.flow.* WildcardImport:GroupedProductListFragment.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:InfiniteListHandler.kt$import androidx.compose.runtime.* WildcardImport:JetpackInstallProgressDialog.kt$import com.woocommerce.android.extensions.* @@ -580,7 +575,6 @@ WildcardImport:MoreMenuFragment.kt$import com.woocommerce.android.ui.moremenu.MoreMenuViewModel.MoreMenuEvent.* WildcardImport:MoveShippingItemViewModel.kt$import com.woocommerce.android.ui.orders.shippinglabels.creation.MoveShippingItemViewModel.DestinationPackage.* WildcardImport:MyStoreStatsView.kt$import com.woocommerce.android.extensions.* - WildcardImport:MyStoreViewModel.kt$import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.* WildcardImport:MyStoreViewModel.kt$import kotlinx.coroutines.flow.* WildcardImport:Notification.kt$import com.woocommerce.android.push.* WildcardImport:NotificationChannelType.kt$import com.woocommerce.android.push.NotificationChannelType.* From 8b10aafe54135e85936edb7cb321d959ef678463 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 30 Jun 2022 17:41:23 +0300 Subject: [PATCH 084/173] Analysis: Resolve (no) wildcard imports detekt warnings for media file Also, with this change the below such entries are removed from the Detekt related 'baseline.xml' file as it is no longer needed: - NoWildcardImports:com.woocommerce.android.ui.media. MediaFileUploadHandler.kt:13 - NoWildcardImports:com.woocommerce.android.ui.media. MediaFileUploadHandler.kt:21 - WildcardImport:MediaFileUploadHandler.kt$import com.woocommerce.android.ui.media.MediaFileUploadHandler.UploadStatus.* - WildcardImport:MediaFileUploadHandler.kt$import kotlinx.coroutines.flow.* --- .../ui/media/MediaFileUploadHandler.kt | 48 +++++++++++-------- config/detekt/baseline.xml | 4 -- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/media/MediaFileUploadHandler.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/media/MediaFileUploadHandler.kt index 4bfbd37ef70..f367ac4e475 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/media/MediaFileUploadHandler.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/media/MediaFileUploadHandler.kt @@ -10,14 +10,23 @@ import com.woocommerce.android.media.ProductImagesUploadWorker import com.woocommerce.android.media.ProductImagesUploadWorker.Event import com.woocommerce.android.media.ProductImagesUploadWorker.Work import com.woocommerce.android.media.ProductImagesUploadWorker.Work.UploadMedia -import com.woocommerce.android.ui.media.MediaFileUploadHandler.UploadStatus.* import com.woocommerce.android.ui.products.ProductDetailRepository import com.woocommerce.android.ui.products.ProductDetailViewModel import com.woocommerce.android.util.StringUtils import com.woocommerce.android.util.WooLog import com.woocommerce.android.viewmodel.ResourceProvider import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.filterIsInstance +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onCompletion +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.onSubscription +import kotlinx.coroutines.flow.update import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.model.MediaModel import org.wordpress.android.fluxc.store.MediaStore @@ -119,10 +128,10 @@ class MediaFileUploadHandler @Inject constructor( tag = WooLog.T.MEDIA, message = "MediaFileUploadHandler -> uploads finished for product $productId, check if we need to update it" ) - uploadsStatus.value.filter { it.remoteProductId == productId && it.uploadStatus !is Failed } - .takeIf { images -> images.none { it.uploadStatus == InProgress } && images.isNotEmpty() } + uploadsStatus.value.filter { it.remoteProductId == productId && it.uploadStatus !is UploadStatus.Failed } + .takeIf { images -> images.none { it.uploadStatus == UploadStatus.InProgress } && images.isNotEmpty() } ?.let { productImages -> - val uploadedImages = productImages.map { (it.uploadStatus as UploadSuccess).media } + val uploadedImages = productImages.map { (it.uploadStatus as UploadStatus.UploadSuccess).media } WooLog.d( WooLog.T.MEDIA, @@ -137,7 +146,7 @@ class MediaFileUploadHandler @Inject constructor( private fun showUploadFailureNotifIfNoObserver(productId: Long, state: List) { if (!externalObservers.contains(productId)) { WooLog.d(WooLog.T.MEDIA, "MediaFileUploadHandler -> post upload failure notification") - val errors = state.filter { it.remoteProductId == productId && it.uploadStatus is Failed } + val errors = state.filter { it.remoteProductId == productId && it.uploadStatus is UploadStatus.Failed } notificationHandler.postUploadFailureNotification(productDetailRepository.getProduct(productId), errors) } } @@ -145,7 +154,7 @@ class MediaFileUploadHandler @Inject constructor( private fun clearPendingUploads() { uploadsStatus.update { list -> list.filterNot { - it.uploadStatus is InProgress || it.uploadStatus is UploadSuccess + it.uploadStatus is UploadStatus.InProgress || it.uploadStatus is UploadStatus.UploadSuccess } } } @@ -156,7 +165,7 @@ class MediaFileUploadHandler @Inject constructor( ProductImageUploadData( remoteProductId = remoteProductId, localUri = it, - uploadStatus = InProgress + uploadStatus = UploadStatus.InProgress ) } } @@ -174,7 +183,7 @@ class MediaFileUploadHandler @Inject constructor( fun clearImageErrors(remoteProductId: Long) { uploadsStatus.update { list -> list.filterNot { - it.remoteProductId == remoteProductId && it.uploadStatus is Failed + it.remoteProductId == remoteProductId && it.uploadStatus is UploadStatus.Failed } } notificationHandler.removeUploadFailureNotification(remoteProductId) @@ -182,13 +191,13 @@ class MediaFileUploadHandler @Inject constructor( fun observeCurrentUploadErrors(remoteProductId: Long): Flow> = uploadsStatus.map { list -> - list.filter { it.remoteProductId == remoteProductId && it.uploadStatus is Failed } + list.filter { it.remoteProductId == remoteProductId && it.uploadStatus is UploadStatus.Failed } } fun observeCurrentUploads(remoteProductId: Long): Flow> { return uploadsStatus .map { list -> - list.filter { it.remoteProductId == remoteProductId && it.uploadStatus == InProgress } + list.filter { it.remoteProductId == remoteProductId && it.uploadStatus == UploadStatus.InProgress } .map { it.localUri } } } @@ -203,12 +212,12 @@ class MediaFileUploadHandler @Inject constructor( .onStart { // Start with the pending succeeded uploads, the observer will be able to handle them val pendingSuccessUploads = uploadsStatus.value.filter { - it.remoteProductId == remoteProductId && it.uploadStatus is UploadSuccess + it.remoteProductId == remoteProductId && it.uploadStatus is UploadStatus.UploadSuccess } if (pendingSuccessUploads.isNotEmpty()) { uploadsStatus.update { list -> list - pendingSuccessUploads } pendingSuccessUploads.forEach { - emit((it.uploadStatus as UploadSuccess).media) + emit((it.uploadStatus as UploadStatus.UploadSuccess).media) } } } @@ -226,7 +235,7 @@ class MediaFileUploadHandler @Inject constructor( uploadsStatus.update { list -> list.map { if (it.remoteProductId == ProductDetailViewModel.DEFAULT_ADD_NEW_PRODUCT_ID && - it.uploadStatus is UploadSuccess + it.uploadStatus is UploadStatus.UploadSuccess ) { it.copy(remoteProductId = productId) } else { @@ -236,7 +245,8 @@ class MediaFileUploadHandler @Inject constructor( } // Cancel and reschedule ongoing uploads val ongoingUploads = uploadsStatus.value.filter { - it.remoteProductId == ProductDetailViewModel.DEFAULT_ADD_NEW_PRODUCT_ID && it.uploadStatus == InProgress + it.remoteProductId == ProductDetailViewModel.DEFAULT_ADD_NEW_PRODUCT_ID && it.uploadStatus == + UploadStatus.InProgress } if (ongoingUploads.isNotEmpty()) { cancelUpload(ProductDetailViewModel.DEFAULT_ADD_NEW_PRODUCT_ID) @@ -246,18 +256,18 @@ class MediaFileUploadHandler @Inject constructor( private fun Event.MediaUploadEvent.toStatus(): ProductImageUploadData { val uploadStatus = when (this) { - is Event.MediaUploadEvent.FetchFailed -> Failed( + is Event.MediaUploadEvent.FetchFailed -> UploadStatus.Failed( media = MediaModel(), mediaErrorMessage = resourceProvider.getString(R.string.product_image_service_error_media_null), mediaErrorType = MediaStore.MediaErrorType.NULL_MEDIA_ARG ) - is Event.MediaUploadEvent.FetchSucceeded -> InProgress - is Event.MediaUploadEvent.UploadFailed -> Failed( + is Event.MediaUploadEvent.FetchSucceeded -> UploadStatus.InProgress + is Event.MediaUploadEvent.UploadFailed -> UploadStatus.Failed( media = error.media, mediaErrorMessage = error.errorMessage, mediaErrorType = error.errorType ) - is Event.MediaUploadEvent.UploadSucceeded -> UploadSuccess(media = media) + is Event.MediaUploadEvent.UploadSucceeded -> UploadStatus.UploadSuccess(media = media) } return ProductImageUploadData( remoteProductId = productId, diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 44c272ae4f0..59a028da5fb 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -212,8 +212,6 @@ NoWildcardImports:com.woocommerce.android.ui.main.MainActivityViewModelTest.kt:7 NoWildcardImports:com.woocommerce.android.ui.main.MainActivityViewModelTest.kt:9 NoWildcardImports:com.woocommerce.android.ui.main.MainPresenterTest.kt:17 - NoWildcardImports:com.woocommerce.android.ui.media.MediaFileUploadHandler.kt:13 - NoWildcardImports:com.woocommerce.android.ui.media.MediaFileUploadHandler.kt:21 NoWildcardImports:com.woocommerce.android.ui.moremenu.MoreMenu.kt:11 NoWildcardImports:com.woocommerce.android.ui.moremenu.MoreMenu.kt:17 NoWildcardImports:com.woocommerce.android.ui.moremenu.MoreMenuFragment.kt:18 @@ -565,8 +563,6 @@ WildcardImport:MainSettingsFragment.kt$import com.woocommerce.android.analytics.AnalyticsEvent.* WildcardImport:MainSettingsFragment.kt$import com.woocommerce.android.util.* WildcardImport:MarkAllReviewsAsSeen.kt$import com.woocommerce.android.model.RequestResult.* - WildcardImport:MediaFileUploadHandler.kt$import com.woocommerce.android.ui.media.MediaFileUploadHandler.UploadStatus.* - WildcardImport:MediaFileUploadHandler.kt$import kotlinx.coroutines.flow.* WildcardImport:MediaFilesRepository.kt$import kotlinx.coroutines.channels.* WildcardImport:MediaFilesRepository.kt$import kotlinx.coroutines.flow.* WildcardImport:MediaFilesRepository.kt$import org.wordpress.android.fluxc.store.MediaStore.* From 7e378585007c42b8acfa77c363b16c7dd93aed3e Mon Sep 17 00:00:00 2001 From: Alejo Date: Thu, 30 Jun 2022 11:45:48 -0300 Subject: [PATCH 085/173] fix animations --- .../ui/orders/creation/OrderCreationFormFragment.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt index 0488d312801..81e37d2837e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt @@ -2,6 +2,7 @@ package com.woocommerce.android.ui.orders.creation import android.annotation.SuppressLint import android.os.Bundle +import android.transition.AutoTransition import android.transition.TransitionManager import android.view.Menu import android.view.MenuInflater @@ -64,6 +65,16 @@ class OrderCreationFormFragment : BaseFragment(R.layout.fragment_order_creation_ ) } + private val transition by lazy { + AutoTransition().apply { + excludeChildren(R.id.order_status_view, true) + excludeChildren(R.id.products_section, true) + excludeChildren(R.id.payment_section, true) + excludeChildren(R.id.customer_section, true) + excludeChildren(R.id.notes_section, true) + } + } + override val activityAppBarStatus: AppBarStatus get() = AppBarStatus.Visible( navigationIcon = when (viewModel.mode) { @@ -228,7 +239,7 @@ class OrderCreationFormFragment : BaseFragment(R.layout.fragment_order_creation_ createOrderMenuItem?.isEnabled = it } new.isIdle.takeIfNotEqualTo(old?.isIdle) { enabled -> - TransitionManager.beginDelayedTransition(binding.root) + TransitionManager.beginDelayedTransition(binding.root, transition) when (viewModel.mode) { OrderCreationViewModel.Mode.Creation -> { binding.paymentSection.loadingProgress.isVisible = !enabled From 3e2279cbfc7f3df26ba52b3ecb8cdce7a8ff0eeb Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 30 Jun 2022 17:47:10 +0300 Subject: [PATCH 086/173] Analysis: Resolve (no) wildcard imports detekt warnings for media files Also, with this change the below such entries are removed from the Detekt related 'baseline.xml' file as it is no longer needed: - NoWildcardImports:com.woocommerce.android.media. MediaFilesRepository.kt:13 - NoWildcardImports:com.woocommerce.android.media. MediaFilesRepository.kt:14 - NoWildcardImports:com.woocommerce.android.media. MediaFilesRepository.kt:22 - WildcardImport:MediaFilesRepository.kt$import kotlinx.coroutines.channels.* - WildcardImport:MediaFilesRepository.kt$import kotlinx.coroutines.flow.* - WildcardImport:MediaFilesRepository.kt$import org.wordpress.android.fluxc.store.MediaStore.* --- .../android/media/MediaFilesRepository.kt | 21 ++++++++++++------- config/detekt/baseline.xml | 6 ------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt index 4056b38707a..c2894c7dde5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt @@ -11,8 +11,15 @@ import com.woocommerce.android.util.WooLog import com.woocommerce.android.util.WooLog.T import com.woocommerce.android.viewmodel.ResourceProvider import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.channels.* -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.channels.ProducerScope +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.channels.onFailure +import kotlinx.coroutines.channels.trySendBlocking +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.withContext import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode @@ -20,8 +27,6 @@ import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.generated.MediaActionBuilder import org.wordpress.android.fluxc.model.MediaModel import org.wordpress.android.fluxc.store.MediaStore -import org.wordpress.android.fluxc.store.MediaStore.* -import org.wordpress.android.fluxc.store.MediaStore.MediaErrorType.GENERIC_ERROR import org.wordpress.android.mediapicker.MediaPickerUtils import java.io.File import javax.inject.Inject @@ -58,14 +63,14 @@ class MediaFilesRepository @Inject constructor( WooLog.d(T.MEDIA, "MediaFilesRepository > Dispatching request to upload ${localMediaModel.filePath}") val listener = OnMediaUploadListener(this) dispatcher.register(listener) - val payload = UploadMediaPayload(selectedSite.get(), localMediaModel, stripLocation) + val payload = MediaStore.UploadMediaPayload(selectedSite.get(), localMediaModel, stripLocation) dispatcher.dispatch(MediaActionBuilder.newUploadMediaAction(payload)) awaitClose { dispatcher.unregister(listener) // Cancel upload if the collection was cancelled before completion if (!isClosedForSend) { - val payload = CancelMediaPayload(selectedSite.get(), localMediaModel, true) + val payload = MediaStore.CancelMediaPayload(selectedSite.get(), localMediaModel, true) dispatcher.dispatch(MediaActionBuilder.newCancelMediaUploadAction(payload)) } } @@ -105,7 +110,7 @@ class MediaFilesRepository @Inject constructor( @Suppress("LongMethod") @SuppressWarnings("unused") @Subscribe(threadMode = ThreadMode.BACKGROUND) - fun onMediaUploaded(event: OnMediaUploaded) { + fun onMediaUploaded(event: MediaStore.OnMediaUploaded) { when { event.isError -> { WooLog.w( @@ -146,7 +151,7 @@ class MediaFilesRepository @Inject constructor( UploadFailure( error = MediaUploadException( event.media, - GENERIC_ERROR, + MediaStore.MediaErrorType.GENERIC_ERROR, resourceProvider.getString(R.string.product_image_service_error_uploading) ) ) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 59a028da5fb..e67d67bddee 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -148,9 +148,6 @@ NoWildcardImports:com.woocommerce.android.cardreader.internal.payments.PaymentManager.kt:20 NoWildcardImports:com.woocommerce.android.extensions.DateExt.kt:10 NoWildcardImports:com.woocommerce.android.extensions.LiveDataExt.kt:3 - NoWildcardImports:com.woocommerce.android.media.MediaFilesRepository.kt:13 - NoWildcardImports:com.woocommerce.android.media.MediaFilesRepository.kt:14 - NoWildcardImports:com.woocommerce.android.media.MediaFilesRepository.kt:22 NoWildcardImports:com.woocommerce.android.media.ProductImagesUploadWorker.kt:13 NoWildcardImports:com.woocommerce.android.media.ProductImagesUploadWorker.kt:14 NoWildcardImports:com.woocommerce.android.media.ProductImagesUploadWorker.kt:4 @@ -563,9 +560,6 @@ WildcardImport:MainSettingsFragment.kt$import com.woocommerce.android.analytics.AnalyticsEvent.* WildcardImport:MainSettingsFragment.kt$import com.woocommerce.android.util.* WildcardImport:MarkAllReviewsAsSeen.kt$import com.woocommerce.android.model.RequestResult.* - WildcardImport:MediaFilesRepository.kt$import kotlinx.coroutines.channels.* - WildcardImport:MediaFilesRepository.kt$import kotlinx.coroutines.flow.* - WildcardImport:MediaFilesRepository.kt$import org.wordpress.android.fluxc.store.MediaStore.* WildcardImport:MoreMenu.kt$import androidx.compose.foundation.layout.* WildcardImport:MoreMenu.kt$import androidx.compose.material.* WildcardImport:MoreMenuFragment.kt$import com.woocommerce.android.ui.moremenu.MoreMenuViewModel.MoreMenuEvent.* From 15a5f0ae0269fa53392e0f7ad4067d2d1d586c6a Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Thu, 30 Jun 2022 18:03:12 +0300 Subject: [PATCH 087/173] Analysis: Resolve regexp single line checkstyle error for media files This is a custom CheckStyle error that needed a specific import for FluxC Store purposes, see full error message below: "[ant:checkstyle] [ERROR] .../WooCommerce/src/main/kotlin/com/ woocommerce/android/media/MediaFilesRepository.kt:113: Specific imports should be used for FluxC Store inner classes [RegexpSingleline]" --- .../com/woocommerce/android/media/MediaFilesRepository.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt index c2894c7dde5..07d55a6a3e3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/media/MediaFilesRepository.kt @@ -27,6 +27,7 @@ import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.generated.MediaActionBuilder import org.wordpress.android.fluxc.model.MediaModel import org.wordpress.android.fluxc.store.MediaStore +import org.wordpress.android.fluxc.store.MediaStore.OnMediaUploaded import org.wordpress.android.mediapicker.MediaPickerUtils import java.io.File import javax.inject.Inject @@ -110,7 +111,7 @@ class MediaFilesRepository @Inject constructor( @Suppress("LongMethod") @SuppressWarnings("unused") @Subscribe(threadMode = ThreadMode.BACKGROUND) - fun onMediaUploaded(event: MediaStore.OnMediaUploaded) { + fun onMediaUploaded(event: OnMediaUploaded) { when { event.isError -> { WooLog.w( From f9a53818b9e994e38f6e03138827bf3d402875fb Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 30 Jun 2022 12:41:02 -0400 Subject: [PATCH 088/173] Don't show empty view when searching if the query is empty --- .../android/ui/products/ProductListViewModel.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt index 4381edfb605..446317024c9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt @@ -305,13 +305,19 @@ class ProductListViewModel @Inject constructor( !isSearching() } + val shouldShowEmptyView = if (isSearching()) { + viewState.query?.isNotEmpty() == true + } else { + _productList.value?.isEmpty() == true + } + viewState = viewState.copy( isSkeletonShown = false, isLoading = false, isLoadingMore = false, isRefreshing = false, canLoadMore = productRepository.canLoadMoreProducts, - isEmptyViewVisible = _productList.value?.isEmpty() == true, + isEmptyViewVisible = shouldShowEmptyView, isAddProductButtonVisible = shouldShowAddProductButton, displaySortAndFilterCard = !isSearching() && (productFilterOptions.isNotEmpty() || _productList.value?.isNotEmpty() == true) From 893fb250d67ff7b69a4bbaff697ed8d26d97a563 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 30 Jun 2022 13:11:35 -0400 Subject: [PATCH 089/173] don't update the product list if a search was initiated while fetching --- .../android/ui/products/ProductListViewModel.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt index 446317024c9..e7753d4a5f0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt @@ -352,9 +352,15 @@ class ProductListViewModel @Inject constructor( loadMore: Boolean = false, scrollToTop: Boolean = false ) { - if (searchQuery.isNullOrEmpty()) { - _productList.value = productRepository.fetchProductList(loadMore, productFilterOptions) - } else { + if (!isSearching()) { + val products = productRepository.fetchProductList(loadMore, productFilterOptions) + // don't update the product list if a search was initiated while fetching + if (isSearching()) { + WooLog.i(WooLog.T.PRODUCTS, "Search initiated while fetching products") + } else { + _productList.value = products + } + } else if (searchQuery?.isNotEmpty() == true) { productRepository.searchProductList(searchQuery, loadMore)?.let { fetchedProducts -> // make sure the search query hasn't changed while the fetch was processing if (searchQuery == productRepository.lastSearchQuery) { From ad0c4e83c260ade163a4483b1e6a328146b883c8 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 30 Jun 2022 13:21:11 -0400 Subject: [PATCH 090/173] Don't show empty view when search results are found --- .../com/woocommerce/android/ui/products/ProductListViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt index e7753d4a5f0..045670ef945 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListViewModel.kt @@ -306,7 +306,7 @@ class ProductListViewModel @Inject constructor( } val shouldShowEmptyView = if (isSearching()) { - viewState.query?.isNotEmpty() == true + viewState.query?.isNotEmpty() == true && _productList.value?.isEmpty() == true } else { _productList.value?.isEmpty() == true } From 42e15e5d592fa959f672437002d53471b9774cfe Mon Sep 17 00:00:00 2001 From: Alejo Date: Thu, 30 Jun 2022 14:30:14 -0300 Subject: [PATCH 091/173] temporarily remove transitions --- .../ui/orders/creation/OrderCreationFormFragment.kt | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt index 81e37d2837e..6dd8179aa44 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt @@ -2,8 +2,6 @@ package com.woocommerce.android.ui.orders.creation import android.annotation.SuppressLint import android.os.Bundle -import android.transition.AutoTransition -import android.transition.TransitionManager import android.view.Menu import android.view.MenuInflater import android.view.MenuItem @@ -65,16 +63,6 @@ class OrderCreationFormFragment : BaseFragment(R.layout.fragment_order_creation_ ) } - private val transition by lazy { - AutoTransition().apply { - excludeChildren(R.id.order_status_view, true) - excludeChildren(R.id.products_section, true) - excludeChildren(R.id.payment_section, true) - excludeChildren(R.id.customer_section, true) - excludeChildren(R.id.notes_section, true) - } - } - override val activityAppBarStatus: AppBarStatus get() = AppBarStatus.Visible( navigationIcon = when (viewModel.mode) { @@ -239,7 +227,6 @@ class OrderCreationFormFragment : BaseFragment(R.layout.fragment_order_creation_ createOrderMenuItem?.isEnabled = it } new.isIdle.takeIfNotEqualTo(old?.isIdle) { enabled -> - TransitionManager.beginDelayedTransition(binding.root, transition) when (viewModel.mode) { OrderCreationViewModel.Mode.Creation -> { binding.paymentSection.loadingProgress.isVisible = !enabled From 697c1351f0aff98f9cd5d2b3f0f6cccf9b50d793 Mon Sep 17 00:00:00 2001 From: Alejo Date: Thu, 30 Jun 2022 17:42:38 -0300 Subject: [PATCH 092/173] add sync strategy --- .../ui/orders/creation/AutoSyncOrder.kt | 13 ++- .../orders/creation/AutoSyncPriceModifier.kt | 13 ++- .../creation/CreateOrUpdateOrderDraft.kt | 97 ------------------- .../ui/orders/creation/CreateUpdateOrder.kt | 9 +- .../ui/orders/creation/SyncStrategy.kt | 8 ++ 5 files changed, 25 insertions(+), 115 deletions(-) delete mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateOrUpdateOrderDraft.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategy.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt index 738c0ee18c9..f98db91f950 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt @@ -3,16 +3,12 @@ package com.woocommerce.android.ui.orders.creation import com.woocommerce.android.extensions.areSameAs import com.woocommerce.android.extensions.isEqualTo import com.woocommerce.android.model.Order -import com.woocommerce.android.util.CoroutineDispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import javax.inject.Inject -class AutoSyncOrder @Inject constructor( - dispatchers: CoroutineDispatchers, - orderCreationRepository: OrderCreationRepository -) : CreateUpdateOrder(dispatchers, orderCreationRepository) { +class AutoSyncOrder @Inject constructor(val createUpdateOrderUseCase: CreateUpdateOrder) : SyncStrategy { private fun areEquivalent(old: Order, new: Order): Boolean { // Make sure to update the prices only when items did change val hasSameItems = old.items @@ -60,8 +56,11 @@ class AutoSyncOrder @Inject constructor( } @OptIn(ExperimentalCoroutinesApi::class) - override fun invoke(changes: Flow, retryTrigger: Flow): Flow { - return super.invoke( + override fun syncOrderChanges( + changes: Flow, + retryTrigger: Flow + ): Flow { + return createUpdateOrderUseCase( changes.distinctUntilChanged(::areEquivalent), retryTrigger ) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt index a2fb1b0c6d0..9ebe05637ed 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt @@ -3,17 +3,13 @@ package com.woocommerce.android.ui.orders.creation import com.woocommerce.android.extensions.areSameAs import com.woocommerce.android.extensions.isEqualTo import com.woocommerce.android.model.Order -import com.woocommerce.android.util.CoroutineDispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import javax.inject.Inject -class AutoSyncPriceModifier @Inject constructor( - dispatchers: CoroutineDispatchers, - orderCreationRepository: OrderCreationRepository -) : CreateUpdateOrder(dispatchers, orderCreationRepository) { +class AutoSyncPriceModifier @Inject constructor(val createUpdateOrderUseCase: CreateUpdateOrder) : SyncStrategy { /** * Anything that can be modified during the Order Creation flow that can affect * the Order total price should be accounted here @@ -61,8 +57,11 @@ class AutoSyncPriceModifier @Inject constructor( } @OptIn(ExperimentalCoroutinesApi::class) - override fun invoke(changes: Flow, retryTrigger: Flow): Flow { - return super.invoke( + override fun syncOrderChanges( + changes: Flow, + retryTrigger: Flow + ): Flow { + return createUpdateOrderUseCase( changes .filter { it.containsPriceModifiers() } .distinctUntilChanged(::arePriceModifiersEquivalent), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateOrUpdateOrderDraft.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateOrUpdateOrderDraft.kt deleted file mode 100644 index ca2284790fc..00000000000 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateOrUpdateOrderDraft.kt +++ /dev/null @@ -1,97 +0,0 @@ -package com.woocommerce.android.ui.orders.creation - -import com.woocommerce.android.extensions.areSameAs -import com.woocommerce.android.extensions.isEqualTo -import com.woocommerce.android.model.Order -import com.woocommerce.android.util.CoroutineDispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.* -import javax.inject.Inject - -class CreateOrUpdateOrderDraft @Inject constructor( - private val dispatchers: CoroutineDispatchers, - private val orderCreationRepository: OrderCreationRepository -) { - companion object { - const val DEBOUNCE_DURATION_MS = 500L - } - - @OptIn(ExperimentalCoroutinesApi::class) - operator fun invoke(changes: Flow, retryTrigger: Flow): Flow { - return changes - .distinctUntilChanged(::areEquivalent) - .flowOn(dispatchers.computation) - .flatMapLatest { - val debouncedChanges = flow { - // We can't use `debounce` directly, because we want to cancel any current update - // when we get new changes, hence the use of `flatMapLatest` + `delay` - delay(DEBOUNCE_DURATION_MS) - emit(it) - } - debouncedChanges - .combine(retryTrigger.onStart { emit(Unit) }) { draft, _ -> draft } - .flatMapLatest { createOrUpdateDraft(it) } - .onStart { emit(OrderDraftUpdateStatus.PendingDebounce) } - .distinctUntilChanged() - } - } - - private fun createOrUpdateDraft(order: Order) = flow { - emit(OrderDraftUpdateStatus.Ongoing) - orderCreationRepository.createOrUpdateDraft(order) - .fold( - onSuccess = { emit(OrderDraftUpdateStatus.Succeeded(it)) }, - onFailure = { emit(OrderDraftUpdateStatus.Failed) } - ) - } - - sealed interface OrderDraftUpdateStatus { - object PendingDebounce : OrderDraftUpdateStatus - object Ongoing : OrderDraftUpdateStatus - data class Succeeded(val order: Order) : OrderDraftUpdateStatus - object Failed : OrderDraftUpdateStatus - } - - private fun areEquivalent(old: Order, new: Order): Boolean { - // Make sure to update the prices only when items did change - val hasSameItems = old.items - .filter { - // Check only non-zero quantities, to avoid circular update when removing products - it.quantity > 0 - } - .areSameAs(new.items) { newItem -> - // TODO M3: we need probably to compare the totals too, to account for discounts - this.productId == newItem.productId && - this.variationId == newItem.variationId && - this.quantity == newItem.quantity - } - - val hasSameShippingLines = old.shippingLines - .filter { - // Check only non-removed shipping lines to avoid circular update when removing - it.methodId != null - } - .areSameAs(new.shippingLines) { newLine -> - this.methodId == newLine.methodId && - this.methodTitle == newLine.methodTitle && - this.total isEqualTo newLine.total - } - - val hasSameFeeLines = old.feesLines - .filter { it.name != null } - .areSameAs(new.feesLines) { newLine -> - this.name == newLine.name && - this.total isEqualTo newLine.total - } - - val hasSameStatus = old.status == new.status - - return hasSameItems && - hasSameShippingLines && - hasSameFeeLines && - old.shippingAddress.isSamePhysicalAddress(new.shippingAddress) && - old.billingAddress.isSamePhysicalAddress(new.billingAddress) && - hasSameStatus - } -} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt index cab4b4149a9..5fbbc6bfdc2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt @@ -11,10 +11,11 @@ import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.onStart +import javax.inject.Inject -open class CreateUpdateOrder( - protected val dispatchers: CoroutineDispatchers, - protected val orderCreationRepository: OrderCreationRepository +class CreateUpdateOrder @Inject constructor( + private val dispatchers: CoroutineDispatchers, + private val orderCreationRepository: OrderCreationRepository ) { companion object { const val DEBOUNCE_DURATION_MS = 500L @@ -37,7 +38,7 @@ open class CreateUpdateOrder( } @OptIn(ExperimentalCoroutinesApi::class) - open operator fun invoke(changes: Flow, retryTrigger: Flow): Flow { + operator fun invoke(changes: Flow, retryTrigger: Flow): Flow { return changes .flowOn(dispatchers.computation) .flatMapLatest { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategy.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategy.kt new file mode 100644 index 00000000000..f80e157bd4b --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategy.kt @@ -0,0 +1,8 @@ +package com.woocommerce.android.ui.orders.creation + +import com.woocommerce.android.model.Order +import kotlinx.coroutines.flow.Flow + +interface SyncStrategy { + fun syncOrderChanges(changes: Flow, retryTrigger: Flow): Flow +} From f15b7ce35b809067828aef765d90be30a2d25a53 Mon Sep 17 00:00:00 2001 From: Alejo Date: Thu, 30 Jun 2022 17:44:00 -0300 Subject: [PATCH 093/173] order creation view model use a sync strategy --- .../orders/creation/OrderCreationViewModel.kt | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt index 5b61f662077..975777640bc 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt @@ -1,7 +1,6 @@ package com.woocommerce.android.ui.orders.creation import android.os.Parcelable -import androidx.annotation.VisibleForTesting import androidx.lifecycle.LiveData import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asLiveData @@ -70,6 +69,8 @@ class OrderCreationViewModel @Inject constructor( private val orderCreationRepository: OrderCreationRepository, private val mapItemToProductUiModel: MapItemToProductUiModel, private val createOrderItem: CreateOrderItem, + autoSyncOrder: AutoSyncOrder, + autoSyncPriceModifier: AutoSyncPriceModifier, parameterRepository: ParameterRepository ) : ScopedViewModel(savedState) { companion object { @@ -105,10 +106,10 @@ class OrderCreationViewModel @Inject constructor( private val retryOrderDraftUpdateTrigger = MutableSharedFlow(extraBufferCapacity = 1) - private val createOrUpdateOrder = + private val syncStrategy = when (mode) { - Mode.Creation -> AutoSyncPriceModifier(dispatchers, orderCreationRepository) - is Mode.Edit -> AutoSyncOrder(dispatchers, orderCreationRepository) + Mode.Creation -> autoSyncPriceModifier + is Mode.Edit -> autoSyncOrder } fun getProductUIModelFromItem(item: Order.Item) = runBlocking { @@ -299,31 +300,28 @@ class OrderCreationViewModel @Inject constructor( */ private fun monitorOrderChanges() { viewModelScope.launch { - createOrUpdateOrder(_orderDraft.drop(1), retryOrderDraftUpdateTrigger) - .collect { updateStatus -> onOrderStatusChange(updateStatus) } - } - } - - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - fun onOrderStatusChange(updateStatus: OrderUpdateStatus) { - when (updateStatus) { - OrderUpdateStatus.PendingDebounce -> - viewState = viewState.copy(willUpdateOrderDraft = true, showOrderUpdateSnackbar = false) - OrderUpdateStatus.Ongoing -> - viewState = viewState.copy(willUpdateOrderDraft = false, isUpdatingOrderDraft = true) - OrderUpdateStatus.Failed -> - viewState = viewState.copy(isUpdatingOrderDraft = false, showOrderUpdateSnackbar = true) - is OrderUpdateStatus.Succeeded -> { - viewState = viewState.copy( - isUpdatingOrderDraft = false, - showOrderUpdateSnackbar = false, - isEditable = updateStatus.order.isEditable || mode is Mode.Creation - ) - _orderDraft.update { currentDraft -> - // Keep the user's selected status - updateStatus.order.copy(status = currentDraft.status) + syncStrategy.syncOrderChanges(_orderDraft.drop(1), retryOrderDraftUpdateTrigger) + .collect { updateStatus -> + when (updateStatus) { + OrderUpdateStatus.PendingDebounce -> + viewState = viewState.copy(willUpdateOrderDraft = true, showOrderUpdateSnackbar = false) + OrderUpdateStatus.Ongoing -> + viewState = viewState.copy(willUpdateOrderDraft = false, isUpdatingOrderDraft = true) + OrderUpdateStatus.Failed -> + viewState = viewState.copy(isUpdatingOrderDraft = false, showOrderUpdateSnackbar = true) + is OrderUpdateStatus.Succeeded -> { + viewState = viewState.copy( + isUpdatingOrderDraft = false, + showOrderUpdateSnackbar = false, + isEditable = updateStatus.order.isEditable || mode is Mode.Creation + ) + _orderDraft.update { currentDraft -> + // Keep the user's selected status + updateStatus.order.copy(status = currentDraft.status) + } + } + } } - } } } From 175b33a10b06d52ef661f2e6d219f3afae667cb2 Mon Sep 17 00:00:00 2001 From: Alejo Date: Thu, 30 Jun 2022 18:42:59 -0300 Subject: [PATCH 094/173] fix unit tests --- ...eationFocusedOrderCreationViewModelTest.kt | 44 +++++++++++++++---- .../EditFocusedOrderCreationViewModelTest.kt | 13 +++++- .../creation/UnifiedOrderEditViewModelTest.kt | 18 +++++--- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreationFocusedOrderCreationViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreationFocusedOrderCreationViewModelTest.kt index ddefc02e838..9df118f3a33 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreationFocusedOrderCreationViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreationFocusedOrderCreationViewModelTest.kt @@ -22,11 +22,14 @@ import com.woocommerce.android.viewmodel.MultiLiveEvent.Event import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowDialog import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.fail import org.junit.Test +import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock +import org.mockito.kotlin.verify import org.wordpress.android.fluxc.network.rest.wpcom.wc.order.CoreOrderStatus import java.math.BigDecimal @@ -34,6 +37,11 @@ import java.math.BigDecimal class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest() { override val mode: Mode = Creation + @Test + fun `when initializing the view model, then register the orderDraft flowState`() { + verify(createUpdateOrderUseCase).invoke(any(), any()) + } + @Test fun `when submitting customer note, then update orderDraft liveData`() { var orderDraft: Order? = null @@ -533,8 +541,12 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( @Test fun `when OrderDraftUpdateStatus is WillStart, then adjust view state to reflect the loading preparation`() { + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(PendingDebounce) + } + createSut() + var viewState: ViewState? = null - sut.onOrderStatusChange(PendingDebounce) sut.viewStateData.observeForever { _, new -> viewState = new @@ -548,9 +560,12 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( @Test fun `when OrderDraftUpdateStatus is Ongoing, then adjust view state to reflect the loading`() { - var viewState: ViewState? = null + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Ongoing) + } + createSut() - sut.onOrderStatusChange(Ongoing) + var viewState: ViewState? = null sut.viewStateData.observeForever { _, new -> viewState = new @@ -565,6 +580,10 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( @Test fun `when OrderDraftUpdateStatus is Succeeded, then adjust view state to reflect the loading end`() { val modifiedOrderValue = defaultOrderValue.copy(id = 999) + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(modifiedOrderValue)) + } + createSut() var viewState: ViewState? = null var orderDraft: Order? = null @@ -577,8 +596,6 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( orderDraft = it } - sut.onOrderStatusChange(Succeeded(modifiedOrderValue)) - assertThat(viewState).isNotNull assertThat(viewState?.willUpdateOrderDraft).isFalse assertThat(viewState?.isUpdatingOrderDraft).isFalse @@ -590,9 +607,12 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( @Test fun `when OrderDraftUpdateStatus is Failed, then adjust view state to reflect the failure`() { - var viewState: ViewState? = null + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Failed) + } + createSut() - sut.onOrderStatusChange(Failed) + var viewState: ViewState? = null sut.viewStateData.observeForever { _, new -> viewState = new @@ -681,22 +701,28 @@ class CreationFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest( @Test fun `when isEditable is true on the create flow the order is editable`() { // When the order is on Creation mode is always editable + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(defaultOrderValue.copy(isEditable = true))) + } + createSut() var lastReceivedState: ViewState? = null sut.viewStateData.liveData.observeForever { lastReceivedState = it } - sut.onOrderStatusChange(Succeeded(defaultOrderValue.copy(isEditable = true))) assertThat(lastReceivedState?.isEditable).isEqualTo(true) } @Test fun `when isEditable is false on the edit flow the order is editable`() { // When the order is on Creation mode is always editable + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(defaultOrderValue.copy(isEditable = false))) + } + createSut() var lastReceivedState: ViewState? = null sut.viewStateData.liveData.observeForever { lastReceivedState = it } - sut.onOrderStatusChange(Succeeded(defaultOrderValue.copy(isEditable = false))) assertThat(lastReceivedState?.isEditable).isEqualTo(true) } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreationViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreationViewModelTest.kt index d2068b05ef2..5ec36f28c78 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreationViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/EditFocusedOrderCreationViewModelTest.kt @@ -7,11 +7,14 @@ import com.woocommerce.android.ui.orders.creation.OrderCreationViewModel.Mode.Ed import com.woocommerce.android.viewmodel.MultiLiveEvent.Event import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf import org.assertj.core.api.Assertions.assertThat import org.junit.Test import org.junit.runner.RunWith import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.stub @ExperimentalCoroutinesApi @@ -67,21 +70,27 @@ class EditFocusedOrderCreationViewModelTest : UnifiedOrderEditViewModelTest() { @Test fun `when isEditable is true on the edit flow the order is editable`() { + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(defaultOrderValue.copy(isEditable = true))) + } + createSut() var lastReceivedState: OrderCreationViewModel.ViewState? = null sut.viewStateData.liveData.observeForever { lastReceivedState = it } - sut.onOrderStatusChange(Succeeded(defaultOrderValue.copy(isEditable = true))) assertThat(lastReceivedState?.isEditable).isEqualTo(true) } @Test fun `when isEditable is false on the edit flow the order is NOT editable`() { + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(defaultOrderValue.copy(isEditable = false))) + } + createSut() var lastReceivedState: OrderCreationViewModel.ViewState? = null sut.viewStateData.liveData.observeForever { lastReceivedState = it } - sut.onOrderStatusChange(Succeeded(defaultOrderValue.copy(isEditable = false))) assertThat(lastReceivedState?.isEditable).isEqualTo(false) } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt index 98d4f03da21..908def1f153 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt @@ -3,19 +3,20 @@ package com.woocommerce.android.ui.orders.creation import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import com.woocommerce.android.model.Order +import com.woocommerce.android.ui.orders.creation.CreateUpdateOrder.OrderUpdateStatus.Succeeded import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.products.ParameterRepository import com.woocommerce.android.ui.products.ProductStockStatus import com.woocommerce.android.ui.products.models.SiteParameters import com.woocommerce.android.viewmodel.BaseUnitTest import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf import org.junit.Before import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.spy -import org.mockito.kotlin.stub @ExperimentalCoroutinesApi abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { @@ -23,6 +24,9 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { protected lateinit var viewState: OrderCreationViewModel.ViewState protected lateinit var savedState: SavedStateHandle protected lateinit var mapItemToProductUIModel: MapItemToProductUiModel + protected lateinit var createUpdateOrderUseCase: CreateUpdateOrder + protected lateinit var autoSyncPriceModifier: AutoSyncPriceModifier + protected lateinit var autoSyncOrder: AutoSyncOrder protected lateinit var createOrderItemUseCase: CreateOrderItem protected lateinit var orderCreationRepository: OrderCreationRepository protected lateinit var orderDetailRepository: OrderDetailRepository @@ -46,6 +50,9 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { on { getLiveData(viewState.javaClass.name, viewState) } doReturn MutableLiveData(viewState) on { getLiveData(eq(Order.EMPTY.javaClass.name), any()) } doReturn MutableLiveData(emptyOrder) } + createUpdateOrderUseCase = mock { + onBlocking { invoke(any(), any()) } doReturn flowOf(Succeeded(Order.EMPTY)) + } createOrderItemUseCase = mock { onBlocking { invoke(123, null) } doReturn defaultOrderItem } @@ -63,9 +70,6 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { orderCreationRepository = mock { onBlocking { placeOrder(defaultOrderValue) } doReturn Result.success(defaultOrderValue) } - orderCreationRepository.stub { - onBlocking { createOrUpdateDraft(any()) } doReturn Result.success(defaultOrderValue) - } orderDetailRepository = mock { on { getOrderStatusOptions() } doReturn orderStatusList } @@ -81,6 +85,8 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { } protected fun createSut() { + autoSyncPriceModifier = AutoSyncPriceModifier(createUpdateOrderUseCase) + autoSyncOrder = AutoSyncOrder(createUpdateOrderUseCase) sut = OrderCreationViewModel( savedState = savedState, dispatchers = coroutinesTestRule.testDispatchers, @@ -88,7 +94,9 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { orderCreationRepository = orderCreationRepository, mapItemToProductUiModel = mapItemToProductUIModel, createOrderItem = createOrderItemUseCase, - parameterRepository = parameterRepository + parameterRepository = parameterRepository, + autoSyncOrder = autoSyncOrder, + autoSyncPriceModifier = autoSyncPriceModifier ) } From c6e12a29e5c76d1ef3e6874d6aa3e18265b26e75 Mon Sep 17 00:00:00 2001 From: Alejo Date: Thu, 30 Jun 2022 20:08:53 -0300 Subject: [PATCH 095/173] unit tests of sync strategies --- .../creation/AutoSyncOrderStrategyTest.kt | 49 ++++++++++++++++++ .../AutoSyncPriceModifierStrategyTest.kt | 50 +++++++++++++++++++ .../ui/orders/creation/SyncStrategyTest.kt | 31 ++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrderStrategyTest.kt create mode 100644 WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifierStrategyTest.kt create mode 100644 WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategyTest.kt diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrderStrategyTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrderStrategyTest.kt new file mode 100644 index 00000000000..1aea213e57f --- /dev/null +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrderStrategyTest.kt @@ -0,0 +1,49 @@ +package com.woocommerce.android.ui.orders.creation + +import com.woocommerce.android.ui.orders.OrderTestUtils +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.test.advanceUntilIdle +import org.junit.Test +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + +class AutoSyncOrderStrategyTest : SyncStrategyTest() { + private val sut: AutoSyncOrder = AutoSyncOrder(createUpdateOrderUseCase) + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `WHEN the user commits a random change THEN the change is submitted to the API`() = testBlocking { + val job = sut.syncOrderChanges(orderDraftChanges, retryTrigger) + .launchIn(this) + val change = order.copy(customerNote = "testing") + orderDraftChanges.value = change + advanceUntilIdle() + verify(orderCreationRepository, times(1)).createOrUpdateDraft(change) + job.cancel() + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `WHEN the user commits a price modifier change THEN the change is submitted to the API`() = testBlocking { + val job = sut.syncOrderChanges(orderDraftChanges, retryTrigger) + .launchIn(this) + val change = order.copy(items = OrderTestUtils.generateTestOrderItems()) + orderDraftChanges.value = change + advanceUntilIdle() + verify(orderCreationRepository, times(1)).createOrUpdateDraft(change) + job.cancel() + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `WHEN the order is NOT changed by the user THEN the change is NOT submitted to the API`() = testBlocking { + val job = sut.syncOrderChanges(orderDraftChanges, retryTrigger) + .launchIn(this) + val change = order.copy(number = "12354") + orderDraftChanges.value = change + advanceUntilIdle() + verify(orderCreationRepository, times(0)).createOrUpdateDraft(change) + job.cancel() + } +} diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifierStrategyTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifierStrategyTest.kt new file mode 100644 index 00000000000..80b3002e10f --- /dev/null +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifierStrategyTest.kt @@ -0,0 +1,50 @@ +package com.woocommerce.android.ui.orders.creation + +import com.woocommerce.android.ui.orders.OrderTestUtils +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.test.advanceUntilIdle +import org.junit.Test +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + +class AutoSyncPriceModifierStrategyTest : SyncStrategyTest() { + private val sut: AutoSyncPriceModifier = AutoSyncPriceModifier(createUpdateOrderUseCase) + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `WHEN the user commits a change NOT affecting the price THEN the change is NOT submitted to the API`() = + testBlocking { + val job = sut.syncOrderChanges(orderDraftChanges, retryTrigger) + .launchIn(this) + val change = order.copy(customerNote = "testing") + orderDraftChanges.value = change + advanceUntilIdle() + verify(orderCreationRepository, times(0)).createOrUpdateDraft(change) + job.cancel() + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `WHEN the user commits a price modifier change THEN the change is submitted to the API`() = testBlocking { + val job = sut.syncOrderChanges(orderDraftChanges, retryTrigger) + .launchIn(this) + val change = order.copy(items = OrderTestUtils.generateTestOrderItems()) + orderDraftChanges.value = change + advanceUntilIdle() + verify(orderCreationRepository, times(1)).createOrUpdateDraft(change) + job.cancel() + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `WHEN the order is NOT changed by the user THEN the change is NOT submitted to the API`() = testBlocking { + val job = sut.syncOrderChanges(orderDraftChanges, retryTrigger) + .launchIn(this) + val change = order.copy(number = "12354") + orderDraftChanges.value = change + advanceUntilIdle() + verify(orderCreationRepository, times(0)).createOrUpdateDraft(change) + job.cancel() + } +} diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategyTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategyTest.kt new file mode 100644 index 00000000000..8ed6e5d026f --- /dev/null +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategyTest.kt @@ -0,0 +1,31 @@ +package com.woocommerce.android.ui.orders.creation + +import com.woocommerce.android.model.Order +import com.woocommerce.android.ui.orders.OrderTestUtils +import com.woocommerce.android.util.InlineClassesAnswer +import com.woocommerce.android.viewmodel.BaseUnitTest +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.mock +import java.math.BigDecimal + +abstract class SyncStrategyTest : BaseUnitTest() { + protected val orderCreationRepository = mock { + onBlocking { createOrUpdateDraft(any()) } doAnswer InlineClassesAnswer { + val order = it.arguments.first() as Order + Result.success(order.copy(total = order.total + BigDecimal.TEN)) + } + } + protected val order = Order.EMPTY.copy(items = OrderTestUtils.generateTestOrderItems()) + protected val orderDraftChanges = MutableStateFlow(order) + protected val retryTrigger = MutableSharedFlow(extraBufferCapacity = 1) + + @OptIn(ExperimentalCoroutinesApi::class) + protected val createUpdateOrderUseCase = CreateUpdateOrder( + dispatchers = coroutinesTestRule.testDispatchers, + orderCreationRepository = orderCreationRepository + ) +} From d65aaccbbac0fd74d3234119fab7897c374dbf7a Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 12:48:42 +0300 Subject: [PATCH 096/173] Analysis: Resolve to lower case deprecated warnings Warning Message: "'toLowerCase(...): String' is deprecated. Use lowercase(...) instead." Replacing 'toLowerCase(...)' with 'lowercase(...)' is the recommended action to resolve this kind of deprecated warnings. --- .../com/woocommerce/android/analytics/AnalyticsTracker.kt | 4 ++-- .../com/woocommerce/android/model/ProductCategory.kt | 5 ++--- .../woocommerce/android/ui/orders/OrderCustomerHelper.kt | 8 ++++---- .../com/woocommerce/android/ui/orders/OrderStatusTag.kt | 4 ++-- .../orders/shippinglabels/PrintShippingLabelViewModel.kt | 2 +- .../android/ui/products/ProductDetailViewModel.kt | 6 ++---- .../com/woocommerce/android/ui/products/ProductStatus.kt | 8 ++++---- .../com/woocommerce/android/ui/products/ProductType.kt | 4 ++-- .../ui/products/settings/ProductCatalogVisibility.kt | 8 ++++---- .../android/ui/products/settings/ProductVisibility.kt | 8 ++++---- .../android/ui/refunds/IssueRefundViewModel.kt | 6 +++--- .../kotlin/com/woocommerce/android/util/PackageUtils.kt | 4 ++-- .../kotlin/com/woocommerce/android/widgets/tags/ITag.kt | 3 ++- 13 files changed, 34 insertions(+), 36 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt index c6ecf633987..095705353a9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt @@ -11,7 +11,7 @@ import com.woocommerce.android.util.WooLog import com.woocommerce.android.util.WooLog.T import org.json.JSONObject import org.wordpress.android.fluxc.model.SiteModel -import java.util.UUID +import java.util.* class AnalyticsTracker private constructor(private val context: Context) { private var tracksClient: TracksClient? = TracksClient.getClient(context) @@ -62,7 +62,7 @@ class AnalyticsTracker private constructor(private val context: Context) { return } - val eventName = stat.name.toLowerCase() + val eventName = stat.name.lowercase(Locale.getDefault()) val user = username ?: getAnonID() ?: generateNewAnonID() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductCategory.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductCategory.kt index 78c53eb8766..c16110beed0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductCategory.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductCategory.kt @@ -7,8 +7,7 @@ import com.woocommerce.android.ui.products.categories.ProductCategoryItemUiModel import com.woocommerce.android.viewmodel.ResourceProvider import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.model.WCProductCategoryModel -import java.util.Locale -import java.util.Stack +import java.util.* @Parcelize data class ProductCategory( @@ -76,7 +75,7 @@ private fun List.sortByNameAndParent(): Set() // we first sort the list by name in a descending order - val productCategoriesSortedByNameDesc = this.sortedByDescending { it.name.toLowerCase(Locale.US) } + val productCategoriesSortedByNameDesc = this.sortedByDescending { it.name.lowercase(Locale.US) } // add root nodes to the Stack stack.addAll(productCategoriesSortedByNameDesc.filter { it.parentId == 0L }) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderCustomerHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderCustomerHelper.kt index f53e6cd8884..28e913ab1dd 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderCustomerHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderCustomerHelper.kt @@ -9,7 +9,7 @@ import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.model.Order import org.wordpress.android.util.ToastUtils -import java.util.Locale +import java.util.* object OrderCustomerHelper { enum class Action { @@ -28,7 +28,7 @@ object OrderCustomerHelper { mapOf( AnalyticsTracker.KEY_ID to order.id, AnalyticsTracker.KEY_STATUS to order.status, - AnalyticsTracker.KEY_TYPE to Action.EMAIL.name.toLowerCase(Locale.US) + AnalyticsTracker.KEY_TYPE to Action.EMAIL.name.lowercase(Locale.US) ) ) @@ -57,7 +57,7 @@ object OrderCustomerHelper { mapOf( AnalyticsTracker.KEY_ID to order.id, AnalyticsTracker.KEY_STATUS to order.status, - AnalyticsTracker.KEY_TYPE to Action.CALL.name.toLowerCase(Locale.US) + AnalyticsTracker.KEY_TYPE to Action.CALL.name.lowercase(Locale.US) ) ) @@ -86,7 +86,7 @@ object OrderCustomerHelper { mapOf( AnalyticsTracker.KEY_ID to order.id, AnalyticsTracker.KEY_STATUS to order.status, - AnalyticsTracker.KEY_TYPE to Action.SMS.name.toLowerCase(Locale.US) + AnalyticsTracker.KEY_TYPE to Action.SMS.name.lowercase(Locale.US) ) ) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt index 2e527f27880..d50c01248b2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt @@ -7,7 +7,7 @@ import com.woocommerce.android.model.Order.OrderStatus import com.woocommerce.android.widgets.tags.ITag import com.woocommerce.android.widgets.tags.TagConfig import org.wordpress.android.fluxc.network.rest.wpcom.wc.order.CoreOrderStatus -import java.util.Locale +import java.util.* /** * Represents a single order status label. @@ -16,7 +16,7 @@ class OrderStatusTag(private val orderStatus: OrderStatus) : ITag(orderStatus.st override fun getTagConfiguration(context: Context): TagConfig { val config = TagConfig(context).apply { tagText = orderStatus.label } - when (rawText.toLowerCase(Locale.US)) { + when (rawText.lowercase(Locale.US)) { CoreOrderStatus.PROCESSING.value -> { config.bgColor = ContextCompat.getColor(context, R.color.tag_bg_processing) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModel.kt index 66c6b988d6d..6d7b1d5634a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModel.kt @@ -89,7 +89,7 @@ class PrintShippingLabelViewModel @Inject constructor( viewState = viewState.copy(isProgressDialogShown = true) launch { val requestResult = repository.printShippingLabels( - viewState.paperSize.name.toLowerCase(Locale.US), arguments.shippingLabelIds.toList() + viewState.paperSize.name.lowercase(Locale.US), arguments.shippingLabelIds.toList() ) viewState = viewState.copy(isProgressDialogShown = false) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailViewModel.kt index be7f21ef133..3cc9134fc40 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailViewModel.kt @@ -121,9 +121,7 @@ import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.store.WCProductStore.ProductErrorType import java.math.BigDecimal -import java.util.Collections -import java.util.Date -import java.util.Locale +import java.util.* import javax.inject.Inject @HiltViewModel @@ -826,7 +824,7 @@ class ProductDetailViewModel @Inject constructor( } private fun trackPublishing(it: Product) { - val properties = mapOf("product_type" to it.productType.value.toLowerCase(Locale.ROOT)) + val properties = mapOf("product_type" to it.productType.value.lowercase(Locale.ROOT)) val statId = if (it.status == DRAFT) ADD_PRODUCT_SAVE_AS_DRAFT_TAPPED else ADD_PRODUCT_PUBLISH_TAPPED AnalyticsTracker.track(statId, properties) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductStatus.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductStatus.kt index 569f004a6c1..079467afe8f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductStatus.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductStatus.kt @@ -4,7 +4,7 @@ import android.content.Context import androidx.annotation.StringRes import com.woocommerce.android.R import org.wordpress.android.fluxc.network.rest.wpcom.wc.product.CoreProductStatus -import java.util.Locale +import java.util.* /** * Similar to PostStatus except only draft, pending, private, and publish are supported @@ -38,14 +38,14 @@ enum class ProductStatus( * it as uppercase fails with "HTTP 400 Invalid parameter "status") */ override fun toString(): String { - return super.toString().toLowerCase(Locale.US) + return super.toString().lowercase(Locale.US) } companion object { fun fromString(status: String): ProductStatus? { - val statusLC = status.toLowerCase(Locale.US) + val statusLC = status.lowercase(Locale.US) values().forEach { value -> - if (value.toString().toLowerCase(Locale.US) == statusLC) return value + if (value.toString().lowercase(Locale.US) == statusLC) return value } return null } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductType.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductType.kt index a4af37be6e0..437d20c9d5a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductType.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductType.kt @@ -3,7 +3,7 @@ package com.woocommerce.android.ui.products import androidx.annotation.StringRes import com.woocommerce.android.R import org.wordpress.android.fluxc.network.rest.wpcom.wc.product.CoreProductType -import java.util.Locale +import java.util.* enum class ProductType(@StringRes val stringResource: Int = 0, val value: String = "") { SIMPLE(R.string.product_type_simple, CoreProductType.SIMPLE.value), @@ -14,7 +14,7 @@ enum class ProductType(@StringRes val stringResource: Int = 0, val value: String companion object { fun fromString(type: String): ProductType { - return when (type.toLowerCase(Locale.US)) { + return when (type.lowercase(Locale.US)) { "grouped" -> GROUPED "external" -> EXTERNAL "variable" -> VARIABLE diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductCatalogVisibility.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductCatalogVisibility.kt index ecf72cc26b1..9bf5b74082a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductCatalogVisibility.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductCatalogVisibility.kt @@ -3,7 +3,7 @@ package com.woocommerce.android.ui.products.settings import android.content.Context import androidx.annotation.StringRes import com.woocommerce.android.R -import java.util.Locale +import java.util.* enum class ProductCatalogVisibility { VISIBLE, @@ -22,14 +22,14 @@ enum class ProductCatalogVisibility { } override fun toString(): String { - return super.toString().toLowerCase(Locale.US) + return super.toString().lowercase(Locale.US) } companion object { fun fromString(catalogVisibility: String): ProductCatalogVisibility? { - val lcCatalogVisibility = catalogVisibility.toLowerCase(Locale.US) + val lcCatalogVisibility = catalogVisibility.lowercase(Locale.US) values().forEach { value -> - if (value.toString().toLowerCase(Locale.US) == lcCatalogVisibility) return value + if (value.toString().lowercase(Locale.US) == lcCatalogVisibility) return value } return null } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductVisibility.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductVisibility.kt index 3a00ec8374f..0d6cf407cf5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductVisibility.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductVisibility.kt @@ -3,7 +3,7 @@ package com.woocommerce.android.ui.products.settings import android.content.Context import androidx.annotation.StringRes import com.woocommerce.android.R -import java.util.Locale +import java.util.* enum class ProductVisibility { PUBLIC, @@ -20,14 +20,14 @@ enum class ProductVisibility { } override fun toString(): String { - return super.toString().toLowerCase(Locale.US) + return super.toString().lowercase(Locale.US) } companion object { fun fromString(visibility: String): ProductVisibility? { - val lcVisibility = visibility.toLowerCase(Locale.US) + val lcVisibility = visibility.lowercase(Locale.US) values().forEach { value -> - if (value.toString().toLowerCase(Locale.US) == lcVisibility) return value + if (value.toString().lowercase(Locale.US) == lcVisibility) return value } return null } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt index 70e2bf17686..387ca8ad3f7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt @@ -75,7 +75,7 @@ import org.wordpress.android.fluxc.store.WCOrderStore import org.wordpress.android.fluxc.store.WCRefundStore import org.wordpress.android.fluxc.store.WooCommerceStore import java.math.BigDecimal -import java.util.Locale +import java.util.* import javax.inject.Inject import kotlin.collections.set import kotlin.collections.sumBy @@ -219,11 +219,11 @@ class IssueRefundViewModel @Inject constructor( val refundOptions = mutableListOf() // Inform user that multiple shipping lines can only be refunded in wp-admin. if (refundableShippingLineIds.size > 1) { - val shipping = resourceProvider.getString(R.string.multiple_shipping).toLowerCase(Locale.getDefault()) + val shipping = resourceProvider.getString(R.string.multiple_shipping).lowercase(Locale.getDefault()) refundOptions.add(shipping) } return if (refundOptions.isNotEmpty()) { - val and = resourceProvider.getString(R.string.and).toLowerCase(Locale.getDefault()) + val and = resourceProvider.getString(R.string.and).lowercase(Locale.getDefault()) val options = refundOptions.joinToString(lastSeparator = " $and ") return resourceProvider.getString(R.string.order_refunds_shipping_refund_variable_notice, options) } else { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt index a2b42000e88..ff39a21c0cb 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt @@ -5,7 +5,7 @@ import android.content.pm.PackageInfo import android.content.pm.PackageManager import androidx.core.content.pm.PackageInfoCompat import com.woocommerce.android.BuildConfig -import java.util.Locale +import java.util.* object PackageUtils { const val PACKAGE_VERSION_CODE_DEFAULT = -1 @@ -39,7 +39,7 @@ object PackageUtils { } fun isBetaBuild(context: Context): Boolean { - val versionName = getVersionName(context).toLowerCase(Locale.ROOT) + val versionName = getVersionName(context).lowercase(Locale.ROOT) return (versionName.contains("beta") || versionName.contains("rc")) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/tags/ITag.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/tags/ITag.kt index a41bd2f42d1..b76e3371697 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/tags/ITag.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/tags/ITag.kt @@ -1,6 +1,7 @@ package com.woocommerce.android.widgets.tags import android.content.Context +import java.util.* /** * Interface for working with individual Tag elements. @@ -20,7 +21,7 @@ abstract class ITag(val rawText: String) : Comparable { } override fun compareTo(other: ITag): Int { - return rawText.toLowerCase().compareTo(other.rawText.toLowerCase()) + return rawText.lowercase(Locale.getDefault()).compareTo(other.rawText.lowercase(Locale.getDefault())) } override fun hashCode(): Int { From 911c112101792d3e73b2bee09bd16411a5a432fc Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Fri, 1 Jul 2022 10:51:13 +0100 Subject: [PATCH 097/173] Add a lane for download promo strings --- fastlane/Fastfile | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 651d75f654e..70209a43dd3 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -653,6 +653,63 @@ platform :android do ) end + ##################################################################################### + # download_promo_strings + # ----------------------------------------------------------------------------------- + # This lane download the translated promo strings from the translation system + # ----------------------------------------------------------------------------------- + # Usage: + # fastlane download_promo_strings + # + # Example: + # fastlane download_promo_strings + ##################################################################################### + desc "Downloads translated promo strings from the translation system" + lane :download_promo_strings do |options| + # "" => { desc: "" } + files = { + 'app_store_screenshot-1': { desc: "promo_screenshot_1.txt" }, + 'app_store_screenshot-1_b': { desc: "promo_screenshot_1_b.txt" }, + 'app_store_screenshot-2': { desc: "promo_screenshot_2.txt" }, + 'app_store_screenshot-3': { desc: "promo_screenshot_3.txt" }, + 'app_store_screenshot-4': { desc: "promo_screenshot_4.txt" }, + 'app_store_screenshot-5': { desc: "promo_screenshot_5.txt" }, + 'app_store_screenshot-6': { desc: "promo_screenshot_6.txt" }, + 'app_store_screenshot-7': { desc: "promo_screenshot_7.txt" }, + 'app_store_screenshot-8': { desc: "promo_screenshot_8.txt" }, + } + + locales = SUPPORTED_LOCALES + .select { |hsh| hsh[:promo_config] != false } + .map { |hsh| [hsh[:glotpress], hsh[:google_play]] } + + gp_downloadmetadata(project_url: GLOTPRESS_PLAYSTORE_METADATA_PROJECT_URL, + target_files: files, + locales: locales, + source_locale: "en-US", + download_path: File.join(Dir.pwd, "/playstoreres/metadata")) + + # Copy metadata (screenshot-related) txt files into `en-US` + en_us_path = File.join(Dir.pwd, "/playstoreres/metadata", "en-US") + FileUtils.mkdir_p(en_us_path) + + [ + "promo_screenshot_1.txt", + "promo_screenshot_1_b.txt", + "promo_screenshot_2.txt", + "promo_screenshot_3.txt", + "promo_screenshot_4.txt", + "promo_screenshot_5.txt", + "promo_screenshot_6.txt", + "promo_screenshot_7.txt", + "promo_screenshot_8.txt", + ].each do |filename| + source = File.join(METADATA_DIR_PATH, filename) + destination = File.join(en_us_path, filename) + FileUtils.cp(source, destination) + end + end + ##################################################################################### # build_apk # ----------------------------------------------------------------------------------- From d00191ab0e51d57f68ec005b4ef9e46fb2b02e4f Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 12:55:08 +0300 Subject: [PATCH 098/173] Analysis: Suppress connectivity action deprecated warnings Warning Message: "'CONNECTIVITY_ACTION: String' is deprecated. Deprecated in Java" This deprecated warning is suppressed instead of being resolved since a resolution would require a proper solution. Explanation: "This constant was deprecated in API level 28. apps should use the more versatile requestNetwork(NetworkRequest, PendingIntent), registerNetworkCallback(NetworkRequest, PendingIntent) or registerDefaultNetworkCallback(ConnectivityManager.NetworkCallback) functions instead for faster and more detailed updates about the network changes they care about." Docs: https://developer.android.com/reference/android/net/ ConnectivityManager#CONNECTIVITY_ACTION --- .../src/main/kotlin/com/woocommerce/android/AppInitializer.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/AppInitializer.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/AppInitializer.kt index 9486ead0fc6..d3c69e416e6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/AppInitializer.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/AppInitializer.kt @@ -156,6 +156,7 @@ class AppInitializer @Inject constructor() : ApplicationLifecycleListener { } } + @Suppress("DEPRECATION") override fun onAppComesFromBackground() { AnalyticsTracker.track(AnalyticsEvent.APPLICATION_OPENED) From ff33eb7725e6b57db33e0dc0d47e9e5a45b3c963 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 13:27:03 +0300 Subject: [PATCH 099/173] Analysis: Resolve from html deprecated warnings Warning Message: "'fromHtml(String!): Spanned!' is deprecated. Deprecated in Java" Replacing 'fromHtml(html)' with 'fromHtml(html, Html.FROM_HTML_MODE_LEGACY)' is the recommended action to resolve this kind of deprecated warnings. --- .../com/woocommerce/android/extensions/TextViewExt.kt | 2 +- .../android/ui/login/LoginDiscoveryErrorFragment.kt | 4 +++- .../android/ui/login/LoginEmailHelpDialogFragment.kt | 5 ++++- .../android/ui/orders/notes/OrderDetailOrderNoteItemView.kt | 3 +-- .../main/kotlin/com/woocommerce/android/util/StringUtils.kt | 6 ++++-- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt index 0db6722d21d..ce27b5b7571 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt @@ -29,7 +29,7 @@ fun TextView.setHtmlText(html: String, onLinkClicked: OnLinkClicked? = null) { val spannedHtml = if (SystemVersionUtils.isAtLeastN()) { Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY) } else { - Html.fromHtml(html) + Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY) } val strBuilder = SpannableStringBuilder(spannedHtml) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginDiscoveryErrorFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginDiscoveryErrorFragment.kt index 65b9213a245..81aa84b9d9b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginDiscoveryErrorFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginDiscoveryErrorFragment.kt @@ -92,7 +92,9 @@ class LoginDiscoveryErrorFragment : Fragment(layout.fragment_login_discovery_err it.setDisplayShowTitleEnabled(false) } - errorMessage?.let { binding.discoveryErrorMessage.text = Html.fromHtml(getString(it)) } + errorMessage?.let { + binding.discoveryErrorMessage.text = Html.fromHtml(getString(it), Html.FROM_HTML_MODE_LEGACY) + } with(binding.discoveryWordpressOptionView) { setOnClickListener { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginEmailHelpDialogFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginEmailHelpDialogFragment.kt index 2a885c78aaf..318fb96e76d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginEmailHelpDialogFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginEmailHelpDialogFragment.kt @@ -41,7 +41,10 @@ class LoginEmailHelpDialogFragment : DialogFragment() { } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val message = Html.fromHtml(getString(R.string.login_email_help_desc, "", "", "", "")) + val message = Html.fromHtml( + getString(R.string.login_email_help_desc, "", "", "", ""), + Html.FROM_HTML_MODE_LEGACY + ) return MaterialAlertDialogBuilder(ContextThemeWrapper(requireActivity(), style.Theme_Woo_Dialog)) .setTitle(R.string.login_email_help_title) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt index 818749c1222..33918b5e304 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt @@ -45,8 +45,7 @@ class OrderDetailOrderNoteItemView @JvmOverloads constructor( private fun getHtmlText(txt: String): Spanned { return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - @Suppress("DEPRECATION") - Html.fromHtml(txt) + Html.fromHtml(txt, Html.FROM_HTML_MODE_LEGACY) } else { Html.fromHtml(txt, Html.FROM_HTML_MODE_LEGACY) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt index f7acc62884d..3aa80a3e780 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt @@ -246,7 +246,9 @@ object StringUtils { * double spaces with a single space (just in case) */ fun getRawTextFromHtml(htmlStr: String) = - Html.fromHtml(htmlStr).toString().replace("\n", " ").replace(" ", " ") + Html.fromHtml(htmlStr, Html.FROM_HTML_MODE_LEGACY).toString() + .replace("\n", " ") + .replace(" ", " ") /** * Helper method for using the appropriate `Html.fromHtml()` for the build version. @@ -255,7 +257,7 @@ object StringUtils { return if (SystemVersionUtils.isAtLeastN()) { Html.fromHtml(htmlStr, Html.FROM_HTML_MODE_LEGACY) } else { - Html.fromHtml(htmlStr) + Html.fromHtml(htmlStr, Html.FROM_HTML_MODE_LEGACY) } } From a31e5e0f0a61e4cd79c52c4009c8072f07a21dba Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 13:35:31 +0300 Subject: [PATCH 100/173] Refactor: Remove unnecessary from html utility functions Using 'Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY)' directly should be enough. Also, it being explicitly used should become easier to reason about this kind of 'Html.fromHtml(...)' logic. --- .../woocommerce/android/extensions/TextViewExt.kt | 7 +------ .../woocommerce/android/extensions/WCSSRModelExt.kt | 4 ++-- .../com/woocommerce/android/ui/inbox/InboxScreen.kt | 4 ++-- .../ui/orders/notes/OrderDetailOrderNoteItemView.kt | 12 +----------- .../shippinglabels/PrintShippingLabelInfoFragment.kt | 12 ++++++------ .../com/woocommerce/android/util/StringUtils.kt | 12 ------------ 6 files changed, 12 insertions(+), 39 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt index ce27b5b7571..995a1214afe 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt @@ -14,7 +14,6 @@ import android.widget.TextView import androidx.annotation.ColorRes import androidx.core.content.ContextCompat import androidx.core.text.toSpannable -import com.woocommerce.android.util.SystemVersionUtils import com.woocommerce.android.widgets.WooClickableSpan typealias OnLinkClicked = (ClickableSpan) -> Unit @@ -26,11 +25,7 @@ typealias OnLinkClicked = (ClickableSpan) -> Unit * The callback is triggered in addition to the default link handling behavior, it does not override it. */ fun TextView.setHtmlText(html: String, onLinkClicked: OnLinkClicked? = null) { - val spannedHtml = if (SystemVersionUtils.isAtLeastN()) { - Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY) - } else { - Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY) - } + val spannedHtml = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY) val strBuilder = SpannableStringBuilder(spannedHtml) onLinkClicked?.let { callback -> diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt index 7ec9a98499e..242334b4e61 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt @@ -2,7 +2,7 @@ package com.woocommerce.android.extensions -import com.woocommerce.android.util.StringUtils +import android.text.Html import com.woocommerce.android.util.WooLog import org.apache.commons.io.FileUtils.byteCountToDisplaySize import org.json.JSONArray @@ -228,7 +228,7 @@ private fun formatSettingsData(data: JSONObject): String { if (currencySymbolHTML == MISSING_VALUE) { MISSING_VALUE } else { - StringUtils.fromHtml(currencySymbolHTML) + Html.fromHtml(currencySymbolHTML, Html.FROM_HTML_MODE_LEGACY) } ) .append(")\n") diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/inbox/InboxScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/inbox/InboxScreen.kt index 44bdfdec7ff..3a4b57431b6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/inbox/InboxScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/inbox/InboxScreen.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.inbox +import android.text.Html import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement @@ -46,7 +47,6 @@ import com.woocommerce.android.ui.compose.animations.SkeletonView import com.woocommerce.android.ui.inbox.InboxViewModel.InboxNoteActionUi import com.woocommerce.android.ui.inbox.InboxViewModel.InboxNoteUi import com.woocommerce.android.ui.inbox.InboxViewModel.InboxState -import com.woocommerce.android.util.StringUtils @Composable fun InboxScreen(viewModel: InboxViewModel) { @@ -159,7 +159,7 @@ fun InboxNoteRow(note: InboxNoteUi) { style = MaterialTheme.typography.subtitle1 ) Text( - text = StringUtils.fromHtml(note.description).toAnnotatedString(), + text = Html.fromHtml(note.description, Html.FROM_HTML_MODE_LEGACY).toAnnotatedString(), style = MaterialTheme.typography.body2 ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt index 33918b5e304..968a7431228 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt @@ -2,9 +2,7 @@ package com.woocommerce.android.ui.orders.notes import android.annotation.SuppressLint import android.content.Context -import android.os.Build import android.text.Html -import android.text.Spanned import android.text.format.DateFormat import android.util.AttributeSet import android.view.LayoutInflater @@ -33,7 +31,7 @@ class OrderDetailOrderNoteItemView @JvmOverloads constructor( val header = if (note.isSystemNote) "$date ($type)" else "$date - ${note.author} ($type)" binding.orderNoteHeader.text = header - binding.orderNoteNote.text = getHtmlText(note.note) + binding.orderNoteNote.text = Html.fromHtml(note.note, Html.FROM_HTML_MODE_LEGACY) @DrawableRes val drawableId = when { note.isCustomerNote -> R.drawable.ic_note_public @@ -42,12 +40,4 @@ class OrderDetailOrderNoteItemView @JvmOverloads constructor( } binding.orderNoteIcon.setImageDrawable(ContextCompat.getDrawable(context, drawableId)) } - - private fun getHtmlText(txt: String): Spanned { - return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - Html.fromHtml(txt, Html.FROM_HTML_MODE_LEGACY) - } else { - Html.fromHtml(txt, Html.FROM_HTML_MODE_LEGACY) - } - } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelInfoFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelInfoFragment.kt index b51a760abe9..9c76f51b688 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelInfoFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelInfoFragment.kt @@ -1,13 +1,13 @@ package com.woocommerce.android.ui.orders.shippinglabels import android.os.Bundle +import android.text.Html import android.view.View import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.databinding.FragmentPrintShippingLabelInfoBinding import com.woocommerce.android.ui.base.BaseFragment import com.woocommerce.android.ui.main.AppBarStatus -import com.woocommerce.android.util.StringUtils class PrintShippingLabelInfoFragment : BaseFragment(R.layout.fragment_print_shipping_label_info) { override val activityAppBarStatus: AppBarStatus @@ -19,15 +19,15 @@ class PrintShippingLabelInfoFragment : BaseFragment(R.layout.fragment_print_ship super.onViewCreated(view, savedInstanceState) val binding = FragmentPrintShippingLabelInfoBinding.bind(view) binding.printShippingLabelInfoStep1.text = - StringUtils.fromHtml(getString(R.string.print_shipping_label_info_step_1)) + Html.fromHtml(getString(R.string.print_shipping_label_info_step_1), Html.FROM_HTML_MODE_LEGACY) binding.printShippingLabelInfoStep2.text = - StringUtils.fromHtml(getString(R.string.print_shipping_label_info_step_2)) + Html.fromHtml(getString(R.string.print_shipping_label_info_step_2), Html.FROM_HTML_MODE_LEGACY) binding.printShippingLabelInfoStep3.text = - StringUtils.fromHtml(getString(R.string.print_shipping_label_info_step_3)) + Html.fromHtml(getString(R.string.print_shipping_label_info_step_3), Html.FROM_HTML_MODE_LEGACY) binding.printShippingLabelInfoStep4.text = - StringUtils.fromHtml(getString(R.string.print_shipping_label_info_step_4)) + Html.fromHtml(getString(R.string.print_shipping_label_info_step_4), Html.FROM_HTML_MODE_LEGACY) binding.printShippingLabelInfoStep5.text = - StringUtils.fromHtml(getString(R.string.print_shipping_label_info_step_5)) + Html.fromHtml(getString(R.string.print_shipping_label_info_step_5), Html.FROM_HTML_MODE_LEGACY) } override fun onResume() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt index 3aa80a3e780..3dcdbde1913 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt @@ -5,7 +5,6 @@ import android.content.res.Configuration import android.content.res.Resources.NotFoundException import android.net.Uri import android.text.Html -import android.text.Spanned import android.util.Patterns import androidx.annotation.StringRes import androidx.compose.runtime.Composable @@ -250,17 +249,6 @@ object StringUtils { .replace("\n", " ") .replace(" ", " ") - /** - * Helper method for using the appropriate `Html.fromHtml()` for the build version. - */ - fun fromHtml(htmlStr: String): Spanned { - return if (SystemVersionUtils.isAtLeastN()) { - Html.fromHtml(htmlStr, Html.FROM_HTML_MODE_LEGACY) - } else { - Html.fromHtml(htmlStr, Html.FROM_HTML_MODE_LEGACY) - } - } - /** * Returns a string for the specified locale. * From f5b3e427d3c31a6e89aa8d71a305372cca45156e Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 13:46:09 +0300 Subject: [PATCH 101/173] Analysis: Suppress network type and connectivity deprecated warnings Warning Messages: - "'getter for type: Int' is deprecated. Deprecated in Java" - "'TYPE_WIFI: Int' is deprecated. Deprecated in Java" - "'TYPE_MOBILE: Int' is deprecated. Deprecated in Java" These deprecated warnings are suppressed instead of being resolved since a resolution would require a proper solution. Explanations: - "This method was deprecated in API level 28. Callers should switch to checking NetworkCapabilities#hasTransport instead with one of the NetworkCapabilities#TRANSPORT_* constants : getType() and getTypeName() cannot account for networks using multiple transports. Note that generally apps should not care about transport; NetworkCapabilities#NET_CAPABILITY_NOT_METERED and NetworkCapabilities#getLinkDownstreamBandwidthKbps are calls that apps concerned with meteredness or bandwidth should be looking at, as they offer this information with much better accuracy." - "This constant was deprecated in API level 28. Applications should instead use NetworkCapabilities#hasTransport or requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback) to request an appropriate network. for supported transports." Docs: - https://developer.android.com/reference/android/net/ NetworkInfo#getType() - https://developer.android.com/reference/android/net/ ConnectivityManager#TYPE_WIFI - https://developer.android.com/reference/android/net/ ConnectivityManager#TYPE_MOBILE --- .../main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt index 655bb2425a5..32eadd30661 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt @@ -487,6 +487,7 @@ private fun buildZendeskTags(allSites: List?, origin: Origin, extraTa * This is a helper function which returns information about the network state of the app to be sent to Zendesk, which * could prove useful for the Happiness Engineers while debugging the users' issues. */ +@Suppress("DEPRECATION") private fun getNetworkInformation(context: Context): String { val networkType = when (NetworkUtils.getActiveNetworkInfo(context)?.type) { ConnectivityManager.TYPE_WIFI -> ZendeskConstants.networkWifi From 5242c08f6e2bbbeacd41d9f160a28189bee67b11 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 13:50:41 +0300 Subject: [PATCH 102/173] Analysis: Suppress bluetooth get default adapter deprecated warning Warning Message: "'getDefaultAdapter(): BluetoothAdapter!' is deprecated. Deprecated in Java" This deprecated warning is suppressed instead of being resolved since a resolution would require a proper solution. Explanation: "This method was deprecated in API level 31. this method will continue to work, but developers are strongly encouraged to migrate to using BluetoothManager#getAdapter(), since that approach enables support for Context#createAttributionContext." Docs: https://developer.android.com/reference/android/bluetooth/ BluetoothAdapter#getDefaultAdapter() --- .../ui/cardreader/connect/CardReaderConnectDialogFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/connect/CardReaderConnectDialogFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/connect/CardReaderConnectDialogFragment.kt index 1aca4242bc7..fac68c052e7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/connect/CardReaderConnectDialogFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/connect/CardReaderConnectDialogFragment.kt @@ -209,7 +209,7 @@ class CardReaderConnectDialogFragment : DialogFragment(R.layout.card_reader_conn WooPermissionUtils.requestScanAndConnectBluetoothPermission(requestBluetoothPermissionsLauncher) } is CheckBluetoothEnabled -> { - val btAdapter = BluetoothAdapter.getDefaultAdapter() + @Suppress("DEPRECATION") val btAdapter = BluetoothAdapter.getDefaultAdapter() event.onBluetoothCheckResult(btAdapter?.isEnabled ?: false) } is RequestEnableBluetooth -> { From 0df3ee9e04a574b2c70cf41347e50570001364ac Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 13:57:59 +0300 Subject: [PATCH 103/173] Analysis: Suppress fragment retain instance deprecated warnings Warning Message: "'setter for retainInstance: Boolean' is deprecated. Deprecated in Java" These deprecated warnings are suppressed instead of being resolved since a resolution would require a proper solution. Explanation: "Instead of retaining the Fragment itself, use a non-retained Fragment and keep retained state in a ViewModel attached to that Fragment. The ViewModel's constructor and its onCleared() callback provide the signal for initial creation and final destruction of the retained state." Docs: https://developer.android.com/reference/android/app/ Fragment#setRetainInstance(boolean) --- .../kotlin/com/woocommerce/android/ui/login/LoginActivity.kt | 1 + .../woocommerce/android/ui/products/ProductItemSelectorDialog.kt | 1 + .../variations/attributes/edit/AttributeOptionSelectorDialog.kt | 1 + 3 files changed, 3 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginActivity.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginActivity.kt index a2311b3cffd..ae3bbd94432 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginActivity.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginActivity.kt @@ -474,6 +474,7 @@ class LoginActivity : viewHelpAndSupport(Origin.LOGIN_SOCIAL) } + @Suppress("DEPRECATION") override fun addGoogleLoginFragment(isSignupFromLoginEnabled: Boolean) { val fragmentManager = supportFragmentManager val fragmentTransaction = fragmentManager.beginTransaction() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemSelectorDialog.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemSelectorDialog.kt index 1f95a0b455c..b3107130217 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemSelectorDialog.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemSelectorDialog.kt @@ -26,6 +26,7 @@ class ProductItemSelectorDialog : DialogFragment() { companion object { const val TAG: String = "ProductItemSelectorDialog" + @Suppress("DEPRECATION") fun newInstance( listener: Fragment, requestCode: Int, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/edit/AttributeOptionSelectorDialog.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/edit/AttributeOptionSelectorDialog.kt index 999ec7d1f18..6d4c3ac745c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/edit/AttributeOptionSelectorDialog.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/edit/AttributeOptionSelectorDialog.kt @@ -15,6 +15,7 @@ class AttributeOptionSelectorDialog : DialogFragment() { companion object { const val TAG: String = "AttributeOptionSelectorDialog" + @Suppress("DEPRECATION") fun newInstance( attributeGroup: VariationAttributeSelectionGroup, onAttributeOptionSelected: (VariationAttributeSelectionGroup) -> Unit From c56fffcf72c96a9b16db3433355c90a708e44da3 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 14:14:06 +0300 Subject: [PATCH 104/173] Analysis: Suppress progress dialog deprecated warnings Warning Messages: - "'ProgressDialog' is deprecated. Deprecated in Java" - "'show(Context!, CharSequence!, CharSequence!, Boolean): ProgressDialog!' is deprecated. Deprecated in Java" These deprecated warnings are suppressed instead of being resolved since a resolution would require a proper solution. You will also notice that I suppressed the deprecated warning both, on the file level and closer to the deprecation itself. In addition to that, you will notice that I suppressed the deprecated warning for other such warnings, like 'startActivityForResult(...)' and 'onActivityResult(...)'. I did that because suppressing on the file level was necessary due to the 'android.app.ProgressDialog' import that can't be suppressed any other way. But, when doing so, every deprecated warning is suppressed as well. At which point the deprecated information is lost. This way, adding first the '@Suppress("DEPRECATION")' closer to source and then adding it on the file level makes sure that this information is not lost, at least for the existing code. Explanation: "This class was deprecated in API level 26. ProgressDialog is a modal dialog, which prevents the user from interacting with the app. Instead of using this class, you should use a progress indicator like ProgressBar, which can be embedded in your app's UI. Alternatively, you can use a notification to inform the user of the task's progress." Docs: https://developer.android.com/reference/android/app/ProgressDialog --- .../android/ui/login/LoginNoJetpackFragment.kt | 5 ++++- .../android/ui/login/MagicLinkInterceptFragment.kt | 6 +++++- .../com/woocommerce/android/ui/main/MainActivity.kt | 8 +++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginNoJetpackFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginNoJetpackFragment.kt index 3abfb3adb20..4ea5bcf816e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginNoJetpackFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginNoJetpackFragment.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.woocommerce.android.ui.login import android.app.Activity @@ -70,7 +72,7 @@ class LoginNoJetpackFragment : Fragment(layout.fragment_login_no_jetpack) { private var mInputPassword: String? = null private var userAvatarUrl: String? = null - private var progressDialog: ProgressDialog? = null + @Suppress("DEPRECATION") private var progressDialog: ProgressDialog? = null /** * This flag, when set to true calls the CONNECT_SITE_INFO API to verify if Jetpack is @@ -232,6 +234,7 @@ class LoginNoJetpackFragment : Fragment(layout.fragment_login_no_jetpack) { ) } + @Suppress("DEPRECATION") private fun showProgressDialog(show: Boolean) { if (show) { hideProgressDialog() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/MagicLinkInterceptFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/MagicLinkInterceptFragment.kt index 970f76f24fc..3b78511e0f0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/MagicLinkInterceptFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/MagicLinkInterceptFragment.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.woocommerce.android.ui.login import android.app.ProgressDialog @@ -40,7 +42,7 @@ class MagicLinkInterceptFragment : Fragment() { } private var authToken: String? = null - private var progressDialog: ProgressDialog? = null + @Suppress("DEPRECATION") private var progressDialog: ProgressDialog? = null private val viewModel: MagicLinkInterceptViewModel by viewModels() @@ -125,6 +127,7 @@ class MagicLinkInterceptFragment : Fragment() { ) } + @Suppress("DEPRECATION") private fun showProgressDialog(show: Boolean) { if (show) { hideProgressDialog() @@ -152,6 +155,7 @@ class MagicLinkInterceptFragment : Fragment() { activity?.finish() } + @Suppress("DEPRECATION") private fun showLoginScreen() { val intent = Intent(context, LoginActivity::class.java) LoginMode.WOO_LOGIN_MODE.putInto(intent) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt index b664358f943..3fbe4e2da38 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.woocommerce.android.ui.main import android.animation.ValueAnimator @@ -155,7 +157,7 @@ class MainActivity : } // TODO: Using deprecated ProgressDialog temporarily - a proper post-login experience will replace this - private var progressDialog: ProgressDialog? = null + @Suppress("DEPRECATION") private var progressDialog: ProgressDialog? = null private val fragmentLifecycleObserver: FragmentLifecycleCallbacks = object : FragmentLifecycleCallbacks() { override fun onFragmentViewCreated(fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?) { @@ -283,6 +285,7 @@ class MainActivity : } } + @Suppress("DEPRECATION") override fun showProgressDialog(@StringRes stringId: Int) { hideProgressDialog() progressDialog = ProgressDialog.show(this, "", getString(stringId), true) @@ -509,6 +512,7 @@ class MainActivity : private fun isDialogDestination(destination: NavDestination) = destination.navigatorName == DIALOG_NAVIGATOR_NAME + @Suppress("DEPRECATION") public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { @@ -534,6 +538,7 @@ class MainActivity : } } + @Suppress("DEPRECATION") override fun showLoginScreen() { selectedSite.reset() val intent = Intent(this, LoginActivity::class.java) @@ -547,6 +552,7 @@ class MainActivity : navController.navigateSafely(action) } + @Suppress("DEPRECATION") override fun showSettingsScreen() { AnalyticsTracker.track(AnalyticsEvent.MAIN_MENU_SETTINGS_TAPPED) val intent = Intent(this, AppSettingsActivity::class.java) From 763058b4ffb232e622b914bff0482e22079d5a10 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 14:24:46 +0300 Subject: [PATCH 105/173] Analysis: Suppress (dialog) fragment activity created deprecated warning Warning Messages: "'onActivityCreated(Bundle?): Unit' is deprecated. Deprecated in Java" These deprecated warnings are suppressed instead of being resolved since a resolution would require a proper solution. Explanation: - "use onViewCreated(View, Bundle) for code touching the view created by onCreateView and onCreate(Bundle) for other initialization. To get a callback specifically when a Fragment activity's Activity.onCreate(Bundle) is called, register a androidx.lifecycle.LifecycleObserver on the Activity's Lifecycle in onAttach(Context), removing it when it receives the Lifecycle.State.CREATED callback." - "use onCreateDialog for code touching the dialog created by onCreateDialog, onViewCreated(View, Bundle) for code touching the view created by onCreateView and onCreate(Bundle) for other initialization. To get a callback specifically when a Fragment activity's Activity.onCreate(Bundle) is called, register a androidx.lifecycle.LifecycleObserver on the Activity's Lifecycle in onAttach(Context), removing it when it receives the Lifecycle.State.CREATED callback." Docs: - https://developer.android.com/reference/android/app/ Fragment#onActivityCreated(android.os.Bundle) - https://developer.android.com/reference/android/app/ DialogFragment#onActivityCreated(android.os.Bundle) --- .../android/ui/login/LoginWhatIsJetpackDialogFragment.kt | 1 + .../android/ui/products/categories/ParentCategoryListFragment.kt | 1 + .../android/ui/products/categories/ProductCategoriesFragment.kt | 1 + .../woocommerce/android/ui/products/tags/ProductTagsFragment.kt | 1 + .../com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt | 1 + 5 files changed, 5 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginWhatIsJetpackDialogFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginWhatIsJetpackDialogFragment.kt index 126987a1808..34919503985 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginWhatIsJetpackDialogFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginWhatIsJetpackDialogFragment.kt @@ -18,6 +18,7 @@ class LoginWhatIsJetpackDialogFragment : DialogFragment() { const val TAG = "LoginWhatIsJetpackDialogFragment" } + @Suppress("DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) dialog?.window?.attributes?.windowAnimations = R.style.Woo_Animations_Dialog diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt index d04ce2eb5d1..8ffa9587a5a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt @@ -61,6 +61,7 @@ class ParentCategoryListFragment : override fun getFragmentTitle() = getString(R.string.product_add_category) + @Suppress("DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt index 3d4c85d6cdd..212af6d77ff 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt @@ -60,6 +60,7 @@ class ProductCategoriesFragment : viewModel.fetchProductCategories() } + @Suppress("DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/tags/ProductTagsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/tags/ProductTagsFragment.kt index d0bdec00830..fd55276ebf5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/tags/ProductTagsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/tags/ProductTagsFragment.kt @@ -65,6 +65,7 @@ class ProductTagsFragment : AnalyticsTracker.trackViewShown(this) } + @Suppress("DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt index 17127c9f7a7..92ced618e90 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt @@ -71,6 +71,7 @@ class ReviewDetailFragment : return inflater.inflate(R.layout.fragment_review_detail, container, false) } + @Suppress("DEPRECATION") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) val dimen = requireActivity().resources.getDimensionPixelSize(R.dimen.image_minor_50) From 7e997e430d5e0cc3520457a7a42b425e5bc7e81c Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 14:38:22 +0300 Subject: [PATCH 106/173] Analysis: Suppress fluxc related update order status deprecated warnings Warning Messages: "'UPDATE_ORDER_STATUS' is deprecated. Deprecated in Java" These deprecated warnings are suppressed instead of being resolved since a resolution would require a proper solution. You will also notice that I suppressed the deprecated warning both, on the file level and closer to the deprecation itself. In addition to that, you will notice that I suppressed the deprecated warning for other such warnings, like 'SelectedSiteChangedEvent'. I did that because suppressing on the file level was necessary due to the 'org.wordpress.android.fluxc.action.WCOrderAction.UPDATE_ORDER_STATUS' import that can't be suppressed any other way. But, when doing so, every deprecated warning is suppressed as well. At which point the deprecated information is lost. This way, adding first the '@Suppress ("DEPRECATION")' closer to source and then adding it on the file level makes sure that this information is not lost, at least for the existing code. Explanation: - "Use suspendable WCOrderStore.updateOrderStatus(..) directly." - "Event bus is considered deprecated." Docs: - https://github.com/wordpress-mobile/WordPress-FluxC-Android/wiki/ %5BDeprecated%5D-Architecture - https://github.com/wordpress-mobile/WordPress-FluxC-Android/wiki/ Architecture --- .../kotlin/com/woocommerce/android/ui/main/MainPresenter.kt | 5 ++++- .../woocommerce/android/ui/orders/list/OrderListViewModel.kt | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainPresenter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainPresenter.kt index 9fd1b94c512..25dca262d4a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainPresenter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainPresenter.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.woocommerce.android.ui.main import com.woocommerce.android.AppPrefsWrapper @@ -175,7 +177,7 @@ class MainPresenter @Inject constructor( } } - @Suppress("unused") + @Suppress("unused", "DEPRECATION") @Subscribe(threadMode = ThreadMode.MAIN) fun onOrderChanged(event: OnOrderChanged) { when (event.causeOfChange) { @@ -212,6 +214,7 @@ class MainPresenter @Inject constructor( } } + @Suppress("DEPRECATION") fun onEventMainThread(event: SelectedSiteChangedEvent) { if (pendingUnfilledOrderCountCheck) { fetchUnfilledOrderCount() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt index f4576c229d4..8010f7bf2c9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.woocommerce.android.ui.orders.list import android.os.Parcelable @@ -335,7 +337,7 @@ class OrderListViewModel @Inject constructor( super.onCleared() } - @Suppress("unused") + @Suppress("unused", "DEPRECATION") @Subscribe(threadMode = MAIN) fun onOrderChanged(event: OnOrderChanged) { when (event.causeOfChange) { From 71c412abcb71e7d118dbee1933bd29b16c67495c Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 14:50:09 +0300 Subject: [PATCH 107/173] Analysis: Suppress recycler view adapter position deprecated warnings Warning Messages: "'getter for adapterPosition: Int' is deprecated. Deprecated in Java" These deprecated warnings are suppressed instead of being resolved since a resolution would require a proper solution. Explanation: "This method is deprecated. This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()." Docs: https://developer.android.com/reference/androidx/recyclerview/ widget/RecyclerView.ViewHolder#getAdapterPosition() --- .../orders/details/adapter/OrderDetailShippingLabelsAdapter.kt | 1 + .../orders/shippinglabels/creation/ShippingCustomsAdapter.kt | 3 ++- .../shippinglabels/creation/ShippingLabelPackagesAdapter.kt | 2 +- .../woocommerce/android/ui/products/ProductItemViewHolder.kt | 1 + .../android/ui/products/ProductShippingClassAdapter.kt | 2 +- .../ui/products/categories/ParentCategoryListAdapter.kt | 2 +- .../android/ui/products/variations/VariationListAdapter.kt | 1 + .../variations/attributes/AttributeTermsListAdapter.kt | 1 + .../woocommerce/android/widgets/DraggableItemTouchHelper.kt | 1 + .../woocommerce/android/widgets/WCProductImageGalleryView.kt | 1 + 10 files changed, 11 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/adapter/OrderDetailShippingLabelsAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/adapter/OrderDetailShippingLabelsAdapter.kt index 75c221699c8..0d340ca3818 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/adapter/OrderDetailShippingLabelsAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/adapter/OrderDetailShippingLabelsAdapter.kt @@ -205,6 +205,7 @@ class OrderDetailShippingLabelsAdapter( // Shipping label header with(viewBinding.shippingLabelListLblPackage) { + @Suppress("DEPRECATION") text = context.getString( R.string.orderdetail_shipping_label_item_header, adapterPosition + 1 diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCustomsAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCustomsAdapter.kt index b6c49ae19e3..811bb51be8e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCustomsAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCustomsAdapter.kt @@ -65,7 +65,7 @@ class ShippingCustomsAdapter( return customsPackages[position].data.id.hashCode().toLong() } - @Suppress("MagicNumber") + @Suppress("MagicNumber", "DEPRECATION") inner class PackageCustomsViewHolder(val binding: ShippingCustomsListItemBinding) : ViewHolder(binding.root) { private val linesAdapter: ShippingCustomsLineAdapter by lazy { ShippingCustomsLineAdapter( @@ -231,6 +231,7 @@ class ShippingCustomsLineAdapter( holder.bind(customsLines[position]) } + @Suppress("DEPRECATION") inner class CustomsLineViewHolder(val binding: ShippingCustomsLineListItemBinding) : ViewHolder(binding.root) { private val context get() = binding.root.context diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelPackagesAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelPackagesAdapter.kt index 20fe92c7ee8..c27b3d3a9d5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelPackagesAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelPackagesAdapter.kt @@ -71,7 +71,7 @@ class ShippingLabelPackagesAdapter( super.onBindViewHolder(holder, position, payloads) } - @Suppress("MagicNumber") + @Suppress("MagicNumber", "DEPRECATION") inner class ShippingLabelPackageViewHolder( val binding: ShippingLabelPackageDetailsListItemBinding ) : ViewHolder(binding.root) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemViewHolder.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemViewHolder.kt index 828278541f1..4d692aec26d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemViewHolder.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemViewHolder.kt @@ -46,6 +46,7 @@ class ProductItemViewHolder(val viewBinding: ProductListItemBinding) : */ fun getItemDetails() = object : ItemDetailsLookup.ItemDetails() { + @Suppress("DEPRECATION") override fun getPosition() = adapterPosition override fun getSelectionKey() = itemId override fun inSelectionHotspot(e: MotionEvent) = true diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingClassAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingClassAdapter.kt index d49cbb3eed1..ea40d75485e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingClassAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingClassAdapter.kt @@ -51,7 +51,7 @@ class ProductShippingClassAdapter( RecyclerView.ViewHolder(viewBinding.root) { init { itemView.setOnClickListener { - val position = adapterPosition + @Suppress("DEPRECATION") val position = adapterPosition if (position > -1) { onItemClicked(items[position]) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListAdapter.kt index 45a6dce043c..a6bc85d41e5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListAdapter.kt @@ -45,7 +45,7 @@ class ParentCategoryListAdapter( RecyclerView.ViewHolder(viewBinder.root) { init { viewBinder.root.setOnClickListener { - val position = adapterPosition + @Suppress("DEPRECATION") val position = adapterPosition if (position > -1) { getItem(position).let { selectedCategoryId = it.category.remoteCategoryId diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/VariationListAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/VariationListAdapter.kt index 51c2fa2f69b..d4cd56a020f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/VariationListAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/VariationListAdapter.kt @@ -48,6 +48,7 @@ class VariationListAdapter( ) holder.itemView.setOnClickListener { + @Suppress("DEPRECATION") onItemClick(getItem(holder.adapterPosition)) } return holder diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeTermsListAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeTermsListAdapter.kt index f2b3d975eac..79c604b6cbf 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeTermsListAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeTermsListAdapter.kt @@ -142,6 +142,7 @@ class AttributeTermsListAdapter( areItemsTheSame(oldItemPosition, newItemPosition) } + @Suppress("DEPRECATION") @SuppressLint("ClickableViewAccessibility") inner class TermViewHolder(val viewBinding: AttributeTermListItemBinding) : RecyclerView.ViewHolder(viewBinding.root) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/DraggableItemTouchHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/DraggableItemTouchHelper.kt index 9f3c502e2e6..f31f999fde3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/DraggableItemTouchHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/DraggableItemTouchHelper.kt @@ -10,6 +10,7 @@ class DraggableItemTouchHelper( private val onMove: (from: Int, to: Int) -> Unit ) : ItemTouchHelper( object : ItemTouchHelper.SimpleCallback(dragDirs, 0) { + @Suppress("DEPRECATION") override fun onMove( recyclerView: RecyclerView, viewHolder: ViewHolder, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCProductImageGalleryView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCProductImageGalleryView.kt index bdefd1b187b..264857a4e62 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCProductImageGalleryView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCProductImageGalleryView.kt @@ -386,6 +386,7 @@ class WCProductImageGalleryView @JvmOverloads constructor( return@OnTouchListener false } + @Suppress("DEPRECATION") private val onClickListener = OnClickListener { if (adapterPosition > NO_POSITION) { onImageClicked(adapterPosition) From 2f3576d7ac431070b72045dccd9508820e55dd6c Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 14:58:55 +0300 Subject: [PATCH 108/173] Analysis: Suppress fragment target fragment deprecated warnings Warning Messages: "'getter for targetFragment: Fragment?' is deprecated. Deprecated in Java" These deprecated warnings are suppressed instead of being resolved since a resolution would require a proper solution. Explanation: "Instead of using a target fragment to pass results, use FragmentManager.setFragmentResult(String, Bundle) to deliver results to FragmentResultListener instances registered by other fragments via FragmentManager.setFragmentResultListener(String, LifecycleOwner, FragmentResultListener)." Docs: https://developer.android.com/reference/android/app/ Fragment#getTargetFragment() --- .../woocommerce/android/ui/products/ProductItemSelectorDialog.kt | 1 + .../kotlin/com/woocommerce/android/widgets/ConfirmationDialog.kt | 1 + .../com/woocommerce/android/widgets/CurrencyAmountDialog.kt | 1 + .../kotlin/com/woocommerce/android/widgets/NumberPickerDialog.kt | 1 + 4 files changed, 4 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemSelectorDialog.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemSelectorDialog.kt index b3107130217..b85f769f935 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemSelectorDialog.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductItemSelectorDialog.kt @@ -57,6 +57,7 @@ class ProductItemSelectorDialog : DialogFragment() { private var listener: ProductItemSelectorDialogListener? = null + @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) listener = targetFragment as ProductItemSelectorDialogListener diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/ConfirmationDialog.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/ConfirmationDialog.kt index 64fea27a32a..5b36b2d9a20 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/ConfirmationDialog.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/ConfirmationDialog.kt @@ -63,6 +63,7 @@ open class ConfirmationDialog : DialogFragment(), DialogInterface.OnClickListene super.onDismiss(dialog) } + @Suppress("DEPRECATION") open fun returnResult(result: Boolean) { val target = targetFragment val resultIntent = Intent() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt index 57d135d4adc..48927bc0cc9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt @@ -122,6 +122,7 @@ open class CurrencyAmountDialog : DialogFragment(), DialogInterface.OnClickListe super.onDismiss(dialog) } + @Suppress("DEPRECATION") open fun returnResult(enteredAmount: BigDecimal) { val target = targetFragment val resultIntent = Intent() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/NumberPickerDialog.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/NumberPickerDialog.kt index 78d787f56b8..b8323bd07d6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/NumberPickerDialog.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/NumberPickerDialog.kt @@ -96,6 +96,7 @@ open class NumberPickerDialog : DialogFragment(), DialogInterface.OnClickListene super.onDismiss(dialog) } + @Suppress("DEPRECATION") open fun returnResult(selectedValue: Int) { val target = targetFragment val resultIntent = Intent() From e795d1c48c37a1224fb8f0e5f2364e372006a519 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 15:55:29 +0300 Subject: [PATCH 109/173] Analysis: Resolve handler deprecated warnings Warning Messages: "'constructor Handler()' is deprecated. Deprecated in Java" Specifying the `Lopper` explicitly, using 'Looper.getMainLooper()' is the recommended action to resolve this kind of deprecated warnings. Explanation: "This constructor is deprecated. Implicitly choosing a Looper during Handler construction can lead to bugs where operations are silently lost (if the Handler is not expecting new tasks and quits), crashes (if a handler is sometimes created on a thread without a Looper active), or race conditions, where the thread a handler is associated with is not what the author anticipated. Instead, use an Executor or specify the Looper explicitly, using Looper#getMainLooper, {link android.view.View#getHandler}, or similar. If the implicit thread local behavior is required for compatibility, use new Handler(Looper.myLooper()) to make it clear to readers." Docs: https://developer.android.com/reference/android/os/ Handler#Handler() --- .../android/ui/products/ProductImageViewerFragment.kt | 3 ++- .../variations/attributes/AttributeTermsListAdapter.kt | 3 ++- .../com/woocommerce/android/widgets/CurrencyAmountDialog.kt | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImageViewerFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImageViewerFragment.kt index 7971f1dfc53..6844496ed37 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImageViewerFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImageViewerFragment.kt @@ -4,6 +4,7 @@ import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.os.Bundle import android.os.Handler +import android.os.Looper import android.view.View import android.view.WindowManager import android.view.animation.Animation @@ -50,7 +51,7 @@ class ProductImageViewerFragment : private var isConfirmationShowing = false private var confirmationDialog: AlertDialog? = null - private val fadeOutToolbarHandler = Handler() + private val fadeOutToolbarHandler = Handler(Looper.getMainLooper()) private var remoteMediaId = 0L private lateinit var pagerAdapter: ImageViewerAdapter diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeTermsListAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeTermsListAdapter.kt index 79c604b6cbf..aefb14332fc 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeTermsListAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeTermsListAdapter.kt @@ -2,6 +2,7 @@ package com.woocommerce.android.ui.products.variations.attributes import android.annotation.SuppressLint import android.os.Handler +import android.os.Looper import android.util.TypedValue import android.view.LayoutInflater import android.view.ViewGroup @@ -108,7 +109,7 @@ class AttributeTermsListAdapter( * to animate */ private fun delayedChangeNotification() { - Handler().postDelayed( + Handler(Looper.getMainLooper()).postDelayed( { notifyDataSetChanged() }, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt index 48927bc0cc9..6c3d1887e71 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt @@ -6,6 +6,7 @@ import android.content.DialogInterface import android.content.Intent import android.os.Bundle import android.os.Handler +import android.os.Looper import android.text.TextUtils import android.view.View import android.widget.TextView @@ -75,7 +76,7 @@ open class CurrencyAmountDialog : DialogFragment(), DialogInterface.OnClickListe } ) - Handler().postDelayed( + Handler(Looper.getMainLooper()).postDelayed( { currencyEditTextLayout.requestFocus() ActivityUtils.showKeyboard(currencyEditTextLayout) From 40b495e75116a14069d3d2b91003fcf699e9f407 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 16:01:24 +0300 Subject: [PATCH 110/173] Analysis: Suppress window manager flag fullscreen deprecated warning Warning Messages: "'FLAG_FULLSCREEN: Int' is deprecated. Deprecated in Java" This deprecated warning is suppressed instead of being resolved since a resolution would require a proper solution. Explanation: "This constant was deprecated in API level 30. Use WindowInsetsController#hide(int) with Type#statusBars() instead." Docs: https://developer.android.com/reference/android/view/ WindowManager.LayoutParams#FLAG_FULLSCREEN --- .../android/ui/products/ProductImageViewerFragment.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImageViewerFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImageViewerFragment.kt index 6844496ed37..ba6caba37d8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImageViewerFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImageViewerFragment.kt @@ -104,6 +104,7 @@ class ProductImageViewerFragment : // Toolbar doesn't get restored when navigating back. // This seems like a bug in the fragment library. view.postDelayed({ + @Suppress("DEPRECATION") requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) }, 500) } @@ -111,6 +112,7 @@ class ProductImageViewerFragment : override fun onDestroyView() { super.onDestroyView() _binding = null + @Suppress("DEPRECATION") requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) } From 70817ceda79fcb1dd7bdea4bd8b4a8f7bc6c1a46 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 16:07:09 +0300 Subject: [PATCH 111/173] Analysis: Suppress fragment pager adapter deprecated warning Warning Messages: "'FragmentPagerAdapter' is deprecated. Deprecated in Java" This deprecated warning is suppressed instead of being resolved since a resolution would require a proper solution. You will also notice that I suppressed the deprecated warning both, on the file level and closer to the deprecation itself. I did that because suppressing on the file level was necessary due to the 'androidx.fragment.app.FragmentPagerAdapter' import that can't be suppressed any other way. But, when doing so, every deprecated warning is suppressed as well. At which point the deprecated information is lost. This way, adding first the '@Suppress("DEPRECATION")' closer to source and then adding it on the file level makes sure that this information is not lost, at least for the existing code. Explanation: "This class is deprecated. Switch to androidx.viewpager2.widget.ViewPager2 and use androidx.viewpager2.adapter.FragmentStateAdapter instead." Docs: https://developer.android.com/reference/androidx/fragment/app/ FragmentPagerAdapter --- .../com/woocommerce/android/ui/refunds/IssueRefundFragment.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundFragment.kt index 45aaee6dddc..07cc9a0739b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundFragment.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.woocommerce.android.ui.refunds import android.annotation.SuppressLint @@ -101,7 +103,7 @@ class IssueRefundFragment : BaseFragment() { } // TODO: Temporarily unused; it will be used again in a future release - do not remove - @Suppress("unused") + @Suppress("unused", "DEPRECATION") @SuppressLint("WrongConstant") private class RefundPageAdapter( fragmentManager: FragmentManager From 2e5a4d4f8fbd02b018b8f05a67f61f12736e6f4a Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 16:20:01 +0300 Subject: [PATCH 112/173] Analysis: Resolve drawable color filter deprecated warning Warning Messages: "'setColorFilter(Int, PorterDuff.Mode): Unit' is deprecated. Deprecated in Java" Using 'BlendModeColorFilterCompat.createBlendModeColorFilterCompat(...)' is the recommended action to resolve this kind of deprecated warning. Explanation: "This method was deprecated in API level 29. use setColorFilter(android.graphics.ColorFilter) with an instance of BlendModeColorFilter" Docs: https://developer.android.com/reference/android/graphics/drawable/ Drawable#setColorFilter(int,%20android.graphics.PorterDuff.Mode) --- .../woocommerce/android/ui/reviews/ReviewDetailFragment.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt index 92ced618e90..ffc55b03882 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt @@ -2,7 +2,6 @@ package com.woocommerce.android.ui.reviews import android.content.Context import android.graphics.Color -import android.graphics.PorterDuff import android.graphics.drawable.LayerDrawable import android.os.Build import android.os.Bundle @@ -11,6 +10,8 @@ import android.view.View import android.view.ViewGroup import android.widget.CompoundButton.OnCheckedChangeListener import androidx.core.content.ContextCompat +import androidx.core.graphics.BlendModeColorFilterCompat +import androidx.core.graphics.BlendModeCompat import androidx.core.view.ViewCompat import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController @@ -187,9 +188,9 @@ class ReviewDetailFragment : if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { val stars = binding.reviewRatingBar.progressDrawable as? LayerDrawable - stars?.getDrawable(2)?.setColorFilter( + stars?.getDrawable(2)?.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat( ContextCompat.getColor(requireContext(), R.color.woo_yellow_30), - PorterDuff.Mode.SRC_ATOP + BlendModeCompat.SRC_ATOP ) } From 8b8023f8a09ba6507f3cebed40aacd04e8c7fa59 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 16:26:26 +0300 Subject: [PATCH 113/173] Analysis: Resolve custom tabs intent toolbar color deprecated warning Warning Messages: "'setToolbarColor(Int): CustomTabsIntent.Builder' is deprecated. Deprecated in Java" Using 'CustomTabColorSchemeParams.Builder()' is the recommended action to resolve this kind of deprecated warning. Explanation: "This method is deprecated. Use setDefaultColorSchemeParams (CustomTabColorSchemeParams) instead." Docs: https://developer.android.com/reference/androidx/browser/ customtabs/CustomTabsIntent.Builder#setToolbarColor(int) --- .../com/woocommerce/android/util/ChromeCustomTabUtils.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ChromeCustomTabUtils.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ChromeCustomTabUtils.kt index c13778c39b4..8d6e2c28edb 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ChromeCustomTabUtils.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ChromeCustomTabUtils.kt @@ -6,6 +6,7 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle +import androidx.browser.customtabs.CustomTabColorSchemeParams import androidx.browser.customtabs.CustomTabsClient import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION @@ -104,8 +105,11 @@ object ChromeCustomTabUtils { } private fun createIntent(context: Context, tabSession: CustomTabsSession? = null): CustomTabsIntent { - val intent = CustomTabsIntent.Builder(tabSession) + val defaultColorSchemeParams = CustomTabColorSchemeParams.Builder() .setToolbarColor(ContextCompat.getColor(context, R.color.color_surface)) + .build() + val intent = CustomTabsIntent.Builder(tabSession) + .setDefaultColorSchemeParams(defaultColorSchemeParams) .addDefaultShareMenuItem() .setShowTitle(true) .build() From 6f25f6242a2fb3e10fbde85db8e6f67019a2092f Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 16:28:27 +0300 Subject: [PATCH 114/173] Analysis: Resolve custom tabs intent menu item color deprecated warning Warning Messages: "'addDefaultShareMenuItem(): CustomTabsIntent.Builder' is deprecated. Deprecated in Java" Replacing 'addDefaultShareMenuItem()' with 'setShareState(SHARE_STATE_ON)' is the recommended action to resolve this kind of deprecated warning. Explanation: "This method is deprecated. Use setShareState(int) instead. This will set the share state to CustomTabsIntent.SHARE_STATE_ON." Docs: https://developer.android.com/reference/androidx/browser/ customtabs/CustomTabsIntent.Builder#addDefaultShareMenuItem() --- .../kotlin/com/woocommerce/android/util/ChromeCustomTabUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ChromeCustomTabUtils.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ChromeCustomTabUtils.kt index 8d6e2c28edb..9687e1afd30 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ChromeCustomTabUtils.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/ChromeCustomTabUtils.kt @@ -110,7 +110,7 @@ object ChromeCustomTabUtils { .build() val intent = CustomTabsIntent.Builder(tabSession) .setDefaultColorSchemeParams(defaultColorSchemeParams) - .addDefaultShareMenuItem() + .setShareState(CustomTabsIntent.SHARE_STATE_ON) .setShowTitle(true) .build() intent.intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse("android-app://" + context.packageName)) From 0fd87c0b596677a48047fea7e7dd08bf342e2560 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 16:36:05 +0300 Subject: [PATCH 115/173] Analysis: Suppress wordpress utils date time utils deprecated warning Warning Messages: "'nowUTC(): Date!' is deprecated. Deprecated in Java" These deprecated warnings are suppressed instead of being resolved since a resolution would require a proper solution. Explanation: "This method doesn't work as expected and shouldn't be used in production code. It doesn't take into account that `Date` class uses TimeZone.getDefault(). It substracts the currentOffsetFromUTC, but the final date still uses system default timezone." Source Code: https://github.com/wordpress-mobile/WordPress-Utils-Android --- .../kotlin/com/woocommerce/android/util/RollingLogEntries.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/RollingLogEntries.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/RollingLogEntries.kt index b5b1377ce9c..39f67c87943 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/RollingLogEntries.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/RollingLogEntries.kt @@ -38,7 +38,7 @@ class RollingLogEntries(private val limit: Int) : LinkedList() { val level: LogLevel, val text: String? ) { - private val logDate: Date = DateTimeUtils.nowUTC() + @Suppress("DEPRECATION") private val logDate: Date = DateTimeUtils.nowUTC() override fun toString(): String { val logText = if (text.isNullOrEmpty()) "null" else text From 66cf506d9641b96d01632c9f7a137bc7838b9d33 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 16:42:06 +0300 Subject: [PATCH 116/173] Refactor: Remove unused adjust dialog size ui helper function This removal also solve the below two deprecate warnings: - "'getter for defaultDisplay: Display!' is deprecated. Deprecated in Java" - "'getSize(Point!): Unit' is deprecated. Deprecated in Java" --- .../com/woocommerce/android/util/UiHelpers.kt | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/UiHelpers.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/UiHelpers.kt index 1005658827e..9bb898b28ed 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/UiHelpers.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/UiHelpers.kt @@ -85,24 +85,4 @@ object UiHelpers { updateVisibility(imageView, image != null) image?.let { imageView.setImageDrawable(image) } } - - fun adjustDialogSize(dialog: Dialog) { - dialog.window?.let { window -> - val size = Point() - - val display = window.windowManager.defaultDisplay - display.getSize(size) - - val width = size.x - - val maximumWidth = window.context.resources.getDimension(R.dimen.alert_dialog_max_width).toInt() - var proposedWidth = (width * 0.8).toInt() - - if (proposedWidth > maximumWidth) { - proposedWidth = maximumWidth - } - - window.setLayout(proposedWidth, LayoutParams.WRAP_CONTENT) - } - } } From 59aaf30e46598be25b30ebcb911751fce4e1a535 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 16:47:14 +0300 Subject: [PATCH 117/173] Analysis: Suppress recycler view recycler listener deprecated warning Warning Messages: "'setRecyclerListener(RecyclerView.RecyclerListener?): Unit' is deprecated. Deprecated in Java" This deprecated warning is suppressed instead of being resolved since a resolution would require a proper solution. Explanation: "This method is deprecated. Use addRecyclerListener (RecyclerListener) and removeRecyclerListener(RecyclerListener)" Docs: https://developer.android.com/reference/androidx/recyclerview/ widget/RecyclerView#setRecyclerListener(androidx.recyclerview.widget. RecyclerView.RecyclerListener) --- .../com/woocommerce/android/widgets/WCProductImageGalleryView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCProductImageGalleryView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCProductImageGalleryView.kt index 264857a4e62..7d2700f4c2b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCProductImageGalleryView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCProductImageGalleryView.kt @@ -116,6 +116,7 @@ class WCProductImageGalleryView @JvmOverloads constructor( // cancel pending Glide request when a view is recycled val glideRequests = GlideApp.with(this) + @Suppress("DEPRECATION") setRecyclerListener { holder -> glideRequests.clear((holder as ImageViewHolder).viewBinding.productImage) } From 181b785a5d690cdb7a736bbd52b62b21d5cb8975 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 17:16:18 +0300 Subject: [PATCH 118/173] Analysis: Resolve kotlin char to int deprecated warning Warning Messages: "'toInt(): Int' is deprecated. Conversion of Char to Number is deprecated. Use Char.code property instead." Replacing 'toInt()' with 'code' is the recommended action to resolve this kind of deprecated warning. Explanation: "Conversion of Char to Number is deprecated. Use Char.code property instead." --- .../main/kotlin/com/woocommerce/android/extensions/StringExt.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt index 0ebe2ff75c7..8cf33f1c91b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt @@ -51,7 +51,7 @@ fun String.fastStripHtml(): String { if (htmlString.isEmpty()) return str var start = 0 - while (start != 0 && (Character.isWhitespace(htmlString[start]) || htmlString[start].toInt() == 160)) { + while (start != 0 && (Character.isWhitespace(htmlString[start]) || htmlString[start].code == 160)) { start++ } From 5bfba70bec96f31de1ba28575cac84957f18313d Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 17:21:55 +0300 Subject: [PATCH 119/173] Analysis: Resolve kotlin sum by deprecated warnings Warning Messages: "'sumBy((T) -> Int): Int' is deprecated. Use sumOf instead." Replacing 'sumBy(...)' with 'sumOf(...)' is the recommended action to resolve this kind of deprecated warnings. Explanation: "Use sumOf instead." --- .../src/main/kotlin/com/woocommerce/android/model/Refund.kt | 2 +- .../com/woocommerce/android/model/ShippingLabelPackage.kt | 2 +- .../shippinglabels/creation/CreateShippingLabelViewModel.kt | 2 +- .../com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt | 2 +- .../com/woocommerce/android/ui/refunds/RefundDetailViewModel.kt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Refund.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Refund.kt index 6b9c9c8ea51..6176f36b081 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Refund.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Refund.kt @@ -147,7 +147,7 @@ fun List.getMaxRefundQuantities( val map = mutableMapOf() val groupedRefunds = this.flatMap { it.items }.groupBy { it.orderItemId } products.map { item -> - map[item.itemId] = item.quantity - (groupedRefunds[item.itemId]?.sumBy { it.quantity } ?: 0) + map[item.itemId] = item.quantity - (groupedRefunds[item.itemId]?.sumOf { it.quantity } ?: 0) } return map } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabelPackage.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabelPackage.kt index 73e195f011e..80018893d54 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabelPackage.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabelPackage.kt @@ -19,7 +19,7 @@ data class ShippingLabelPackage( get() = "package$position" @IgnoredOnParcel - val itemsCount = items.sumBy { it.quantity } + val itemsCount = items.sumOf { it.quantity } @Parcelize data class Item( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelViewModel.kt index 886b1faf98a..2743b71be05 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/CreateShippingLabelViewModel.kt @@ -516,7 +516,7 @@ class CreateShippingLabelViewModel @Inject constructor( } else { resourceProvider.getString( string.shipping_label_multi_packages_items_count, - data.sumBy { it.itemsCount }, + data.sumOf { it.itemsCount }, data.size ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt index 387ca8ad3f7..07d037cf76c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt @@ -677,7 +677,7 @@ class IssueRefundViewModel @Inject constructor( private fun updateRefundItems(items: List) { _refundItems.value = items.filter { it.maxQuantity > 0 } - val selectedItems = items.sumBy { it.quantity } + val selectedItems = items.sumOf { it.quantity } refundByItemsState = refundByItemsState.copy( selectedItemsHeader = resourceProvider.getString( R.string.order_refunds_items_selected, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundDetailViewModel.kt index ea88ec3c25b..17d9c51ae5c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundDetailViewModel.kt @@ -89,7 +89,7 @@ class RefundDetailViewModel @Inject constructor( val groupedRefunds = refunds.flatMap { it.items }.groupBy { it.orderItemId } val refundedProducts = groupedRefunds.keys.mapNotNull { id -> order.items.firstOrNull { it.itemId == id }?.let { item -> - groupedRefunds[id]?.sumBy { it.quantity }?.let { quantity -> + groupedRefunds[id]?.sumOf { it.quantity }?.let { quantity -> ProductRefundListItem(item, quantity = quantity) } } From 40ed6560f6d60fc8aa77fe75d6e5c5838fe49f7f Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 17:27:28 +0300 Subject: [PATCH 120/173] Analysis: Resolve to upper case deprecated warnings Warning Message: "'toUpperCase(): String' is deprecated. Use uppercase() instead." Replacing 'toUpperCase(...)' with 'uppercase(...)' is the recommended action to resolve this kind of deprecated warnings. --- .../kotlin/com/woocommerce/android/support/ZendeskHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt index 32eadd30661..1ae7be85791 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/support/ZendeskHelper.kt @@ -500,7 +500,7 @@ private fun getNetworkInformation(context: Context): String { return listOf( "${ZendeskConstants.networkTypeLabel} $networkType", "${ZendeskConstants.networkCarrierLabel} $carrierName", - "${ZendeskConstants.networkCountryCodeLabel} ${countryCodeLabel.toUpperCase()}" + "${ZendeskConstants.networkCountryCodeLabel} ${countryCodeLabel.uppercase(Locale.getDefault())}" ).joinToString(separator = "\n") } From b30ec0ff22ca3b6d624e1a1dfc12deead084ee97 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 17:34:00 +0300 Subject: [PATCH 121/173] Analysis: Suppress fluxc related selected site changed event warning Warning Messages: "'SelectedSiteChangedEvent' is deprecated. Event bus is considered deprecated." These deprecated warnings are suppressed instead of being resolved since a resolution would require a proper solution. Explanation: "Event bus is considered deprecated." Docs: - https://github.com/wordpress-mobile/WordPress-FluxC-Android/wiki/ %5BDeprecated%5D-Architecture - https://github.com/wordpress-mobile/WordPress-FluxC-Android/wiki/ Architecture --- .../main/kotlin/com/woocommerce/android/tools/SelectedSite.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/tools/SelectedSite.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/tools/SelectedSite.kt index be05103ad65..9d0936e533a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/tools/SelectedSite.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/tools/SelectedSite.kt @@ -51,6 +51,7 @@ class SelectedSite( ) } + @Suppress("DEPRECATION") fun set(siteModel: SiteModel) { state.value = siteModel PreferenceUtils.setInt(getPreferences(), SELECTED_SITE_LOCAL_ID, siteModel.id) From 2b0a2a47eaf665a0190320630cd154d4691dadfc Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 17:46:13 +0300 Subject: [PATCH 122/173] Analysis: Suppress fragment activity activity result deprecated warning Warning Messages: "'onActivityResult(Int, Int, Intent?): Unit' is deprecated. Overrides deprecated member in 'androidx.activity.ComponentActivity'. Deprecated in Java" This deprecated warning is suppressed instead of being resolved since a resolution would require a proper solution. Explanation: "This method is deprecated. This method has been deprecated in favor of using the Activity Result API which brings increased type safety via an ActivityResultContract and the prebuilt contracts for common intents available in androidx.activity.result.contract.ActivityResultContracts, provides hooks for testing, and allow receiving results in separate, testable classes independent from your activity. Use registerForActivityResult with the appropriate ActivityResultContract and handling the result in the callback." Docs: https://developer.android.com/reference/androidx/fragment/app/ FragmentActivity#onActivityResult(int,int,android.content.Intent) --- .../kotlin/com/woocommerce/android/ui/main/AppUpgradeActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/AppUpgradeActivity.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/AppUpgradeActivity.kt index 7628b084795..1f958e2f6e7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/AppUpgradeActivity.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/AppUpgradeActivity.kt @@ -76,6 +76,7 @@ abstract class AppUpgradeActivity : appUpdateManager.unregisterListener(this) } + @Suppress("DEPRECATION") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == RequestCodes.IN_APP_UPDATE) { From f609daa434f849467ce366a04a243aa896d7f86d Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 18:05:58 +0300 Subject: [PATCH 123/173] Refactor: Remove redundant lifecycle observer related sam-constructors --- .../android/extensions/FragmentExt.kt | 27 +++--- .../ui/common/UserEligibilityErrorFragment.kt | 40 ++++----- .../ui/login/LoginNoJetpackFragment.kt | 33 +++---- .../ui/login/MagicLinkInterceptFragment.kt | 47 ++++------ .../ui/orders/fulfill/OrderFulfillFragment.kt | 40 ++++----- .../PrintShippingLabelFragment.kt | 18 ++-- .../ShippingLabelRefundFragment.kt | 16 ++-- .../creation/ShippingCarrierRatesFragment.kt | 18 ++-- .../ShippingLabelAddressSuggestionFragment.kt | 22 ++--- .../ui/products/BaseProductFragment.kt | 40 ++++----- .../ui/products/GroupedProductListFragment.kt | 31 +++---- .../ui/products/LinkedProductsFragment.kt | 14 ++- .../ProductDetailBottomSheetFragment.kt | 25 ++---- .../products/ProductExternalLinkFragment.kt | 14 ++- .../ui/products/ProductFilterListFragment.kt | 29 +++---- .../ProductFilterOptionListFragment.kt | 25 ++---- .../ui/products/ProductInventoryFragment.kt | 20 ++--- .../ui/products/ProductListFragment.kt | 43 ++++----- .../ui/products/ProductPricingFragment.kt | 18 ++-- .../products/ProductSelectionListFragment.kt | 31 +++---- .../ui/products/ProductShippingFragment.kt | 20 ++--- .../ui/products/ProductSortingFragment.kt | 16 ++-- .../categories/AddProductCategoryFragment.kt | 20 ++--- .../categories/ParentCategoryListFragment.kt | 25 ++---- .../categories/ProductCategoriesFragment.kt | 25 ++---- .../reviews/ProductReviewsFragment.kt | 10 +-- .../settings/ProductSettingsFragment.kt | 14 ++- .../ui/products/tags/ProductTagsFragment.kt | 36 +++----- .../attributes/AddAttributeTermsFragment.kt | 23 ++--- .../attributes/AttributeListFragment.kt | 23 ++--- .../android/ui/refunds/IssueRefundFragment.kt | 18 ++-- .../ui/refunds/RefundByAmountFragment.kt | 25 ++---- .../ui/refunds/RefundByItemsFragment.kt | 87 ++++++++----------- .../android/viewmodel/LiveDataDelegate.kt | 14 ++- .../android/viewmodel/MultiLiveEvent.kt | 15 ++-- .../android/viewmodel/SingleLiveEvent.kt | 11 +-- .../android/widgets/CurrencyAmountDialog.kt | 12 +-- 37 files changed, 365 insertions(+), 580 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/FragmentExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/FragmentExt.kt index 1bf48f67b40..4fa5e812464 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/FragmentExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/FragmentExt.kt @@ -3,7 +3,6 @@ package com.woocommerce.android.extensions import android.view.View import androidx.annotation.IdRes import androidx.fragment.app.Fragment -import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import com.google.android.material.appbar.AppBarLayout @@ -88,15 +87,12 @@ fun Fragment.handleResult(key: String, entryId: Int? = null, handler: (T) -> } entry?.savedStateHandle?.let { saveState -> - saveState.getLiveData(key).observe( - this.viewLifecycleOwner, - Observer { - it?.let { - handler(it) - saveState.set(key, null) - } + saveState.getLiveData(key).observe(this.viewLifecycleOwner) { + it?.let { + handler(it) + saveState.set(key, null) } - ) + } } } @@ -157,15 +153,12 @@ fun Fragment.handleNotice(key: String, entryId: Int? = null, handler: () -> Unit } entry?.savedStateHandle?.let { saveState -> - saveState.getLiveData(key).observe( - this.viewLifecycleOwner, - Observer { - it?.let { - handler() - saveState.set(key, null) - } + saveState.getLiveData(key).observe(this.viewLifecycleOwner) { + it?.let { + handler() + saveState.set(key, null) } - ) + } } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/common/UserEligibilityErrorFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/common/UserEligibilityErrorFragment.kt index 1779362c5a0..94d03cee14c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/common/UserEligibilityErrorFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/common/UserEligibilityErrorFragment.kt @@ -9,7 +9,6 @@ import android.view.MenuItem import android.view.View import androidx.core.view.isVisible import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.woocommerce.android.AppUrls import com.woocommerce.android.R @@ -103,30 +102,27 @@ class UserEligibilityErrorFragment : BaseFragment(layout.fragment_user_eligibili new.user?.takeIfNotEqualTo(old?.user) { showView(it) } new.isProgressDialogShown?.takeIfNotEqualTo(old?.isProgressDialogShown) { showProgressDialog(it) } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> { - uiMessageResolver.showSnack(event.message) - } - is Exit -> { - findNavController().navigateUp() - } - is Logout -> { - requireActivity().apply { - setResult(Activity.RESULT_CANCELED) - val intent = Intent(activity, LoginActivity::class.java) - intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP - LoginMode.WOO_LOGIN_MODE.putInto(intent) - startActivity(intent) - finish() - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> { + uiMessageResolver.showSnack(event.message) + } + is Exit -> { + findNavController().navigateUp() + } + is Logout -> { + requireActivity().apply { + setResult(Activity.RESULT_CANCELED) + val intent = Intent(activity, LoginActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP + LoginMode.WOO_LOGIN_MODE.putInto(intent) + startActivity(intent) + finish() } - else -> event.isHandled = false } + else -> event.isHandled = false } - ) + } viewModel.start() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginNoJetpackFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginNoJetpackFragment.kt index 4ea5bcf816e..5e10f84c056 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginNoJetpackFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginNoJetpackFragment.kt @@ -15,7 +15,6 @@ import android.widget.TextView import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.Snackbar import com.woocommerce.android.AppPrefs @@ -210,28 +209,22 @@ class LoginNoJetpackFragment : Fragment(layout.fragment_login_no_jetpack) { } private fun setupObservers() { - viewModel.isLoading.observe( - viewLifecycleOwner, - Observer { - showProgressDialog(it) - } - ) + viewModel.isLoading.observe(viewLifecycleOwner) { + showProgressDialog(it) + } - viewModel.isJetpackAvailable.observe( - viewLifecycleOwner, - Observer { isJetpackAvailable -> - if (isJetpackAvailable) { - AppPrefs.setLoginUserBypassedJetpackRequired(false) - redirectToSiteCredentialsScreen() - } else { - view?.let { - Snackbar.make( - it, getString(R.string.login_jetpack_not_found), BaseTransientBottomBar.LENGTH_LONG - ).show() - } + viewModel.isJetpackAvailable.observe(viewLifecycleOwner) { isJetpackAvailable -> + if (isJetpackAvailable) { + AppPrefs.setLoginUserBypassedJetpackRequired(false) + redirectToSiteCredentialsScreen() + } else { + view?.let { + Snackbar.make( + it, getString(R.string.login_jetpack_not_found), BaseTransientBottomBar.LENGTH_LONG + ).show() } } - ) + } } @Suppress("DEPRECATION") diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/MagicLinkInterceptFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/MagicLinkInterceptFragment.kt index 3b78511e0f0..674d22034c2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/MagicLinkInterceptFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/MagicLinkInterceptFragment.kt @@ -14,7 +14,6 @@ import android.widget.TextView import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.Snackbar import com.woocommerce.android.R @@ -94,37 +93,25 @@ class MagicLinkInterceptFragment : Fragment() { } private fun setupObservers() { - viewModel.isLoading.observe( - viewLifecycleOwner, - Observer { - showProgressDialog(it) - } - ) - - viewModel.isAuthTokenUpdated.observe( - viewLifecycleOwner, - Observer { authTokenUpdated -> - if (authTokenUpdated) { - showSitePickerScreen() - } else showLoginScreen() - } - ) - - viewModel.showSnackbarMessage.observe( - viewLifecycleOwner, - Observer { messageId -> - view?.let { - Snackbar.make(it, getString(messageId), BaseTransientBottomBar.LENGTH_LONG).show() - } - } - ) + viewModel.isLoading.observe(viewLifecycleOwner) { + showProgressDialog(it) + } - viewModel.showRetryOption.observe( - viewLifecycleOwner, - Observer { - showRetryScreen(it) + viewModel.isAuthTokenUpdated.observe(viewLifecycleOwner) { authTokenUpdated -> + if (authTokenUpdated) { + showSitePickerScreen() + } else showLoginScreen() + } + + viewModel.showSnackbarMessage.observe(viewLifecycleOwner) { messageId -> + view?.let { + Snackbar.make(it, getString(messageId), BaseTransientBottomBar.LENGTH_LONG).show() } - ) + } + + viewModel.showRetryOption.observe(viewLifecycleOwner) { + showRetryScreen(it) + } } @Suppress("DEPRECATION") diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/fulfill/OrderFulfillFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/fulfill/OrderFulfillFragment.kt index 87087ee1d54..5d6e1cdcdff 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/fulfill/OrderFulfillFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/fulfill/OrderFulfillFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.View import androidx.core.view.isVisible import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.google.android.material.snackbar.Snackbar import com.woocommerce.android.R @@ -104,32 +103,23 @@ class OrderFulfillFragment : showAddShipmentTracking(it, binding) } } - viewModel.productList.observe( - viewLifecycleOwner, - Observer { - showOrderProducts(it, viewModel.order.currency, binding) - } - ) - viewModel.shipmentTrackings.observe( - viewLifecycleOwner, - Observer { - showShipmentTrackings(it, binding) - } - ) + viewModel.productList.observe(viewLifecycleOwner) { + showOrderProducts(it, viewModel.order.currency, binding) + } + viewModel.shipmentTrackings.observe(viewLifecycleOwner) { + showShipmentTrackings(it, binding) + } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is Exit -> findNavController().navigateUp() - is ExitWithResult<*> -> navigateBackWithResult(event.key!!, event.data) - is OrderNavigationTarget -> navigator.navigate(this, event) - is ShowUndoSnackbar -> displayUndoSnackbar(event.message, event.undoAction, event.dismissAction) - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is Exit -> findNavController().navigateUp() + is ExitWithResult<*> -> navigateBackWithResult(event.key!!, event.data) + is OrderNavigationTarget -> navigator.navigate(this, event) + is ShowUndoSnackbar -> displayUndoSnackbar(event.message, event.undoAction, event.dismissAction) + else -> event.isHandled = false } - ) + } } private fun setupResultHandlers(viewModel: OrderFulfillViewModel) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelFragment.kt index f090bf3c8de..cdc8479b714 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelFragment.kt @@ -6,7 +6,6 @@ import android.view.View import androidx.annotation.StringRes import androidx.core.view.isVisible import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.navArgs import com.woocommerce.android.R import com.woocommerce.android.databinding.FragmentPrintShippingLabelBinding @@ -92,17 +91,14 @@ class PrintShippingLabelFragment : BaseFragment(R.layout.fragment_print_shipping new.tempFile?.takeIfNotEqualTo(old?.tempFile) { openShippingLabelPreview(it) } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> displayError(event.message) - is OrderNavigationTarget -> navigator.navigate(this, event) - is ExitWithResult<*> -> navigateBackAndNotifyOrderDetails() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> displayError(event.message) + is OrderNavigationTarget -> navigator.navigate(this, event) + is ExitWithResult<*> -> navigateBackAndNotifyOrderDetails() + else -> event.isHandled = false } - ) + } } private fun setupResultHandlers(viewModel: PrintShippingLabelViewModel) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/ShippingLabelRefundFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/ShippingLabelRefundFragment.kt index 68a90dc0907..bf1600289fb 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/ShippingLabelRefundFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/ShippingLabelRefundFragment.kt @@ -5,7 +5,6 @@ import android.view.View import android.widget.Toast import androidx.core.view.isVisible import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsTracker @@ -54,16 +53,13 @@ class ShippingLabelRefundFragment : BaseFragment(R.layout.fragment_shipping_labe } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.getSnack(event.message, *event.args).show() - is Exit -> navigateBackWithResult(KEY_REFUND_SHIPPING_LABEL_RESULT, true) - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.getSnack(event.message, *event.args).show() + is Exit -> navigateBackWithResult(KEY_REFUND_SHIPPING_LABEL_RESULT, true) + else -> event.isHandled = false } - ) + } } private fun FragmentShippingLabelRefundBinding.showShippingLabelDetails(shippingLabel: ShippingLabel) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCarrierRatesFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCarrierRatesFragment.kt index bd6704ee0df..85b36ce5cba 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCarrierRatesFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCarrierRatesFragment.kt @@ -8,7 +8,6 @@ import android.view.MenuItem import android.view.View import androidx.core.view.isVisible import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager import com.woocommerce.android.R @@ -143,17 +142,14 @@ class ShippingCarrierRatesFragment : BaseFragment(R.layout.fragment_shipping_car } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is ExitWithResult<*> -> navigateBackWithResult(SHIPPING_CARRIERS_RESULT, event.data) - is Exit -> navigateBackWithNotice(SHIPPING_CARRIERS_CLOSED) - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is ExitWithResult<*> -> navigateBackWithResult(SHIPPING_CARRIERS_RESULT, event.data) + is Exit -> navigateBackWithNotice(SHIPPING_CARRIERS_CLOSED) + else -> event.isHandled = false } - ) + } } private fun showEmptyView(isVisible: Boolean) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelAddressSuggestionFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelAddressSuggestionFragment.kt index bad4f821c3e..cb3d5e03fea 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelAddressSuggestionFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelAddressSuggestionFragment.kt @@ -4,7 +4,6 @@ import android.annotation.SuppressLint import android.os.Bundle import android.view.View import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.databinding.FragmentShippingLabelAddressSuggestionBinding @@ -91,19 +90,16 @@ class ShippingLabelAddressSuggestionFragment : } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is ExitWithResult<*> -> navigateBackWithResult(SELECTED_ADDRESS_ACCEPTED, event.data) - is Exit -> navigateBackWithNotice(SUGGESTED_ADDRESS_DISCARDED) - is EditSelectedAddress -> navigateBackWithResult(SELECTED_ADDRESS_TO_BE_EDITED, event.address) - is UseSelectedAddress -> navigateBackWithResult(SELECTED_ADDRESS_ACCEPTED, event.address) - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is ExitWithResult<*> -> navigateBackWithResult(SELECTED_ADDRESS_ACCEPTED, event.data) + is Exit -> navigateBackWithNotice(SUGGESTED_ADDRESS_DISCARDED) + is EditSelectedAddress -> navigateBackWithResult(SELECTED_ADDRESS_TO_BE_EDITED, event.address) + is UseSelectedAddress -> navigateBackWithResult(SELECTED_ADDRESS_ACCEPTED, event.address) + else -> event.isHandled = false } - ) + } } private fun Address.toStringMarkingDifferences(other: Address?): String { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/BaseProductFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/BaseProductFragment.kt index b74bfd44d26..51b6013c9e1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/BaseProductFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/BaseProductFragment.kt @@ -5,7 +5,6 @@ import android.view.View import androidx.annotation.CallSuper import androidx.annotation.LayoutRes import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.Observer import com.woocommerce.android.R import com.woocommerce.android.ui.base.BaseFragment import com.woocommerce.android.ui.base.UIMessageResolver @@ -38,28 +37,25 @@ abstract class BaseProductFragment : BaseFragment, BackPressListener { } private fun setupObservers(viewModel: ProductDetailViewModel) { - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is Exit -> requireActivity().onBackPressed() - is ShowDialog -> WooDialog.showDialog( - requireActivity(), - event.positiveBtnAction, - event.negativeBtnAction, - event.neutralBtnAction, - titleId = event.titleId, - messageId = event.messageId, - positiveButtonId = event.positiveButtonId, - negativeButtonId = event.negativeButtonId, - neutralButtonId = event.neutralButtonId - ) - is ProductNavigationTarget -> navigator.navigate(this, event) - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is Exit -> requireActivity().onBackPressed() + is ShowDialog -> WooDialog.showDialog( + requireActivity(), + event.positiveBtnAction, + event.negativeBtnAction, + event.neutralBtnAction, + titleId = event.titleId, + messageId = event.messageId, + positiveButtonId = event.positiveButtonId, + negativeButtonId = event.negativeButtonId, + neutralButtonId = event.neutralButtonId + ) + is ProductNavigationTarget -> navigator.navigate(this, event) + else -> event.isHandled = false } - ) + } } @CallSuper diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/GroupedProductListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/GroupedProductListFragment.kt index 0bb560fe7b4..9cd79237e94 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/GroupedProductListFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/GroupedProductListFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.View import androidx.core.view.isVisible import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import com.woocommerce.android.R @@ -74,27 +73,21 @@ class GroupedProductListFragment : BaseFragment(R.layout.fragment_grouped_produc } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is MultiLiveEvent.Event.ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is MultiLiveEvent.Event.Exit -> findNavController().navigateUp() - is MultiLiveEvent.Event.ExitWithResult<*> -> { - navigateBackWithResult(viewModel.getKeyForGroupedProductListType(), event.data as List<*>) - } - is ProductNavigationTarget -> navigator.navigate(this, event) - else -> event.isHandled = false + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is MultiLiveEvent.Event.ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is MultiLiveEvent.Event.Exit -> findNavController().navigateUp() + is MultiLiveEvent.Event.ExitWithResult<*> -> { + navigateBackWithResult(viewModel.getKeyForGroupedProductListType(), event.data as List<*>) } + is ProductNavigationTarget -> navigator.navigate(this, event) + else -> event.isHandled = false } - ) + } - viewModel.productList.observe( - viewLifecycleOwner, - Observer { - productListAdapter.submitList(it) - } - ) + viewModel.productList.observe(viewLifecycleOwner) { + productListAdapter.submitList(it) + } } private fun setupResultHandlers() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/LinkedProductsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/LinkedProductsFragment.kt index 6afba12589e..6531471cc32 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/LinkedProductsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/LinkedProductsFragment.kt @@ -2,7 +2,6 @@ package com.woocommerce.android.ui.products import android.os.Bundle import android.view.View -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsEvent @@ -51,15 +50,12 @@ class LinkedProductsFragment : BaseProductFragment(R.layout.fragment_linked_prod } private fun setupObservers() { - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ExitLinkedProducts -> findNavController().navigateUp() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ExitLinkedProducts -> findNavController().navigateUp() + else -> event.isHandled = false } - ) + } handleResult>(UPSELLS.resultKey) { viewModel.updateProductDraft(upsellProductIds = it) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailBottomSheetFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailBottomSheetFragment.kt index 7aa661e54da..723ce42e19b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailBottomSheetFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailBottomSheetFragment.kt @@ -5,7 +5,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import com.woocommerce.android.R @@ -56,24 +55,18 @@ class ProductDetailBottomSheetFragment : WCBottomSheetDialogFragment() { } private fun setupObservers() { - viewModel.productDetailBottomSheetList.observe( - viewLifecycleOwner, - Observer { - showProductDetailBottomSheetOptions(it) - } - ) + viewModel.productDetailBottomSheetList.observe(viewLifecycleOwner) { + showProductDetailBottomSheetOptions(it) + } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is Exit -> { - dismiss() - } - else -> event.isHandled = false + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is Exit -> { + dismiss() } + else -> event.isHandled = false } - ) + } } private fun showProductDetailBottomSheetOptions( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductExternalLinkFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductExternalLinkFragment.kt index 831178ddb76..5de38e80b7b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductExternalLinkFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductExternalLinkFragment.kt @@ -2,7 +2,6 @@ package com.woocommerce.android.ui.products import android.os.Bundle import android.view.View -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsTracker @@ -51,15 +50,12 @@ class ProductExternalLinkFragment : BaseProductFragment(R.layout.fragment_produc override fun getFragmentTitle() = getString(R.string.product_external_link) private fun setupObservers(viewModel: ProductDetailViewModel) { - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ExitExternalLink -> findNavController().navigateUp() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ExitExternalLink -> findNavController().navigateUp() + else -> event.isHandled = false } - ) + } updateProductView(viewModel.getProduct()) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductFilterListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductFilterListFragment.kt index 13b377991cc..d0669816fb0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductFilterListFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductFilterListFragment.kt @@ -6,7 +6,6 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -106,25 +105,19 @@ class ProductFilterListFragment : new.screenTitle.takeIfNotEqualTo(old?.screenTitle) { requireActivity().title = it } new.displayClearButton?.takeIfNotEqualTo(old?.displayClearButton) { showClearAllAction(it) } } - viewModel.filterListItems.observe( - viewLifecycleOwner, - Observer { - showProductFilterList(it) - } - ) - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is Exit -> findNavController().navigateUp() - is ShowDialog -> event.showDialog() - is ExitWithResult<*> -> { - navigateBackWithResult(ProductListFragment.PRODUCT_FILTER_RESULT_KEY, event.data) - } - else -> event.isHandled = false + viewModel.filterListItems.observe(viewLifecycleOwner) { + showProductFilterList(it) + } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is Exit -> findNavController().navigateUp() + is ShowDialog -> event.showDialog() + is ExitWithResult<*> -> { + navigateBackWithResult(ProductListFragment.PRODUCT_FILTER_RESULT_KEY, event.data) } + else -> event.isHandled = false } - ) + } viewModel.loadFilters() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductFilterOptionListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductFilterOptionListFragment.kt index 7864d3403e3..766acad60a0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductFilterOptionListFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductFilterOptionListFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.View import androidx.core.view.isVisible import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -89,24 +88,18 @@ class ProductFilterOptionListFragment : } } - viewModel.filterOptionListItems.observe( - viewLifecycleOwner, - Observer { - showProductFilterList(it) - } - ) + viewModel.filterOptionListItems.observe(viewLifecycleOwner) { + showProductFilterList(it) + } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ExitWithResult<*> -> { - navigateBackWithResult(ProductListFragment.PRODUCT_FILTER_RESULT_KEY, event.data) - } - else -> event.isHandled = false + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ExitWithResult<*> -> { + navigateBackWithResult(ProductListFragment.PRODUCT_FILTER_RESULT_KEY, event.data) } + else -> event.isHandled = false } - ) + } viewModel.loadFilterOptions(arguments.selectedFilterItemPosition) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductInventoryFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductInventoryFragment.kt index dc5ae759a11..72106bf57e1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductInventoryFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductInventoryFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.View import androidx.core.view.isVisible import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.RequestCodes @@ -122,18 +121,15 @@ class ProductInventoryFragment : binding.soldIndividuallySwitch.isChecked = it } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is ExitWithResult<*> -> navigateBackWithResult(KEY_INVENTORY_DIALOG_RESULT, event.data) - is Exit -> findNavController().navigateUp() - is ShowDialog -> event.showDialog() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is ExitWithResult<*> -> navigateBackWithResult(KEY_INVENTORY_DIALOG_RESULT, event.data) + is Exit -> findNavController().navigateUp() + is ShowDialog -> event.showDialog() + else -> event.isHandled = false } - ) + } } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListFragment.kt index 384ae28dcf6..c181c7da5e8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductListFragment.kt @@ -12,7 +12,6 @@ import androidx.core.view.ViewGroupCompat import androidx.core.view.doOnPreDraw import androidx.core.view.isVisible import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.floatingactionbutton.FloatingActionButton @@ -302,32 +301,26 @@ class ProductListFragment : } } - viewModel.productList.observe( - viewLifecycleOwner, - Observer { - showProductList(it) - } - ) + viewModel.productList.observe(viewLifecycleOwner) { + showProductList(it) + } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is ScrollToTop -> scrollToTop() - is ShowAddProductBottomSheet -> showAddProductBottomSheet() - is ShowProductFilterScreen -> showProductFilterScreen( - event.stockStatusFilter, - event.productTypeFilter, - event.productStatusFilter, - event.productCategoryFilter, - event.selectedCategoryName - ) - is ShowProductSortingBottomSheet -> showProductSortingBottomSheet() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is ScrollToTop -> scrollToTop() + is ShowAddProductBottomSheet -> showAddProductBottomSheet() + is ShowProductFilterScreen -> showProductFilterScreen( + event.stockStatusFilter, + event.productTypeFilter, + event.productStatusFilter, + event.productCategoryFilter, + event.selectedCategoryName + ) + is ShowProductSortingBottomSheet -> showProductSortingBottomSheet() + else -> event.isHandled = false } - ) + } } private fun setupResultHandlers() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductPricingFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductPricingFragment.kt index 1fd0ce64b9a..75141b4fc82 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductPricingFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductPricingFragment.kt @@ -5,7 +5,6 @@ import android.app.DatePickerDialog.OnDateSetListener import android.os.Bundle import android.view.View import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.RequestCodes @@ -108,17 +107,14 @@ class ProductPricingFragment : new.salePriceErrorMessage?.takeIfNotEqualTo(old?.salePriceErrorMessage) { displaySalePriceError(it) } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is ExitWithResult<*> -> navigateBackWithResult(KEY_PRICING_DIALOG_RESULT, event.data) - is Exit -> findNavController().navigateUp() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is ExitWithResult<*> -> navigateBackWithResult(KEY_PRICING_DIALOG_RESULT, event.data) + is Exit -> findNavController().navigateUp() + else -> event.isHandled = false } - ) + } } private fun setupViews(currency: String, isCurrencyPrefix: Boolean, pricingData: PricingData) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductSelectionListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductSelectionListFragment.kt index 111f6356662..aa6a22cb85c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductSelectionListFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductSelectionListFragment.kt @@ -7,7 +7,6 @@ import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView.OnQueryTextListener import androidx.core.view.isVisible import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.recyclerview.selection.SelectionPredicates import androidx.recyclerview.selection.SelectionTracker import androidx.recyclerview.selection.StorageStrategy @@ -186,27 +185,21 @@ class ProductSelectionListFragment : } } - viewModel.productList.observe( - viewLifecycleOwner, - Observer { - showProductList(it) - } - ) + viewModel.productList.observe(viewLifecycleOwner) { + showProductList(it) + } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is ExitWithResult<*> -> { - val key = viewModel.groupedProductListType.resultKey - val productIds = (event.data as? List) ?: emptyList() - navigateBackWithResult(key, productIds) - } - else -> event.isHandled = false + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is ExitWithResult<*> -> { + val key = viewModel.groupedProductListType.resultKey + val productIds = (event.data as? List) ?: emptyList() + navigateBackWithResult(key, productIds) } + else -> event.isHandled = false } - ) + } } private fun showSkeleton(show: Boolean) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingFragment.kt index 001354fb9ad..48f5064001a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingFragment.kt @@ -6,7 +6,6 @@ import android.view.View import androidx.annotation.StringRes import androidx.core.view.isVisible import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.databinding.FragmentProductShippingBinding @@ -76,18 +75,15 @@ class ProductShippingFragment : BaseProductEditorFragment(R.layout.fragment_prod binding.productShippingClassSpinner.setText(viewModel.getShippingClassByRemoteShippingClassId(classId)) } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is ExitWithResult<*> -> navigateBackWithResult(KEY_SHIPPING_DIALOG_RESULT, event.data) - is Exit -> findNavController().navigateUp() - is ShowDialog -> event.showDialog() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is ExitWithResult<*> -> navigateBackWithResult(KEY_SHIPPING_DIALOG_RESULT, event.data) + is Exit -> findNavController().navigateUp() + is ShowDialog -> event.showDialog() + else -> event.isHandled = false } - ) + } } private fun setupResultHandlers() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductSortingFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductSortingFragment.kt index 7e36e28d8ad..2dea12300b0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductSortingFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductSortingFragment.kt @@ -5,7 +5,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import com.woocommerce.android.databinding.DialogProductListSortingBinding import com.woocommerce.android.util.CurrencyFormatter @@ -41,17 +40,14 @@ class ProductSortingFragment : WCBottomSheetDialogFragment() { } private fun setupObservers() { - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is Exit -> { - dismiss() - } - else -> event.isHandled = false + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is Exit -> { + dismiss() } + else -> event.isHandled = false } - ) + } } private fun showSortingOptions() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/AddProductCategoryFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/AddProductCategoryFragment.kt index 4d5d8c8bd13..3e3b7d63585 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/AddProductCategoryFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/AddProductCategoryFragment.kt @@ -6,7 +6,6 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsEvent @@ -117,18 +116,15 @@ class AddProductCategoryFragment : BaseFragment(R.layout.fragment_add_product_ca new.displayProgressDialog?.takeIfNotEqualTo(old?.displayProgressDialog) { showProgressDialog(it) } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is Exit -> requireActivity().onBackPressed() - is ShowDialog -> event.showDialog() - is ExitWithResult<*> -> navigateBackWithResult(ARG_ADDED_CATEGORY, event.data) - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is Exit -> requireActivity().onBackPressed() + is ShowDialog -> event.showDialog() + is ExitWithResult<*> -> navigateBackWithResult(ARG_ADDED_CATEGORY, event.data) + else -> event.isHandled = false } - ) + } } private fun displayCategoryNameError(messageId: Int) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt index 8ffa9587a5a..cc2d176f1ee 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ParentCategoryListFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.View import androidx.core.view.isVisible import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsEvent @@ -100,23 +99,17 @@ class ParentCategoryListFragment : } } - viewModel.parentCategories.observe( - viewLifecycleOwner, - Observer { - showParentCategories(it) - } - ) + viewModel.parentCategories.observe(viewLifecycleOwner) { + showParentCategories(it) + } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowSnackbar -> uiMessageResolver.showSnack(event.message) - is Exit -> findNavController().navigateUp() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowSnackbar -> uiMessageResolver.showSnack(event.message) + is Exit -> findNavController().navigateUp() + else -> event.isHandled = false } - ) + } } private fun showParentCategories(productCategories: List) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt index 212af6d77ff..7baef37d5e5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/ProductCategoriesFragment.kt @@ -3,7 +3,6 @@ package com.woocommerce.android.ui.products.categories import android.os.Bundle import android.view.View import androidx.core.view.isVisible -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -105,22 +104,16 @@ class ProductCategoriesFragment : } } - viewModel.productCategories.observe( - viewLifecycleOwner, - Observer { - showProductCategories(it) - } - ) - - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ExitProductCategories -> findNavController().navigateUp() - else -> event.isHandled = false - } + viewModel.productCategories.observe(viewLifecycleOwner) { + showProductCategories(it) + } + + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ExitProductCategories -> findNavController().navigateUp() + else -> event.isHandled = false } - ) + } } private fun setupResultHandlers() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/reviews/ProductReviewsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/reviews/ProductReviewsFragment.kt index d74b52dfc67..03954dc0c20 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/reviews/ProductReviewsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/reviews/ProductReviewsFragment.kt @@ -3,7 +3,6 @@ package com.woocommerce.android.ui.products.reviews import android.os.Bundle import android.view.View import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager @@ -117,12 +116,9 @@ class ProductReviewsFragment : } } - viewModel.reviewList.observe( - viewLifecycleOwner, - Observer { - showReviewList(it) - } - ) + viewModel.reviewList.observe(viewLifecycleOwner) { + showReviewList(it) + } observeModerationStatus( reviewModerationConsumer = viewModel, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductSettingsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductSettingsFragment.kt index d40f3d5c239..8c70e5322fb 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductSettingsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductSettingsFragment.kt @@ -3,7 +3,6 @@ package com.woocommerce.android.ui.products.settings import android.os.Bundle import android.view.View import android.widget.CompoundButton -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.woocommerce.android.R @@ -167,15 +166,12 @@ class ProductSettingsFragment : BaseProductFragment(R.layout.fragment_product_se } private fun setupObservers() { - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ExitSettings -> findNavController().navigateUp() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ExitSettings -> findNavController().navigateUp() + else -> event.isHandled = false } - ) + } updateProductView() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/tags/ProductTagsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/tags/ProductTagsFragment.kt index fd55276ebf5..b9a6091da0e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/tags/ProductTagsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/tags/ProductTagsFragment.kt @@ -5,7 +5,6 @@ import android.os.Handler import android.os.Looper import android.view.View import androidx.core.view.isVisible -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DividerItemDecoration @@ -144,32 +143,23 @@ class ProductTagsFragment : } } - viewModel.productTags.observe( - viewLifecycleOwner, - Observer { - showProductTags(it) - } - ) + viewModel.productTags.observe(viewLifecycleOwner) { + showProductTags(it) + } - viewModel.addedProductTags.observe( - viewLifecycleOwner, - Observer { - addTags(it, this) - } - ) + viewModel.addedProductTags.observe(viewLifecycleOwner) { + addTags(it, this) + } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ExitProductTags -> { - viewModel.clearProductTagsState() - findNavController().navigateUp() - } - else -> event.isHandled = false + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ExitProductTags -> { + viewModel.clearProductTagsState() + findNavController().navigateUp() } + else -> event.isHandled = false } - ) + } } private fun showProductTags(productTags: List) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AddAttributeTermsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AddAttributeTermsFragment.kt index afc4fe07a2a..4ae5ad04369 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AddAttributeTermsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AddAttributeTermsFragment.kt @@ -8,7 +8,6 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.core.view.isVisible -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.ItemTouchHelper @@ -311,12 +310,9 @@ class AddAttributeTermsFragment : BaseProductFragment(R.layout.fragment_add_attr } private fun setupObservers() { - viewModel.attributeTermsList.observe( - viewLifecycleOwner, - Observer { - showGlobalAttributeTerms(it) - } - ) + viewModel.attributeTermsList.observe(viewLifecycleOwner) { + showGlobalAttributeTerms(it) + } viewModel.globalAttributeTermsViewStateData.observe(viewLifecycleOwner) { old, new -> new.isSkeletonShown?.takeIfNotEqualTo(old?.isSkeletonShown) { @@ -324,15 +320,12 @@ class AddAttributeTermsFragment : BaseProductFragment(R.layout.fragment_add_attr } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ExitProductAddAttributeTerms -> findNavController().navigateUp() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ExitProductAddAttributeTerms -> findNavController().navigateUp() + else -> event.isHandled = false } - ) + } } private fun setupResultHandlers() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeListFragment.kt index e5bedc0025c..f53e7c14364 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeListFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/variations/attributes/AttributeListFragment.kt @@ -6,7 +6,6 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager @@ -109,22 +108,16 @@ class AttributeListFragment : BaseProductFragment(R.layout.fragment_attribute_li } private fun setupObservers() { - viewModel.event.observe( - viewLifecycleOwner, - { event -> - when (event) { - is ExitProductAttributeList -> findNavController().navigateUp() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ExitProductAttributeList -> findNavController().navigateUp() + else -> event.isHandled = false } - ) + } - viewModel.attributeList.observe( - viewLifecycleOwner, - Observer { - showAttributes(it) - } - ) + viewModel.attributeList.observe(viewLifecycleOwner) { + showAttributes(it) + } viewModel.attributeListViewStateData.observe(viewLifecycleOwner) { old, new -> new.isCreatingVariationDialogShown?.takeIfNotEqualTo(old?.isCreatingVariationDialogShown) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundFragment.kt index 07cc9a0739b..780347402ab 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundFragment.kt @@ -11,7 +11,6 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentPagerAdapter import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsTracker @@ -88,18 +87,15 @@ class IssueRefundFragment : BaseFragment() { // } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowRefundSummary -> { - val action = IssueRefundFragmentDirections.actionIssueRefundFragmentToRefundSummaryFragment() - findNavController().navigateSafely(action) - } - else -> event.isHandled = false + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowRefundSummary -> { + val action = IssueRefundFragmentDirections.actionIssueRefundFragmentToRefundSummaryFragment() + findNavController().navigateSafely(action) } + else -> event.isHandled = false } - ) + } } // TODO: Temporarily unused; it will be used again in a future release - do not remove diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundByAmountFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundByAmountFragment.kt index 8d73cba7f36..6d0041eaf9a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundByAmountFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundByAmountFragment.kt @@ -3,7 +3,6 @@ package com.woocommerce.android.ui.refunds import android.os.Bundle import android.view.View import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.Observer import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.databinding.FragmentRefundByAmountBinding @@ -63,22 +62,16 @@ class RefundByAmountFragment : BaseFragment(R.layout.fragment_refund_by_amount) } } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowValidationError -> binding.issueRefundRefundAmount.error = event.message - is HideValidationError -> binding.issueRefundRefundAmount.error = null - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowValidationError -> binding.issueRefundRefundAmount.error = event.message + is HideValidationError -> binding.issueRefundRefundAmount.error = null + else -> event.isHandled = false } - ) + } - binding.issueRefundRefundAmount.value.filterNotNull().observe( - viewLifecycleOwner, - Observer { - viewModel.onManualRefundAmountChanged(it) - } - ) + binding.issueRefundRefundAmount.value.filterNotNull().observe(viewLifecycleOwner) { + viewModel.onManualRefundAmountChanged(it) + } } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundByItemsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundByItemsFragment.kt index f81a706543e..1bb428d88d9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundByItemsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/RefundByItemsFragment.kt @@ -8,7 +8,6 @@ import android.view.View import android.widget.TextView import androidx.core.view.isVisible import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import com.woocommerce.android.R @@ -213,60 +212,48 @@ class RefundByItemsFragment : } } - viewModel.refundItems.observe( - viewLifecycleOwner, - Observer { list -> - val adapter = productsBinding.issueRefundProducts.adapter as RefundProductListAdapter - adapter.update(list) - } - ) + viewModel.refundItems.observe(viewLifecycleOwner) { list -> + val adapter = productsBinding.issueRefundProducts.adapter as RefundProductListAdapter + adapter.update(list) + } - viewModel.refundShippingLines.observe( - viewLifecycleOwner, - Observer { list -> - val adapter = shippingLinesBinding.issueRefundShippingLines.adapter as RefundShippingListAdapter - adapter.update(list) - } - ) + viewModel.refundShippingLines.observe(viewLifecycleOwner) { list -> + val adapter = shippingLinesBinding.issueRefundShippingLines.adapter as RefundShippingListAdapter + adapter.update(list) + } - viewModel.refundFeeLines.observe( - viewLifecycleOwner, - { list -> - val adapter = feeLinesBinding.issueRefundFeeLines.adapter as RefundFeeListAdapter - adapter.update(list) - } - ) + viewModel.refundFeeLines.observe(viewLifecycleOwner) { list -> + val adapter = feeLinesBinding.issueRefundFeeLines.adapter as RefundFeeListAdapter + adapter.update(list) + } - viewModel.event.observe( - viewLifecycleOwner, - Observer { event -> - when (event) { - is ShowNumberPicker -> { - val action = IssueRefundFragmentDirections.actionIssueRefundFragmentToRefundItemsPickerDialog( - title = getString(R.string.order_refunds_select_quantity), - uniqueId = event.refundItem.orderItem.itemId, - maxValue = event.refundItem.availableRefundQuantity, - currentValue = event.refundItem.quantity - ) - findNavController().navigateSafely(action) - } - is ShowRefundAmountDialog -> { - val action = IssueRefundFragmentDirections.actionIssueRefundFragmentToRefundAmountDialog( - title = getString(R.string.order_refunds_products_refund), - maxValue = event.maxRefund, - currentValue = event.refundAmount, - minValue = BigDecimal.ZERO, - message = event.message - ) - findNavController().navigateSafely(action) - } - is OpenUrl -> { - ChromeCustomTabUtils.launchUrl(requireContext(), event.url) - } - else -> event.isHandled = false + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ShowNumberPicker -> { + val action = IssueRefundFragmentDirections.actionIssueRefundFragmentToRefundItemsPickerDialog( + title = getString(R.string.order_refunds_select_quantity), + uniqueId = event.refundItem.orderItem.itemId, + maxValue = event.refundItem.availableRefundQuantity, + currentValue = event.refundItem.quantity + ) + findNavController().navigateSafely(action) + } + is ShowRefundAmountDialog -> { + val action = IssueRefundFragmentDirections.actionIssueRefundFragmentToRefundAmountDialog( + title = getString(R.string.order_refunds_products_refund), + maxValue = event.maxRefund, + currentValue = event.refundAmount, + minValue = BigDecimal.ZERO, + message = event.message + ) + findNavController().navigateSafely(action) } + is OpenUrl -> { + ChromeCustomTabUtils.launchUrl(requireContext(), event.url) + } + else -> event.isHandled = false } - ) + } } private fun updateRefundNoticeView(refundNoticeText: String) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/LiveDataDelegate.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/LiveDataDelegate.kt index ac0c4653e47..ef9fff6c867 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/LiveDataDelegate.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/LiveDataDelegate.kt @@ -4,7 +4,6 @@ import android.os.Parcelable import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.Observer import androidx.lifecycle.SavedStateHandle import java.lang.IllegalStateException import kotlin.reflect.KProperty @@ -40,14 +39,11 @@ class LiveDataDelegate( } previousValue = null - _liveData.observe( - owner, - Observer { - onChange(previousValue, it) - observer(previousValue, it) - previousValue = it - } - ) + _liveData.observe(owner) { + onChange(previousValue, it) + observer(previousValue, it) + previousValue = it + } } fun observeForever(observer: (T?, T) -> Unit) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/MultiLiveEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/MultiLiveEvent.kt index 6dbc000170d..90b57a5463c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/MultiLiveEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/MultiLiveEvent.kt @@ -32,16 +32,13 @@ open class MultiLiveEvent : MutableLiveData() { @MainThread override fun observe(owner: LifecycleOwner, observer: Observer) { // Observe the internal MutableLiveData - super.observe( - owner, - Observer { t -> - if (pending.get()) { - t.isHandled = true - observer.onChanged(t) - pending.compareAndSet(t.isHandled, false) - } + super.observe(owner) { t -> + if (pending.get()) { + t.isHandled = true + observer.onChanged(t) + pending.compareAndSet(t.isHandled, false) } - ) + } } fun reset() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/SingleLiveEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/SingleLiveEvent.kt index 50c445d2a54..1715d963d28 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/SingleLiveEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/SingleLiveEvent.kt @@ -45,14 +45,11 @@ open class SingleLiveEvent : MutableLiveData() { } // Observe the internal MutableLiveData - super.observe( - owner, - Observer { t -> - if (pending.compareAndSet(true, false)) { - observer.onChanged(t) - } + super.observe(owner) { t -> + if (pending.compareAndSet(true, false)) { + observer.onChanged(t) } - ) + } } fun reset() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt index 6c3d1887e71..470f3d421c3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/CurrencyAmountDialog.kt @@ -11,7 +11,6 @@ import android.text.TextUtils import android.view.View import android.widget.TextView import androidx.fragment.app.DialogFragment -import androidx.lifecycle.Observer import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.woocommerce.android.R import com.woocommerce.android.extensions.filterNotNull @@ -68,13 +67,10 @@ open class CurrencyAmountDialog : DialogFragment(), DialogInterface.OnClickListe builder.setNegativeButton(R.string.cancel, this) builder.setView(view) - currencyEditTextLayout.value.filterNotNull().observe( - this, - Observer { - currentValue = if (it > maxValue) maxValue else it - isAmountValid(it) - } - ) + currencyEditTextLayout.value.filterNotNull().observe(this) { + currentValue = if (it > maxValue) maxValue else it + isAmountValid(it) + } Handler(Looper.getMainLooper()).postDelayed( { From f8a1c28ee224fe4a4c8d452fde1a1a38b1647e60 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 18:55:24 +0300 Subject: [PATCH 124/173] Analysis: Resolve lifecycle observe deprecated warnings Warning Message: "'observe(LifecycleOwner, crossinline (T) -> Unit): Observer' is deprecated. This extension method is not required when using Kotlin 1.4. You should remove "import androidx.lifecycle.observe"" Removing 'androidx.lifecycle.observe' import is the recommended action to resolve this kind of deprecated warnings. --- .../ui/orders/notes/AddOrderNoteFragment.kt | 1 - ...hippingLabelCreateCustomPackageFragment.kt | 1 - .../ShippingPackageSelectorFragment.kt | 1 - .../AddOrderShipmentTrackingFragment.kt | 1 - .../AddOrderTrackingProviderListFragment.kt | 1 - .../products/ProductShippingClassFragment.kt | 1 - .../AddProductDownloadBottomSheetFragment.kt | 1 - .../ProductDownloadDetailsFragment.kt | 30 ++++++++----------- .../downloads/ProductDownloadsFragment.kt | 1 - .../ProductDownloadsSettingsFragment.kt | 14 ++++----- 10 files changed, 18 insertions(+), 34 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/AddOrderNoteFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/AddOrderNoteFragment.kt index 1ca2729ffcc..8a1ff441f3e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/AddOrderNoteFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/AddOrderNoteFragment.kt @@ -8,7 +8,6 @@ import android.view.View import androidx.core.view.isVisible import androidx.core.widget.doOnTextChanged import androidx.fragment.app.viewModels -import androidx.lifecycle.observe import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsEvent.ADD_ORDER_NOTE_ADD_BUTTON_TAPPED diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelCreateCustomPackageFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelCreateCustomPackageFragment.kt index 22a36c3ce0e..2c78ddb5da7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelCreateCustomPackageFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelCreateCustomPackageFragment.kt @@ -7,7 +7,6 @@ import android.view.MenuItem import android.view.View import androidx.annotation.StringRes import androidx.fragment.app.viewModels -import androidx.lifecycle.observe import com.woocommerce.android.R import com.woocommerce.android.databinding.FragmentShippingLabelCreateCustomPackageBinding import com.woocommerce.android.extensions.takeIfNotEqualTo diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingPackageSelectorFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingPackageSelectorFragment.kt index 6640ed5e798..e22d1bc87a3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingPackageSelectorFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingPackageSelectorFragment.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.view.View import androidx.core.view.isVisible import androidx.fragment.app.viewModels -import androidx.lifecycle.observe import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import com.woocommerce.android.R diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/tracking/AddOrderShipmentTrackingFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/tracking/AddOrderShipmentTrackingFragment.kt index 51027105b99..14644b7b094 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/tracking/AddOrderShipmentTrackingFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/tracking/AddOrderShipmentTrackingFragment.kt @@ -10,7 +10,6 @@ import android.view.View import android.view.ViewGroup import androidx.core.widget.doOnTextChanged import androidx.fragment.app.viewModels -import androidx.lifecycle.observe import androidx.navigation.fragment.findNavController import com.woocommerce.android.AppPrefs import com.woocommerce.android.R diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/tracking/AddOrderTrackingProviderListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/tracking/AddOrderTrackingProviderListFragment.kt index 543da6573d6..d53225a2b8a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/tracking/AddOrderTrackingProviderListFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/tracking/AddOrderTrackingProviderListFragment.kt @@ -8,7 +8,6 @@ import android.view.inputmethod.EditorInfo import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView.OnQueryTextListener import androidx.fragment.app.viewModels -import androidx.lifecycle.observe import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.databinding.DialogOrderTrackingProviderListBinding diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingClassFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingClassFragment.kt index 518ccc0ce50..a7afe823c89 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingClassFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductShippingClassFragment.kt @@ -3,7 +3,6 @@ package com.woocommerce.android.ui.products import android.os.Bundle import android.view.View import androidx.fragment.app.viewModels -import androidx.lifecycle.observe import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/AddProductDownloadBottomSheetFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/AddProductDownloadBottomSheetFragment.kt index d618c77b972..64ff4c920a0 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/AddProductDownloadBottomSheetFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/AddProductDownloadBottomSheetFragment.kt @@ -9,7 +9,6 @@ import androidx.activity.result.ActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.viewModels import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.observe import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.databinding.DialogProductAddDownloadableFileBinding diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadDetailsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadDetailsFragment.kt index 2e90b168d9b..394111ed86a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadDetailsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadDetailsFragment.kt @@ -7,7 +7,6 @@ import android.view.MenuItem import android.view.View import androidx.fragment.app.viewModels import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.observe import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.woocommerce.android.R @@ -92,23 +91,20 @@ class ProductDownloadDetailsFragment : } private fun setupObservers(viewModel: ProductDownloadDetailsViewModel) { - viewModel.productDownloadDetailsViewStateData.observe( - owner = viewLifecycleOwner, - observer = { old, new -> - new.fileDraft.url.takeIfNotEqualTo(binding.productDownloadUrl.text) { - binding.productDownloadUrl.text = it - } - new.fileDraft.name.takeIfNotEqualTo(binding.productDownloadName.text) { - binding.productDownloadName.text = it - } - new.showDoneButton.takeIfNotEqualTo(old?.showDoneButton) { - showDoneMenuItem(it) - } - if (new.urlErrorMessage != old?.urlErrorMessage || new.nameErrorMessage != old?.nameErrorMessage) { - updateErrorMessages(new.urlErrorMessage, new.nameErrorMessage) - } + viewModel.productDownloadDetailsViewStateData.observe(viewLifecycleOwner) { old, new -> + new.fileDraft.url.takeIfNotEqualTo(binding.productDownloadUrl.text) { + binding.productDownloadUrl.text = it } - ) + new.fileDraft.name.takeIfNotEqualTo(binding.productDownloadName.text) { + binding.productDownloadName.text = it + } + new.showDoneButton.takeIfNotEqualTo(old?.showDoneButton) { + showDoneMenuItem(it) + } + if (new.urlErrorMessage != old?.urlErrorMessage || new.nameErrorMessage != old?.nameErrorMessage) { + updateErrorMessages(new.urlErrorMessage, new.nameErrorMessage) + } + } viewModel.event.observe(viewLifecycleOwner) { event -> when (event) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadsFragment.kt index 41d4038f15d..d839472e16c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadsFragment.kt @@ -5,7 +5,6 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View -import androidx.lifecycle.observe import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.ItemTouchHelper.DOWN import androidx.recyclerview.widget.ItemTouchHelper.UP diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadsSettingsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadsSettingsFragment.kt index e79092c4f6b..ae2bfc42065 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadsSettingsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/ProductDownloadsSettingsFragment.kt @@ -2,7 +2,6 @@ package com.woocommerce.android.ui.products.downloads import android.os.Bundle import android.view.View -import androidx.lifecycle.observe import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsTracker @@ -36,15 +35,12 @@ class ProductDownloadsSettingsFragment : BaseProductFragment(R.layout.fragment_p } fun setupObservers(viewModel: ProductDetailViewModel) { - viewModel.event.observe( - viewLifecycleOwner, - { event -> - when (event) { - is ExitProductDownloadsSettings -> findNavController().navigateUp() - else -> event.isHandled = false - } + viewModel.event.observe(viewLifecycleOwner) { event -> + when (event) { + is ExitProductDownloadsSettings -> findNavController().navigateUp() + else -> event.isHandled = false } - ) + } initFromProductDraft() setupListeners() From 9564fee044080de63e2ed4ef47c03a1dbf53af08 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 18:57:02 +0300 Subject: [PATCH 125/173] Analysis: Resolve to lower case deprecated warnings Warning Message: "'toLowerCase(...): String' is deprecated. Use lowercase(...) instead." Replacing 'toLowerCase(...)' with 'lowercase(...)' is the recommended action to resolve this kind of deprecated warnings. --- .../com/woocommerce/android/ui/reviews/ProductReviewStatus.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ProductReviewStatus.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ProductReviewStatus.kt index 96e7eb001d7..3da7a6ddb52 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ProductReviewStatus.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ProductReviewStatus.kt @@ -16,7 +16,7 @@ enum class ProductReviewStatus { ALL; override fun toString(): String { - return this.name.toLowerCase(Locale.US) + return this.name.lowercase(Locale.US) } companion object { From 2fc2ae77354ec1b6ac8fc21d1042399becae0976 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Fri, 1 Jul 2022 19:06:58 +0300 Subject: [PATCH 126/173] Analysis: Suppress kotlin capitalize deprecated warning Warning Messages: "'capitalize(): String' is deprecated. Use replaceFirstChar instead." This deprecated warning is suppressed instead of being resolved since using 'replaceFirstChar { ... }' is a bit complicated and it would need a bit more thought. --- .../woocommerce/android/ui/products/ProductDetailCardBuilder.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailCardBuilder.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailCardBuilder.kt index 7b7f11dff2e..d3ae32b44fd 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailCardBuilder.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailCardBuilder.kt @@ -375,6 +375,7 @@ class ProductDetailCardBuilder( } } + @Suppress("DEPRECATION") private fun Product.productTypeDisplayName(): String { return when (productType) { SIMPLE -> { From 01e149c8dd52d22da2214dca30559bd85a81f5ef Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 1 Jul 2022 12:43:58 -0400 Subject: [PATCH 127/173] Use woo_blue_5 for completed order status --- .../kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt | 2 +- WooCommerce/src/main/res/values/colors_base.xml | 1 + WooCommerce/src/main/res/values/wc_colors_base.xml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt index 2e527f27880..b847c6d6290 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt @@ -27,7 +27,7 @@ class OrderStatusTag(private val orderStatus: OrderStatus) : ITag(orderStatus.st config.bgColor = ContextCompat.getColor(context, R.color.tag_bg_failed) } CoreOrderStatus.COMPLETED.value -> { - config.bgColor = ContextCompat.getColor(context, R.color.tag_bg_other) + config.bgColor = ContextCompat.getColor(context, R.color.tag_bg_completed) } CoreOrderStatus.ON_HOLD.value -> { config.bgColor = ContextCompat.getColor(context, R.color.tag_bg_on_hold) diff --git a/WooCommerce/src/main/res/values/colors_base.xml b/WooCommerce/src/main/res/values/colors_base.xml index c62b0c5d3c8..d6aa3917076 100644 --- a/WooCommerce/src/main/res/values/colors_base.xml +++ b/WooCommerce/src/main/res/values/colors_base.xml @@ -110,6 +110,7 @@ @color/woo_celadon_5 @color/woo_red_5 @color/woo_orange_5 + @color/woo_blue_5 @color/woo_gray_5 Manage Card Reader Order Card Reader - Payment Provider + Change Payment Provider BBPOS Chipper™ 2X BT Stripe M2 WisePad 3 From 99c76ff13701bd646b7f4d777a4e1fe070308ad1 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Sun, 3 Jul 2022 20:04:42 +0530 Subject: [PATCH 131/173] Trigger onboarding screen when "Change Payment Provider" row is clicked --- .../ui/cardreader/hub/CardReaderHubViewModel.kt | 3 ++- .../ui/cardreader/hub/CardReaderHubViewModelTest.kt | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt index f4a85aee757..843142c3546 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt @@ -114,13 +114,14 @@ class CardReaderHubViewModel @Inject constructor( } private fun onCardReaderPaymentProviderClicked() { - TODO("Not Implemented") + triggerEvent(CardReaderHubEvents.NavigateToCardReaderOnboardingScreen) } sealed class CardReaderHubEvents : MultiLiveEvent.Event() { data class NavigateToCardReaderDetail(val cardReaderFlowParam: CardReaderFlowParam) : CardReaderHubEvents() data class NavigateToPurchaseCardReaderFlow(val url: String) : CardReaderHubEvents() object NavigateToCardReaderManualsScreen : CardReaderHubEvents() + object NavigateToCardReaderOnboardingScreen : CardReaderHubEvents() } sealed class CardReaderHubViewState { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt index dd65a7ccf8c..22b2844a463 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt @@ -15,8 +15,12 @@ import com.woocommerce.android.viewmodel.BaseUnitTest import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyLong +import org.mockito.ArgumentMatchers.eq import org.mockito.kotlin.any import org.mockito.kotlin.mock +import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.model.plugin.SitePluginModel @@ -234,8 +238,8 @@ class CardReaderHubViewModelTest : BaseUnitTest() { } } - @Test(expected = NotImplementedError::class) - fun `given multiple plugins installed, when payment provider clicked, then throw exception`() { + @Test + fun `given multiple plugins installed, when change payment provider clicked, then trigger onboarding event`() { whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) @@ -247,6 +251,10 @@ class CardReaderHubViewModelTest : BaseUnitTest() { .find { it.label == UiString.UiStringRes(R.string.card_reader_manage_payment_provider) }!!.onItemClicked.invoke() + + assertThat(viewModel.event.value).isEqualTo( + CardReaderHubViewModel.CardReaderHubEvents.NavigateToCardReaderOnboardingScreen + ) } @Test From f4e52a994b62f665a325656dbfe63fc0d77ed276 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Sun, 3 Jul 2022 20:05:22 +0530 Subject: [PATCH 132/173] Clear plugin explicitly selected flag when "Change Payment Provider" row is clicked --- .../cardreader/hub/CardReaderHubViewModel.kt | 11 ++++++++++ .../hub/CardReaderHubViewModelTest.kt | 22 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt index 843142c3546..0847aad6116 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt @@ -114,9 +114,20 @@ class CardReaderHubViewModel @Inject constructor( } private fun onCardReaderPaymentProviderClicked() { + clearPluginExplicitlySelectedFlag() triggerEvent(CardReaderHubEvents.NavigateToCardReaderOnboardingScreen) } + private fun clearPluginExplicitlySelectedFlag() { + val site = selectedSite.get() + appPrefsWrapper.setIsCardReaderPluginExplicitlySelectedFlag( + site.id, + site.siteId, + site.selfHostedSiteId, + false + ) + } + sealed class CardReaderHubEvents : MultiLiveEvent.Event() { data class NavigateToCardReaderDetail(val cardReaderFlowParam: CardReaderFlowParam) : CardReaderHubEvents() data class NavigateToPurchaseCardReaderFlow(val url: String) : CardReaderHubEvents() diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt index 22b2844a463..f02024bdb5b 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt @@ -257,6 +257,28 @@ class CardReaderHubViewModelTest : BaseUnitTest() { ) } + @Test + fun `given multiple plugins installed, when payment provider clicked, then clear plugin selected flag`() { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + + initViewModel() + (viewModel.viewStateData.value as CardReaderHubViewModel.CardReaderHubViewState.Content).rows + .find { + it.label == UiString.UiStringRes(R.string.card_reader_manage_payment_provider) + }!!.onItemClicked.invoke() + + verify(appPrefsWrapper).setIsCardReaderPluginExplicitlySelectedFlag( + anyInt(), + anyLong(), + anyLong(), + eq(false) + ) + } + @Test fun `given payment flag disabled, when multiple plugins installed, then payment provider row is not shown`() { whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(false) From 76a3bc22cc9dba65222546f441ffd845c10340df Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 4 Jul 2022 08:21:35 +0530 Subject: [PATCH 133/173] Add navigation to onboarding screen from hub screen. --- .../android/ui/cardreader/hub/CardReaderHubFragment.kt | 9 +++++++++ .../main/res/navigation/nav_graph_card_reader_flow.xml | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubFragment.kt index bb5bea31fba..991cf66964b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubFragment.kt @@ -11,6 +11,8 @@ import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.databinding.FragmentCardReaderHubBinding import com.woocommerce.android.extensions.navigateSafely import com.woocommerce.android.ui.base.BaseFragment +import com.woocommerce.android.ui.cardreader.onboarding.CardReaderFlowParam +import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingParams import com.woocommerce.android.util.ChromeCustomTabUtils import dagger.hilt.android.AndroidEntryPoint @@ -55,6 +57,13 @@ class CardReaderHubFragment : BaseFragment(R.layout.fragment_card_reader_hub) { is CardReaderHubViewModel.CardReaderHubEvents.NavigateToCardReaderManualsScreen -> { findNavController().navigateSafely(R.id.action_cardReaderHubFragment_to_cardReaderManualsFragment) } + is CardReaderHubViewModel.CardReaderHubEvents.NavigateToCardReaderOnboardingScreen -> { + findNavController().navigate( + CardReaderHubFragmentDirections.actionCardReaderHubFragmentToCardReaderOnboardingFragment( + CardReaderOnboardingParams.Check(CardReaderFlowParam.CardReadersHub) + ) + ) + } else -> event.isHandled = false } } diff --git a/WooCommerce/src/main/res/navigation/nav_graph_card_reader_flow.xml b/WooCommerce/src/main/res/navigation/nav_graph_card_reader_flow.xml index 5ea7cfc1e24..18c925a0821 100644 --- a/WooCommerce/src/main/res/navigation/nav_graph_card_reader_flow.xml +++ b/WooCommerce/src/main/res/navigation/nav_graph_card_reader_flow.xml @@ -71,6 +71,11 @@ + Date: Mon, 4 Jul 2022 09:17:20 +0530 Subject: [PATCH 134/173] Track event when "Change Payment Provider" row is clicked --- .../android/analytics/AnalyticsEvent.kt | 2 ++ .../cardreader/hub/CardReaderHubViewModel.kt | 8 +++++++ .../hub/CardReaderHubViewModelTest.kt | 23 ++++++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt index eec15138f9b..f92d8acd3f1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt @@ -258,6 +258,7 @@ enum class AnalyticsEvent(val siteless: Boolean = false) { CARD_PRESENT_ONBOARDING_LEARN_MORE_TAPPED, CARD_PRESENT_ONBOARDING_NOT_COMPLETED, + // -- Card Present Payments - collection CARD_PRESENT_COLLECT_PAYMENT_TAPPED, CARD_PRESENT_COLLECT_PAYMENT_FAILED, @@ -331,6 +332,7 @@ enum class AnalyticsEvent(val siteless: Boolean = false) { SETTINGS_WE_ARE_HIRING_BUTTON_TAPPED, SETTINGS_BETA_FEATURES_PRODUCTS_TOGGLED, SETTINGS_IMAGE_OPTIMIZATION_TOGGLED, + SETTINGS_CARD_PRESENT_SELECT_PAYMENT_GATEWAY_TAPPED, PRIVACY_SETTINGS_COLLECT_INFO_TOGGLED, PRIVACY_SETTINGS_PRIVACY_POLICY_LINK_TAPPED, PRIVACY_SETTINGS_SHARE_INFO_LINK_TAPPED, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt index 0847aad6116..a9cf0808b5d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModel.kt @@ -7,6 +7,8 @@ import androidx.lifecycle.SavedStateHandle import com.woocommerce.android.AppPrefsWrapper import com.woocommerce.android.AppUrls import com.woocommerce.android.R +import com.woocommerce.android.analytics.AnalyticsEvent +import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.model.UiString import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.cardreader.InPersonPaymentsCanadaFeatureFlag @@ -30,6 +32,7 @@ class CardReaderHubViewModel @Inject constructor( private val selectedSite: SelectedSite, private val wooStore: WooCommerceStore, private val ippSelectPaymentGateway: IppSelectPaymentGateway, + private val analyticsTrackerWrapper: AnalyticsTrackerWrapper, ) : ScopedViewModel(savedState) { private val arguments: CardReaderHubFragmentArgs by savedState.navArgs() @@ -114,10 +117,15 @@ class CardReaderHubViewModel @Inject constructor( } private fun onCardReaderPaymentProviderClicked() { + trackPaymentProviderClickedEvent() clearPluginExplicitlySelectedFlag() triggerEvent(CardReaderHubEvents.NavigateToCardReaderOnboardingScreen) } + private fun trackPaymentProviderClickedEvent() { + analyticsTrackerWrapper.track(AnalyticsEvent.SETTINGS_CARD_PRESENT_SELECT_PAYMENT_GATEWAY_TAPPED) + } + private fun clearPluginExplicitlySelectedFlag() { val site = selectedSite.get() appPrefsWrapper.setIsCardReaderPluginExplicitlySelectedFlag( diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt index f02024bdb5b..11cc7567209 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/hub/CardReaderHubViewModelTest.kt @@ -3,6 +3,8 @@ package com.woocommerce.android.ui.cardreader.hub import com.woocommerce.android.AppPrefsWrapper import com.woocommerce.android.AppUrls import com.woocommerce.android.R +import com.woocommerce.android.analytics.AnalyticsEvent +import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.initSavedStateHandle import com.woocommerce.android.model.UiString import com.woocommerce.android.tools.SelectedSite @@ -38,6 +40,7 @@ class CardReaderHubViewModelTest : BaseUnitTest() { } private val wooStore: WooCommerceStore = mock() private val ippSelectPaymentGateway: IppSelectPaymentGateway = mock() + private val analyticsTrackerWrapper: AnalyticsTrackerWrapper = mock() private val countryCode = "US" private val wcPayPluginVersion = "3.3.0" @@ -279,6 +282,23 @@ class CardReaderHubViewModelTest : BaseUnitTest() { ) } + @Test + fun `given multiple plugins installed, when change payment provider clicked, then track event`() { + whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(true) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_STRIPE_GATEWAY)) + .thenReturn(buildStripeExtensionPluginInfo(isActive = true)) + whenever(wooStore.getSitePlugin(selectedSite.get(), WooCommerceStore.WooPlugin.WOO_PAYMENTS)) + .thenReturn(buildWCPayPluginInfo(isActive = true)) + + initViewModel() + (viewModel.viewStateData.value as CardReaderHubViewModel.CardReaderHubViewState.Content).rows + .find { + it.label == UiString.UiStringRes(R.string.card_reader_manage_payment_provider) + }!!.onItemClicked.invoke() + + verify(analyticsTrackerWrapper).track(AnalyticsEvent.SETTINGS_CARD_PRESENT_SELECT_PAYMENT_GATEWAY_TAPPED) + } + @Test fun `given payment flag disabled, when multiple plugins installed, then payment provider row is not shown`() { whenever(ippSelectPaymentGateway.isEnabled()).thenReturn(false) @@ -317,7 +337,8 @@ class CardReaderHubViewModelTest : BaseUnitTest() { appPrefsWrapper, selectedSite, wooStore, - ippSelectPaymentGateway + ippSelectPaymentGateway, + analyticsTrackerWrapper ) } From e2f657df80a6c1f6dabc93f13bff97145e558f27 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Mon, 4 Jul 2022 09:18:29 +0530 Subject: [PATCH 135/173] Fix detekt errors --- .../kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt index f92d8acd3f1..459922c5be7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt @@ -258,7 +258,6 @@ enum class AnalyticsEvent(val siteless: Boolean = false) { CARD_PRESENT_ONBOARDING_LEARN_MORE_TAPPED, CARD_PRESENT_ONBOARDING_NOT_COMPLETED, - // -- Card Present Payments - collection CARD_PRESENT_COLLECT_PAYMENT_TAPPED, CARD_PRESENT_COLLECT_PAYMENT_FAILED, From 07d3c3a6032f5e99ab6d56e826842c8f0f460109 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Mon, 4 Jul 2022 10:55:49 +0100 Subject: [PATCH 136/173] Move the map call above the comment section The previous gave a syntax error on some environments --- fastlane/Fastfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 18df3688dc4..245a0e1b2fd 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -606,13 +606,13 @@ platform :android do locales = options[:locales].split(',') else locales = SUPPORTED_LOCALES + .map { |locale| locale[:google_play] } + .append("en-US") # Depending on how automated this is, possibly on whether we wipe the # emulator before running or not, the zh-CN locale might break due to # Pinwin Keyboard wanting contacts access. If that's the case, you can # skip it by uncommeting the following line. #.reject { |locale| locale[:glotpress] == 'zh-cn' } - .map { |locale| locale[:google_play] } - .append("en-US") end UI.message("Attempting screenshots for locales: #{locales}") From c311d30602930a098a402a7d9f94cbd6d41bd3d4 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 4 Jul 2022 13:35:15 +0300 Subject: [PATCH 137/173] Analysis: Resolve new api lint warnings for html from html static call Replacing 'Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY)' with the 'HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY)' compat related version is the recommended action to resolve this kind of Lint warnings. --- .../com/woocommerce/android/extensions/StringExt.kt | 2 +- .../woocommerce/android/extensions/TextViewExt.kt | 4 ++-- .../woocommerce/android/extensions/WCSSRModelExt.kt | 4 ++-- .../com/woocommerce/android/ui/inbox/InboxScreen.kt | 4 ++-- .../android/ui/login/LoginDiscoveryErrorFragment.kt | 4 ++-- .../android/ui/login/LoginEmailHelpDialogFragment.kt | 6 +++--- .../ui/orders/notes/OrderDetailOrderNoteItemView.kt | 4 ++-- .../shippinglabels/PrintShippingLabelInfoFragment.kt | 12 ++++++------ .../com/woocommerce/android/util/StringUtils.kt | 4 ++-- .../com/woocommerce/android/widgets/WCEmptyView.kt | 5 ++--- 10 files changed, 24 insertions(+), 25 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt index 8cf33f1c91b..3f4e5539400 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/StringExt.kt @@ -26,7 +26,7 @@ fun StringBuilder.appendWithIfNotEmpty(line: String?, separator: String = ", "): } /** - * This is much faster than Html.fromHtml but should only be used when we know the html is valid + * This is much faster than HtmlCompat.fromHtml but should only be used when we know the html is valid * since the regex will be unpredictable with invalid html * String param containing only valid html * @return String without HTML diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt index 995a1214afe..65b7b1e93de 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/TextViewExt.kt @@ -2,7 +2,6 @@ package com.woocommerce.android.extensions import android.graphics.PorterDuff import android.graphics.PorterDuffColorFilter -import android.text.Html import android.text.Selection import android.text.Spannable import android.text.SpannableString @@ -13,6 +12,7 @@ import android.view.View import android.widget.TextView import androidx.annotation.ColorRes import androidx.core.content.ContextCompat +import androidx.core.text.HtmlCompat import androidx.core.text.toSpannable import com.woocommerce.android.widgets.WooClickableSpan @@ -25,7 +25,7 @@ typealias OnLinkClicked = (ClickableSpan) -> Unit * The callback is triggered in addition to the default link handling behavior, it does not override it. */ fun TextView.setHtmlText(html: String, onLinkClicked: OnLinkClicked? = null) { - val spannedHtml = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY) + val spannedHtml = HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY) val strBuilder = SpannableStringBuilder(spannedHtml) onLinkClicked?.let { callback -> diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt index 242334b4e61..b226692b3fe 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/WCSSRModelExt.kt @@ -2,7 +2,7 @@ package com.woocommerce.android.extensions -import android.text.Html +import androidx.core.text.HtmlCompat import com.woocommerce.android.util.WooLog import org.apache.commons.io.FileUtils.byteCountToDisplaySize import org.json.JSONArray @@ -228,7 +228,7 @@ private fun formatSettingsData(data: JSONObject): String { if (currencySymbolHTML == MISSING_VALUE) { MISSING_VALUE } else { - Html.fromHtml(currencySymbolHTML, Html.FROM_HTML_MODE_LEGACY) + HtmlCompat.fromHtml(currencySymbolHTML, HtmlCompat.FROM_HTML_MODE_LEGACY) } ) .append(")\n") diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/inbox/InboxScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/inbox/InboxScreen.kt index 3a4b57431b6..4773ca3ee70 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/inbox/InboxScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/inbox/InboxScreen.kt @@ -1,6 +1,5 @@ package com.woocommerce.android.ui.inbox -import android.text.Html import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement @@ -38,6 +37,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.core.text.HtmlCompat import com.google.accompanist.swiperefresh.SwipeRefresh import com.google.accompanist.swiperefresh.SwipeRefreshIndicator import com.google.accompanist.swiperefresh.rememberSwipeRefreshState @@ -159,7 +159,7 @@ fun InboxNoteRow(note: InboxNoteUi) { style = MaterialTheme.typography.subtitle1 ) Text( - text = Html.fromHtml(note.description, Html.FROM_HTML_MODE_LEGACY).toAnnotatedString(), + text = HtmlCompat.fromHtml(note.description, HtmlCompat.FROM_HTML_MODE_LEGACY).toAnnotatedString(), style = MaterialTheme.typography.body2 ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginDiscoveryErrorFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginDiscoveryErrorFragment.kt index 81aa84b9d9b..a44e176df54 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginDiscoveryErrorFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginDiscoveryErrorFragment.kt @@ -2,13 +2,13 @@ package com.woocommerce.android.ui.login import android.content.Context import android.os.Bundle -import android.text.Html import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar +import androidx.core.text.HtmlCompat import androidx.fragment.app.Fragment import com.woocommerce.android.R import com.woocommerce.android.R.layout @@ -93,7 +93,7 @@ class LoginDiscoveryErrorFragment : Fragment(layout.fragment_login_discovery_err } errorMessage?.let { - binding.discoveryErrorMessage.text = Html.fromHtml(getString(it), Html.FROM_HTML_MODE_LEGACY) + binding.discoveryErrorMessage.text = HtmlCompat.fromHtml(getString(it), HtmlCompat.FROM_HTML_MODE_LEGACY) } with(binding.discoveryWordpressOptionView) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginEmailHelpDialogFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginEmailHelpDialogFragment.kt index 318fb96e76d..eb7a17915e1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginEmailHelpDialogFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/LoginEmailHelpDialogFragment.kt @@ -2,8 +2,8 @@ package com.woocommerce.android.ui.login import android.app.Dialog import android.os.Bundle -import android.text.Html import android.view.ContextThemeWrapper +import androidx.core.text.HtmlCompat import androidx.fragment.app.DialogFragment import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.woocommerce.android.R @@ -41,9 +41,9 @@ class LoginEmailHelpDialogFragment : DialogFragment() { } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val message = Html.fromHtml( + val message = HtmlCompat.fromHtml( getString(R.string.login_email_help_desc, "", "", "", ""), - Html.FROM_HTML_MODE_LEGACY + HtmlCompat.FROM_HTML_MODE_LEGACY ) return MaterialAlertDialogBuilder(ContextThemeWrapper(requireActivity(), style.Theme_Woo_Dialog)) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt index 968a7431228..789a4c5d129 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/notes/OrderDetailOrderNoteItemView.kt @@ -2,13 +2,13 @@ package com.woocommerce.android.ui.orders.notes import android.annotation.SuppressLint import android.content.Context -import android.text.Html import android.text.format.DateFormat import android.util.AttributeSet import android.view.LayoutInflater import androidx.annotation.DrawableRes import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat +import androidx.core.text.HtmlCompat import com.woocommerce.android.R import com.woocommerce.android.databinding.OrderDetailNoteItemBinding import com.woocommerce.android.model.OrderNote @@ -31,7 +31,7 @@ class OrderDetailOrderNoteItemView @JvmOverloads constructor( val header = if (note.isSystemNote) "$date ($type)" else "$date - ${note.author} ($type)" binding.orderNoteHeader.text = header - binding.orderNoteNote.text = Html.fromHtml(note.note, Html.FROM_HTML_MODE_LEGACY) + binding.orderNoteNote.text = HtmlCompat.fromHtml(note.note, HtmlCompat.FROM_HTML_MODE_LEGACY) @DrawableRes val drawableId = when { note.isCustomerNote -> R.drawable.ic_note_public diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelInfoFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelInfoFragment.kt index 9c76f51b688..f3f71af2d43 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelInfoFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelInfoFragment.kt @@ -1,8 +1,8 @@ package com.woocommerce.android.ui.orders.shippinglabels import android.os.Bundle -import android.text.Html import android.view.View +import androidx.core.text.HtmlCompat import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.databinding.FragmentPrintShippingLabelInfoBinding @@ -19,15 +19,15 @@ class PrintShippingLabelInfoFragment : BaseFragment(R.layout.fragment_print_ship super.onViewCreated(view, savedInstanceState) val binding = FragmentPrintShippingLabelInfoBinding.bind(view) binding.printShippingLabelInfoStep1.text = - Html.fromHtml(getString(R.string.print_shipping_label_info_step_1), Html.FROM_HTML_MODE_LEGACY) + HtmlCompat.fromHtml(getString(R.string.print_shipping_label_info_step_1), HtmlCompat.FROM_HTML_MODE_LEGACY) binding.printShippingLabelInfoStep2.text = - Html.fromHtml(getString(R.string.print_shipping_label_info_step_2), Html.FROM_HTML_MODE_LEGACY) + HtmlCompat.fromHtml(getString(R.string.print_shipping_label_info_step_2), HtmlCompat.FROM_HTML_MODE_LEGACY) binding.printShippingLabelInfoStep3.text = - Html.fromHtml(getString(R.string.print_shipping_label_info_step_3), Html.FROM_HTML_MODE_LEGACY) + HtmlCompat.fromHtml(getString(R.string.print_shipping_label_info_step_3), HtmlCompat.FROM_HTML_MODE_LEGACY) binding.printShippingLabelInfoStep4.text = - Html.fromHtml(getString(R.string.print_shipping_label_info_step_4), Html.FROM_HTML_MODE_LEGACY) + HtmlCompat.fromHtml(getString(R.string.print_shipping_label_info_step_4), HtmlCompat.FROM_HTML_MODE_LEGACY) binding.printShippingLabelInfoStep5.text = - Html.fromHtml(getString(R.string.print_shipping_label_info_step_5), Html.FROM_HTML_MODE_LEGACY) + HtmlCompat.fromHtml(getString(R.string.print_shipping_label_info_step_5), HtmlCompat.FROM_HTML_MODE_LEGACY) } override fun onResume() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt index 3dcdbde1913..692df3fb4e3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt @@ -4,11 +4,11 @@ import android.content.Context import android.content.res.Configuration import android.content.res.Resources.NotFoundException import android.net.Uri -import android.text.Html import android.util.Patterns import androidx.annotation.StringRes import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource +import androidx.core.text.HtmlCompat import com.woocommerce.android.extensions.isInteger import com.woocommerce.android.util.WooLog.T.UTILS import com.woocommerce.android.viewmodel.ResourceProvider @@ -245,7 +245,7 @@ object StringUtils { * double spaces with a single space (just in case) */ fun getRawTextFromHtml(htmlStr: String) = - Html.fromHtml(htmlStr, Html.FROM_HTML_MODE_LEGACY).toString() + HtmlCompat.fromHtml(htmlStr, HtmlCompat.FROM_HTML_MODE_LEGACY).toString() .replace("\n", " ") .replace(" ", " ") diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCEmptyView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCEmptyView.kt index b8f71b54c68..c0400dcd11d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCEmptyView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/WCEmptyView.kt @@ -10,7 +10,6 @@ import android.widget.LinearLayout import androidx.annotation.DrawableRes import androidx.appcompat.content.res.AppCompatResources import androidx.core.text.HtmlCompat -import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY import androidx.core.view.isVisible import com.woocommerce.android.R import com.woocommerce.android.databinding.WcEmptyViewBinding @@ -199,10 +198,10 @@ class WCEmptyView @JvmOverloads constructor(ctx: Context, attrs: AttributeSet? = title } - binding.emptyViewTitle.text = HtmlCompat.fromHtml(titleHtml, FROM_HTML_MODE_LEGACY) + binding.emptyViewTitle.text = HtmlCompat.fromHtml(titleHtml, HtmlCompat.FROM_HTML_MODE_LEGACY) binding.emptyViewImage.setImageDrawable(AppCompatResources.getDrawable(context, drawableId)) if (message != null) { - binding.emptyViewMessage.text = HtmlCompat.fromHtml(message, FROM_HTML_MODE_LEGACY) + binding.emptyViewMessage.text = HtmlCompat.fromHtml(message, HtmlCompat.FROM_HTML_MODE_LEGACY) binding.emptyViewMessage.visibility = View.VISIBLE } else { binding.emptyViewMessage.visibility = View.GONE From 4a49cf7fefadeaf2c3186d2fc366be441a047611 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 4 Jul 2022 14:13:26 +0300 Subject: [PATCH 138/173] Analysis: Resolve (no) wildcard imports detekt warnings for java util With this change all the 'import java.util.*' wildcard imports are being replaced with explicit non wildcard imports as per this project standards. Also, with this change 55 entries are removed from the Detekt related 'baseline.xml' file as they are no longer needed. The imports were optimized on all those files that were violating the 'import java.util.*' (no) wildcard imports rule. This means that on some of those file additional imports were optimized as well and thus those got removed from the 'baseline.xml' file too (for example see 'ProductVariation', 'WooLogViewerScreen', 'AnalyticsViewModel', 'MyStoreStatsView', 'ShippingCarrierRatesAdapter' classes and 'AnalyticsViewModelTest', 'PrintShippingLabelViewModelTest', 'ShippingLabelRefundViewModelTest', 'OrderTestUtils' test classes). --- .../android/analytics/AnalyticsTracker.kt | 3 +- .../woocommerce/android/extensions/DateExt.kt | 4 +- .../woocommerce/android/model/OrderMapper.kt | 2 +- .../android/model/ProductCategory.kt | 3 +- .../android/model/ProductVariation.kt | 10 +++- .../android/model/ShippingLabel.kt | 2 +- .../android/model/ShippingLabelMapper.kt | 2 +- .../android/support/WooLogViewerScreen.kt | 16 +++++- .../ui/analytics/AnalyticsViewModel.kt | 8 ++- .../AnalyticsDateRangeCalculator.kt | 4 +- .../MyStoreStatsUsageTracksEventEmitter.kt | 2 +- .../android/ui/mystore/MyStoreStatsView.kt | 10 +++- .../ui/mystore/MyStoreTopPerformersView.kt | 2 +- .../android/ui/orders/OrderCustomerHelper.kt | 2 +- .../android/ui/orders/OrderStatusTag.kt | 2 +- .../PrintShippingLabelViewModel.kt | 3 +- .../creation/ShippingCarrierRatesAdapter.kt | 14 ++++- .../ShippingLabelPaymentMethodsAdapter.kt | 2 +- .../ui/products/ProductDetailViewModel.kt | 4 +- .../android/ui/products/ProductStatus.kt | 2 +- .../android/ui/products/ProductType.kt | 2 +- .../settings/ProductCatalogVisibility.kt | 2 +- .../ui/products/settings/ProductVisibility.kt | 2 +- .../ui/refunds/IssueRefundViewModel.kt | 3 +- .../woocommerce/android/util/PackageUtils.kt | 2 +- .../woocommerce/android/util/PriceUtils.kt | 2 +- .../android/util/RollingLogEntries.kt | 4 +- .../woocommerce/android/util/StringUtils.kt | 2 +- .../woocommerce/android/widgets/tags/ITag.kt | 2 +- .../ui/analytics/AnalyticsViewModelTest.kt | 9 ++- .../AnalyticsDateRangeCalculatorTest.kt | 3 +- .../android/ui/orders/OrderTestUtils.kt | 17 ++++-- .../PrintShippingLabelViewModelTest.kt | 7 ++- .../ShippingLabelRefundViewModelTest.kt | 11 +++- .../android/util/PriceUtilsTest.kt | 3 +- config/detekt/baseline.xml | 55 ------------------- 36 files changed, 117 insertions(+), 106 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt index 095705353a9..85aed8ff252 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt @@ -11,7 +11,8 @@ import com.woocommerce.android.util.WooLog import com.woocommerce.android.util.WooLog.T import org.json.JSONObject import org.wordpress.android.fluxc.model.SiteModel -import java.util.* +import java.util.Locale +import java.util.UUID class AnalyticsTracker private constructor(private val context: Context) { private var tracksClient: TracksClient? = TracksClient.getClient(context) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/DateExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/DateExt.kt index 27e56e8fef7..13429a579d4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/DateExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/DateExt.kt @@ -7,7 +7,9 @@ import com.woocommerce.android.util.WooLog.T import org.apache.commons.lang3.time.DateUtils.isSameDay import java.text.DateFormatSymbols import java.text.SimpleDateFormat -import java.util.* +import java.util.Calendar +import java.util.Date +import java.util.Locale import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit.MILLISECONDS diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt index a20c76ef4c9..46b2235eec6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt @@ -13,7 +13,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.wc.order.OrderMappingConst import org.wordpress.android.fluxc.network.rest.wpcom.wc.order.OrderMappingConst.SHIPPING_PHONE_KEY import org.wordpress.android.util.DateTimeUtils import java.math.BigDecimal -import java.util.* +import java.util.Date import javax.inject.Inject import org.wordpress.android.fluxc.model.order.FeeLine as WCFeeLine import org.wordpress.android.fluxc.model.order.LineItem as WCLineItem diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductCategory.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductCategory.kt index c16110beed0..1807fb03a05 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductCategory.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductCategory.kt @@ -7,7 +7,8 @@ import com.woocommerce.android.ui.products.categories.ProductCategoryItemUiModel import com.woocommerce.android.viewmodel.ResourceProvider import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.model.WCProductCategoryModel -import java.util.* +import java.util.Locale +import java.util.Stack @Parcelize data class ProductCategory( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductVariation.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductVariation.kt index 7d36ca941c4..a7e9e5403dd 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductVariation.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductVariation.kt @@ -3,7 +3,13 @@ package com.woocommerce.android.model import android.os.Parcelable import com.google.gson.JsonArray import com.google.gson.JsonObject -import com.woocommerce.android.extensions.* +import com.woocommerce.android.extensions.fastStripHtml +import com.woocommerce.android.extensions.formatToString +import com.woocommerce.android.extensions.formatToYYYYmmDDhhmmss +import com.woocommerce.android.extensions.isEquivalentTo +import com.woocommerce.android.extensions.isNotSet +import com.woocommerce.android.extensions.isSet +import com.woocommerce.android.extensions.parseFromIso8601DateFormat import com.woocommerce.android.model.Product.Image import com.woocommerce.android.ui.products.ProductBackorderStatus import com.woocommerce.android.ui.products.ProductStatus @@ -14,7 +20,7 @@ import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.model.WCProductVariationModel import org.wordpress.android.util.DateTimeUtils import java.math.BigDecimal -import java.util.* +import java.util.Date @Parcelize data class ProductVariation( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabel.kt index ca43c2ed960..4e369b31448 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabel.kt @@ -6,7 +6,7 @@ import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.model.shippinglabels.WCShippingLabelModel import java.math.BigDecimal -import java.util.* +import java.util.Date import java.util.concurrent.TimeUnit @Parcelize diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabelMapper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabelMapper.kt index 207a28d1dcf..85e4a10d257 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabelMapper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ShippingLabelMapper.kt @@ -1,7 +1,7 @@ package com.woocommerce.android.model import org.wordpress.android.fluxc.model.shippinglabels.WCShippingLabelModel -import java.util.* +import java.util.Date import javax.inject.Inject class ShippingLabelMapper @Inject constructor(private val addressMapper: ShippingLabelAddressMapper) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/support/WooLogViewerScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/support/WooLogViewerScreen.kt index 782932508a6..f5b9cd0d91b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/support/WooLogViewerScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/support/WooLogViewerScreen.kt @@ -2,11 +2,21 @@ package com.woocommerce.android.support import androidx.annotation.ColorRes import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.text.selection.SelectionContainer -import androidx.compose.material.* +import androidx.compose.material.Divider +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.Share @@ -22,7 +32,7 @@ import com.woocommerce.android.R import com.woocommerce.android.util.RollingLogEntries import com.woocommerce.android.util.WooLog import java.lang.String.format -import java.util.* +import java.util.Locale @Composable fun WooLogViewerScreen( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/AnalyticsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/AnalyticsViewModel.kt index 4aca33737e8..057d17366e1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/AnalyticsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/AnalyticsViewModel.kt @@ -2,9 +2,13 @@ package com.woocommerce.android.ui.analytics import androidx.lifecycle.SavedStateHandle import com.woocommerce.android.R -import com.woocommerce.android.ui.analytics.daterangeselector.* +import com.woocommerce.android.ui.analytics.daterangeselector.AnalyticsDateRangeCalculator +import com.woocommerce.android.ui.analytics.daterangeselector.AnalyticsDateRangeSelectorViewState +import com.woocommerce.android.ui.analytics.daterangeselector.AnalyticsDateRanges +import com.woocommerce.android.ui.analytics.daterangeselector.DateRange import com.woocommerce.android.ui.analytics.daterangeselector.DateRange.MultipleDateRange import com.woocommerce.android.ui.analytics.daterangeselector.DateRange.SimpleDateRange +import com.woocommerce.android.ui.analytics.daterangeselector.formatDatesToFriendlyPeriod import com.woocommerce.android.util.DateUtils import com.woocommerce.android.viewmodel.ResourceProvider import com.woocommerce.android.viewmodel.ScopedViewModel @@ -12,7 +16,7 @@ import com.zendesk.util.DateUtils.isSameDay import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import java.util.* +import java.util.Date import javax.inject.Inject @HiltViewModel diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/daterangeselector/AnalyticsDateRangeCalculator.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/daterangeselector/AnalyticsDateRangeCalculator.kt index 7127caa23e0..e4008bce6c2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/daterangeselector/AnalyticsDateRangeCalculator.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/daterangeselector/AnalyticsDateRangeCalculator.kt @@ -3,7 +3,9 @@ package com.woocommerce.android.ui.analytics.daterangeselector import com.woocommerce.android.ui.analytics.daterangeselector.DateRange.MultipleDateRange import com.woocommerce.android.ui.analytics.daterangeselector.DateRange.SimpleDateRange import com.woocommerce.android.util.DateUtils -import java.util.* +import java.util.Calendar +import java.util.Date +import java.util.Locale import javax.inject.Inject sealed class DateRange { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreStatsUsageTracksEventEmitter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreStatsUsageTracksEventEmitter.kt index 8951ea84ae1..6d132cc7504 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreStatsUsageTracksEventEmitter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreStatsUsageTracksEventEmitter.kt @@ -8,7 +8,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.wordpress.android.util.DateTimeUtils -import java.util.* +import java.util.Date import javax.inject.Inject import javax.inject.Singleton diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreStatsView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreStatsView.kt index a3516dfdfde..7b95210d945 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreStatsView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreStatsView.kt @@ -30,7 +30,12 @@ import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.databinding.MyStoreStatsBinding -import com.woocommerce.android.extensions.* +import com.woocommerce.android.extensions.formatDateToFriendlyDayHour +import com.woocommerce.android.extensions.formatDateToFriendlyLongMonthDate +import com.woocommerce.android.extensions.formatDateToFriendlyLongMonthYear +import com.woocommerce.android.extensions.formatDateToYearMonth +import com.woocommerce.android.extensions.formatToDateOnly +import com.woocommerce.android.extensions.formatToMonthDateOnly import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.mystore.MyStoreFragment.Companion.DEFAULT_STATS_GRANULARITY import com.woocommerce.android.util.CurrencyFormatter @@ -43,13 +48,12 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.launch import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity import org.wordpress.android.util.DisplayUtils import java.text.DecimalFormat -import java.util.* +import java.util.Locale import kotlin.math.round @FlowPreview diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreTopPerformersView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreTopPerformersView.kt index abf1c0fddaf..d5f26900a41 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreTopPerformersView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/mystore/MyStoreTopPerformersView.kt @@ -19,7 +19,7 @@ import com.woocommerce.android.di.GlideApp import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.widgets.SkeletonView import org.wordpress.android.fluxc.store.WCStatsStore.StatsGranularity -import java.util.* +import java.util.Locale class MyStoreTopPerformersView @JvmOverloads constructor( ctx: Context, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderCustomerHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderCustomerHelper.kt index 28e913ab1dd..2da0d84d169 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderCustomerHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderCustomerHelper.kt @@ -9,7 +9,7 @@ import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.model.Order import org.wordpress.android.util.ToastUtils -import java.util.* +import java.util.Locale object OrderCustomerHelper { enum class Action { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt index d50c01248b2..1a61595a69d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/OrderStatusTag.kt @@ -7,7 +7,7 @@ import com.woocommerce.android.model.Order.OrderStatus import com.woocommerce.android.widgets.tags.ITag import com.woocommerce.android.widgets.tags.TagConfig import org.wordpress.android.fluxc.network.rest.wpcom.wc.order.CoreOrderStatus -import java.util.* +import java.util.Locale /** * Represents a single order status label. diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModel.kt index 6d7b1d5634a..fd138f2bd16 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModel.kt @@ -24,7 +24,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize import java.io.File -import java.util.* +import java.util.Date +import java.util.Locale import javax.inject.Inject @HiltViewModel diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCarrierRatesAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCarrierRatesAdapter.kt index cb59dab42a8..f7592de12be 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCarrierRatesAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingCarrierRatesAdapter.kt @@ -14,7 +14,11 @@ import com.woocommerce.android.R import com.woocommerce.android.R.string import com.woocommerce.android.databinding.ShippingRateListBinding import com.woocommerce.android.databinding.ShippingRateListItemBinding -import com.woocommerce.android.extensions.* +import com.woocommerce.android.extensions.collapse +import com.woocommerce.android.extensions.expand +import com.woocommerce.android.extensions.hide +import com.woocommerce.android.extensions.isEqualTo +import com.woocommerce.android.extensions.show import com.woocommerce.android.model.ShippingLabelPackage import com.woocommerce.android.model.ShippingRate import com.woocommerce.android.model.ShippingRate.Option @@ -24,12 +28,16 @@ import com.woocommerce.android.model.ShippingRate.Option.SIGNATURE import com.woocommerce.android.model.getTitle import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.RateListAdapter.RateViewHolder import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.RateListViewHolder -import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.ShippingRateItem.ShippingCarrier.* +import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.ShippingRateItem.ShippingCarrier.DHL +import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.ShippingRateItem.ShippingCarrier.FEDEX +import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.ShippingRateItem.ShippingCarrier.UNKNOWN +import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.ShippingRateItem.ShippingCarrier.UPS +import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.ShippingRateItem.ShippingCarrier.USPS import com.woocommerce.android.util.DateUtils import com.woocommerce.android.util.StringUtils import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize -import java.util.* +import java.util.Date class ShippingCarrierRatesAdapter( private val onRateSelected: (ShippingRate) -> Unit, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelPaymentMethodsAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelPaymentMethodsAdapter.kt index 80d5a2efb06..47636230e64 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelPaymentMethodsAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelPaymentMethodsAdapter.kt @@ -14,7 +14,7 @@ import com.woocommerce.android.model.PaymentMethod import com.woocommerce.android.ui.orders.shippinglabels.creation.EditShippingLabelPaymentViewModel.PaymentMethodUiModel import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelPaymentMethodsAdapter.PaymentMethodViewHolder import java.text.SimpleDateFormat -import java.util.* +import java.util.Locale class ShippingLabelPaymentMethodsAdapter( private val onPaymentMethodSelected: (PaymentMethod) -> Unit diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailViewModel.kt index 3cc9134fc40..9df19232b56 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailViewModel.kt @@ -121,7 +121,9 @@ import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.store.WCProductStore.ProductErrorType import java.math.BigDecimal -import java.util.* +import java.util.Collections +import java.util.Date +import java.util.Locale import javax.inject.Inject @HiltViewModel diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductStatus.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductStatus.kt index 079467afe8f..6cacad47c6c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductStatus.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductStatus.kt @@ -4,7 +4,7 @@ import android.content.Context import androidx.annotation.StringRes import com.woocommerce.android.R import org.wordpress.android.fluxc.network.rest.wpcom.wc.product.CoreProductStatus -import java.util.* +import java.util.Locale /** * Similar to PostStatus except only draft, pending, private, and publish are supported diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductType.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductType.kt index 437d20c9d5a..bd80231ef26 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductType.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductType.kt @@ -3,7 +3,7 @@ package com.woocommerce.android.ui.products import androidx.annotation.StringRes import com.woocommerce.android.R import org.wordpress.android.fluxc.network.rest.wpcom.wc.product.CoreProductType -import java.util.* +import java.util.Locale enum class ProductType(@StringRes val stringResource: Int = 0, val value: String = "") { SIMPLE(R.string.product_type_simple, CoreProductType.SIMPLE.value), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductCatalogVisibility.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductCatalogVisibility.kt index 9bf5b74082a..b1e0d0ba17b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductCatalogVisibility.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductCatalogVisibility.kt @@ -3,7 +3,7 @@ package com.woocommerce.android.ui.products.settings import android.content.Context import androidx.annotation.StringRes import com.woocommerce.android.R -import java.util.* +import java.util.Locale enum class ProductCatalogVisibility { VISIBLE, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductVisibility.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductVisibility.kt index 0d6cf407cf5..016c7ccdc47 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductVisibility.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/settings/ProductVisibility.kt @@ -3,7 +3,7 @@ package com.woocommerce.android.ui.products.settings import android.content.Context import androidx.annotation.StringRes import com.woocommerce.android.R -import java.util.* +import java.util.Locale enum class ProductVisibility { PUBLIC, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt index 07d037cf76c..0b58e54bdce 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/refunds/IssueRefundViewModel.kt @@ -75,10 +75,9 @@ import org.wordpress.android.fluxc.store.WCOrderStore import org.wordpress.android.fluxc.store.WCRefundStore import org.wordpress.android.fluxc.store.WooCommerceStore import java.math.BigDecimal -import java.util.* +import java.util.Locale import javax.inject.Inject import kotlin.collections.set -import kotlin.collections.sumBy import kotlin.math.min import org.wordpress.android.fluxc.utils.sumBy as sumByBigDecimal diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt index ff39a21c0cb..10d606ef9ce 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PackageUtils.kt @@ -5,7 +5,7 @@ import android.content.pm.PackageInfo import android.content.pm.PackageManager import androidx.core.content.pm.PackageInfoCompat import com.woocommerce.android.BuildConfig -import java.util.* +import java.util.Locale object PackageUtils { const val PACKAGE_VERSION_CODE_DEFAULT = -1 diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PriceUtils.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PriceUtils.kt index bfbb11c052a..8ce1638c341 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PriceUtils.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/PriceUtils.kt @@ -8,7 +8,7 @@ import com.woocommerce.android.ui.products.models.SiteParameters import com.woocommerce.android.viewmodel.ResourceProvider import org.wordpress.android.util.DateTimeUtils import java.math.BigDecimal -import java.util.* +import java.util.Date object PriceUtils { @Suppress("LongParameterList") diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/RollingLogEntries.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/RollingLogEntries.kt index 39f67c87943..21795ff7abe 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/RollingLogEntries.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/RollingLogEntries.kt @@ -6,7 +6,9 @@ import com.woocommerce.android.util.WooLog.T import org.wordpress.android.util.DateTimeUtils import java.security.InvalidParameterException import java.text.SimpleDateFormat -import java.util.* +import java.util.Date +import java.util.LinkedList +import java.util.Locale /** * Fix-sized list of log entries diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt index 692df3fb4e3..e639dea425d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/StringUtils.kt @@ -15,7 +15,7 @@ import com.woocommerce.android.viewmodel.ResourceProvider import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.util.FormatUtils import java.io.IOException -import java.util.* +import java.util.Locale import java.util.regex.Pattern import kotlin.math.abs diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/tags/ITag.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/tags/ITag.kt index b76e3371697..8fb131f7616 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/tags/ITag.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/widgets/tags/ITag.kt @@ -1,7 +1,7 @@ package com.woocommerce.android.widgets.tags import android.content.Context -import java.util.* +import java.util.Locale /** * Interface for working with individual Tag elements. diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/AnalyticsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/AnalyticsViewModelTest.kt index 390a4ccf371..80b1211d8ce 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/AnalyticsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/AnalyticsViewModelTest.kt @@ -10,9 +10,14 @@ import com.woocommerce.android.viewmodel.BaseUnitTest import com.woocommerce.android.viewmodel.ResourceProvider import kotlinx.coroutines.ExperimentalCoroutinesApi import org.junit.Test -import org.mockito.kotlin.* +import org.mockito.kotlin.any +import org.mockito.kotlin.anyVararg +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doReturnConsecutively +import org.mockito.kotlin.mock import java.text.SimpleDateFormat -import java.util.* +import java.util.Date import kotlin.test.assertEquals import kotlin.test.assertNotNull diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/daterangeselector/AnalyticsDateRangeCalculatorTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/daterangeselector/AnalyticsDateRangeCalculatorTest.kt index 8baa40cac6c..b1ee7d89f34 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/daterangeselector/AnalyticsDateRangeCalculatorTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/analytics/daterangeselector/AnalyticsDateRangeCalculatorTest.kt @@ -7,7 +7,8 @@ import org.junit.Test import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.whenever -import java.util.* +import java.util.Calendar +import java.util.Date import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderTestUtils.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderTestUtils.kt index 4956369673c..f43c82faea1 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderTestUtils.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/OrderTestUtils.kt @@ -1,14 +1,23 @@ package com.woocommerce.android.ui.orders -import com.woocommerce.android.model.* +import com.woocommerce.android.model.Address +import com.woocommerce.android.model.Order import com.woocommerce.android.model.Order.Item -import org.wordpress.android.fluxc.model.* +import com.woocommerce.android.model.OrderNote +import com.woocommerce.android.model.OrderShipmentTracking +import com.woocommerce.android.model.Refund +import com.woocommerce.android.model.ShippingLabel +import com.woocommerce.android.model.toAppModel +import org.wordpress.android.fluxc.model.LocalOrRemoteId +import org.wordpress.android.fluxc.model.OrderEntity +import org.wordpress.android.fluxc.model.WCOrderShipmentProviderModel +import org.wordpress.android.fluxc.model.WCOrderShipmentTrackingModel +import org.wordpress.android.fluxc.model.WCOrderStatusModel import org.wordpress.android.fluxc.network.rest.wpcom.wc.order.CoreOrderStatus import org.wordpress.android.util.DateTimeUtils import java.math.BigDecimal import java.text.SimpleDateFormat -import java.util.* -import kotlin.collections.ArrayList +import java.util.Date object OrderTestUtils { const val ORDER_ID = 1L diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModelTest.kt index ea186683b18..272e6fb2080 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/PrintShippingLabelViewModelTest.kt @@ -6,7 +6,9 @@ import com.woocommerce.android.extensions.takeIfNotEqualTo import com.woocommerce.android.initSavedStateHandle import com.woocommerce.android.media.FileUtils import com.woocommerce.android.tools.NetworkStatus -import com.woocommerce.android.ui.orders.OrderNavigationTarget.* +import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewPrintShippingLabelInfo +import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewShippingLabelFormatOptions +import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewShippingLabelPaperSizes import com.woocommerce.android.ui.orders.OrderTestUtils import com.woocommerce.android.ui.orders.shippinglabels.PrintShippingLabelViewModel.PrintShippingLabelViewState import com.woocommerce.android.ui.orders.shippinglabels.ShippingLabelPaperSizeSelectorDialog.ShippingLabelPaperSize @@ -26,8 +28,7 @@ import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType.NETWORK_ import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooError import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType.API_ERROR import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult -import java.util.* -import kotlin.collections.ArrayList +import java.util.Date import kotlin.test.assertNotNull @ExperimentalCoroutinesApi diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/ShippingLabelRefundViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/ShippingLabelRefundViewModelTest.kt index 92c79640430..13162f077ca 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/ShippingLabelRefundViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/shippinglabels/ShippingLabelRefundViewModelTest.kt @@ -12,12 +12,19 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test -import org.mockito.kotlin.* +import org.mockito.kotlin.any +import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.spy +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType.NETWORK_ERROR import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooError import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType.API_ERROR import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult -import java.util.* +import java.util.Date import java.util.concurrent.TimeUnit import kotlin.test.assertNotNull import kotlin.test.assertNull diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/util/PriceUtilsTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/util/PriceUtilsTest.kt index 16260fdb43c..fd6c9ee4c76 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/util/PriceUtilsTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/util/PriceUtilsTest.kt @@ -9,7 +9,8 @@ import org.mockito.kotlin.any import org.mockito.kotlin.eq import org.mockito.kotlin.mock import java.math.BigDecimal -import java.util.* +import java.util.Date +import java.util.Locale const val SALE_DATES_PRICING_GROUP_KEY = "SALE" diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 2d980e167c2..a6be72224b3 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -147,7 +147,6 @@ NoWildcardImports:com.woocommerce.android.AppPrefsTest.kt:4 NoWildcardImports:com.woocommerce.android.cardreader.internal.payments.PaymentErrorMapper.kt:12 NoWildcardImports:com.woocommerce.android.cardreader.internal.payments.PaymentManager.kt:20 - NoWildcardImports:com.woocommerce.android.extensions.DateExt.kt:10 NoWildcardImports:com.woocommerce.android.extensions.LiveDataExt.kt:3 NoWildcardImports:com.woocommerce.android.extensions.ViewExt.kt:25 NoWildcardImports:com.woocommerce.android.media.MediaFilesRepository.kt:13 @@ -158,15 +157,10 @@ NoWildcardImports:com.woocommerce.android.media.ProductImagesUploadWorker.kt:4 NoWildcardImports:com.woocommerce.android.model.FeatureFeedbackSettingsTest.kt:3 NoWildcardImports:com.woocommerce.android.model.Notification.kt:5 - NoWildcardImports:com.woocommerce.android.model.OrderMapper.kt:16 NoWildcardImports:com.woocommerce.android.model.Product.kt:16 NoWildcardImports:com.woocommerce.android.model.Product.kt:6 NoWildcardImports:com.woocommerce.android.model.Product.kt:7 - NoWildcardImports:com.woocommerce.android.model.ProductVariation.kt:17 - NoWildcardImports:com.woocommerce.android.model.ProductVariation.kt:6 NoWildcardImports:com.woocommerce.android.model.Refund.kt:8 - NoWildcardImports:com.woocommerce.android.model.ShippingLabel.kt:9 - NoWildcardImports:com.woocommerce.android.model.ShippingLabelMapper.kt:4 NoWildcardImports:com.woocommerce.android.push.NotificationChannelType.kt:7 NoWildcardImports:com.woocommerce.android.push.NotificationMessageHandlerTest.kt:12 NoWildcardImports:com.woocommerce.android.push.NotificationMessageHandlerTest.kt:17 @@ -177,15 +171,6 @@ NoWildcardImports:com.woocommerce.android.screenshots.orders.SingleOrderScreen.kt:5 NoWildcardImports:com.woocommerce.android.screenshots.util.Screen.kt:18 NoWildcardImports:com.woocommerce.android.screenshots.util.Screen.kt:7 - NoWildcardImports:com.woocommerce.android.support.WooLogViewerScreen.kt:25 - NoWildcardImports:com.woocommerce.android.support.WooLogViewerScreen.kt:5 - NoWildcardImports:com.woocommerce.android.support.WooLogViewerScreen.kt:9 - NoWildcardImports:com.woocommerce.android.ui.analytics.AnalyticsViewModel.kt:15 - NoWildcardImports:com.woocommerce.android.ui.analytics.AnalyticsViewModel.kt:5 - NoWildcardImports:com.woocommerce.android.ui.analytics.AnalyticsViewModelTest.kt:13 - NoWildcardImports:com.woocommerce.android.ui.analytics.AnalyticsViewModelTest.kt:15 - NoWildcardImports:com.woocommerce.android.ui.analytics.daterangeselector.AnalyticsDateRangeCalculator.kt:6 - NoWildcardImports:com.woocommerce.android.ui.analytics.daterangeselector.AnalyticsDateRangeCalculatorTest.kt:10 NoWildcardImports:com.woocommerce.android.ui.common.UserEligibilityErrorViewModelTest.kt:10 NoWildcardImports:com.woocommerce.android.ui.common.UserEligibilityErrorViewModelTest.kt:15 NoWildcardImports:com.woocommerce.android.ui.compose.animations.SkeletonAnimation.kt:3 @@ -219,10 +204,6 @@ NoWildcardImports:com.woocommerce.android.ui.moremenu.MoreMenu.kt:11 NoWildcardImports:com.woocommerce.android.ui.moremenu.MoreMenu.kt:17 NoWildcardImports:com.woocommerce.android.ui.moremenu.MoreMenuFragment.kt:18 - NoWildcardImports:com.woocommerce.android.ui.mystore.MyStoreStatsUsageTracksEventEmitter.kt:11 - NoWildcardImports:com.woocommerce.android.ui.mystore.MyStoreStatsView.kt:33 - NoWildcardImports:com.woocommerce.android.ui.mystore.MyStoreStatsView.kt:52 - NoWildcardImports:com.woocommerce.android.ui.mystore.MyStoreTopPerformersView.kt:22 NoWildcardImports:com.woocommerce.android.ui.mystore.MyStoreViewModel.kt:18 NoWildcardImports:com.woocommerce.android.ui.mystore.MyStoreViewModel.kt:29 NoWildcardImports:com.woocommerce.android.ui.mystore.MyStoreViewModelTest.kt:18 @@ -237,9 +218,6 @@ NoWildcardImports:com.woocommerce.android.ui.orders.OrderListViewModelTest.kt:23 NoWildcardImports:com.woocommerce.android.ui.orders.OrderListViewModelTest.kt:29 NoWildcardImports:com.woocommerce.android.ui.orders.OrderListViewModelTest.kt:37 - NoWildcardImports:com.woocommerce.android.ui.orders.OrderTestUtils.kt:10 - NoWildcardImports:com.woocommerce.android.ui.orders.OrderTestUtils.kt:3 - NoWildcardImports:com.woocommerce.android.ui.orders.OrderTestUtils.kt:5 NoWildcardImports:com.woocommerce.android.ui.orders.cardreader.ReceiptPreviewViewModelTest.kt:15 NoWildcardImports:com.woocommerce.android.ui.orders.cardreader.ReceiptPreviewViewModelTest.kt:4 NoWildcardImports:com.woocommerce.android.ui.orders.cardreader.payment.CardReaderPaymentErrorMapper.kt:4 @@ -281,11 +259,6 @@ NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.PrintShippingLabelCustomsFormFragment.kt:27 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.PrintShippingLabelCustomsFormViewModelTest.kt:15 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.PrintShippingLabelCustomsFormViewModelTest.kt:9 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.PrintShippingLabelViewModel.kt:27 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.PrintShippingLabelViewModelTest.kt:29 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.PrintShippingLabelViewModelTest.kt:9 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.ShippingLabelRefundViewModelTest.kt:15 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.ShippingLabelRefundViewModelTest.kt:20 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.ShippingLabelRepository.kt:4 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.kt:3 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelFragment.kt:21 @@ -305,14 +278,10 @@ NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.EditShippingLabelPaymentFragment.kt:16 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.EditShippingLabelPaymentViewModelTest.kt:8 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.MoveShippingItemViewModel.kt:9 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.kt:17 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.kt:27 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.kt:32 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCustomsViewModelTest.kt:16 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressSuggestionFragment.kt:11 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressSuggestionFragment.kt:18 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelCreateCustomPackageViewModelTest.kt:9 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelPaymentMethodsAdapter.kt:17 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelsStateMachine.kt:15 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelsStateMachine.kt:16 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelsStateMachine.kt:5 @@ -356,18 +325,6 @@ NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailRepository.kt:26 NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailRepository.kt:4 NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailRepository.kt:7 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:12 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:14 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:16 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:17 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:22 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:23 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:24 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:39 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:41 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:44 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:52 - NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModel.kt:7 NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModelTest.kt:15 NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModelTest.kt:18 NoWildcardImports:com.woocommerce.android.ui.products.ProductDetailViewModelTest.kt:29 @@ -402,7 +359,6 @@ NoWildcardImports:com.woocommerce.android.ui.products.variations.VariationDetailViewModel.kt:37 NoWildcardImports:com.woocommerce.android.ui.products.variations.VariationDetailViewModelTest.kt:24 NoWildcardImports:com.woocommerce.android.ui.products.variations.VariationListAdapter.kt:22 - NoWildcardImports:com.woocommerce.android.ui.refunds.IssueRefundViewModel.kt:74 NoWildcardImports:com.woocommerce.android.ui.reviews.ReviewDetailFragment.kt:32 NoWildcardImports:com.woocommerce.android.ui.reviews.ReviewDetailFragment.kt:41 NoWildcardImports:com.woocommerce.android.ui.reviews.ReviewDetailRepository.kt:6 @@ -418,10 +374,6 @@ NoWildcardImports:com.woocommerce.android.ui.whatsnew.FeatureAnnouncementDialogFragment.kt:5 NoWildcardImports:com.woocommerce.android.util.CurrencyFormatterTest.kt:10 NoWildcardImports:com.woocommerce.android.util.NumberRounding.kt:3 - NoWildcardImports:com.woocommerce.android.util.PriceUtils.kt:11 - NoWildcardImports:com.woocommerce.android.util.PriceUtilsTest.kt:12 - NoWildcardImports:com.woocommerce.android.util.RollingLogEntries.kt:9 - NoWildcardImports:com.woocommerce.android.util.StringUtils.kt:19 NoWildcardImports:com.woocommerce.android.viewmodel.ResourceProvider.kt:4 NoWildcardImports:com.woocommerce.android.viewmodel.ScopedViewModel.kt:3 NoWildcardImports:com.woocommerce.android.widgets.WCMaterialOutlinedCurrencyEditTextView.kt:28 @@ -581,7 +533,6 @@ WildcardImport:MoreMenu.kt$import androidx.compose.material.* WildcardImport:MoreMenuFragment.kt$import com.woocommerce.android.ui.moremenu.MoreMenuViewModel.MoreMenuEvent.* WildcardImport:MoveShippingItemViewModel.kt$import com.woocommerce.android.ui.orders.shippinglabels.creation.MoveShippingItemViewModel.DestinationPackage.* - WildcardImport:MyStoreStatsView.kt$import com.woocommerce.android.extensions.* WildcardImport:MyStoreViewModel.kt$import com.woocommerce.android.ui.mystore.domain.GetStats.LoadStatsResult.* WildcardImport:MyStoreViewModel.kt$import kotlinx.coroutines.flow.* WildcardImport:Notification.kt$import com.woocommerce.android.push.* @@ -626,7 +577,6 @@ WildcardImport:ProductDetailViewModel.kt$import com.woocommerce.android.model.* WildcardImport:ProductDetailViewModel.kt$import com.woocommerce.android.ui.products.ProductDetailViewModel.ProductExitEvent.* WildcardImport:ProductDetailViewModel.kt$import com.woocommerce.android.ui.products.ProductNavigationTarget.* - WildcardImport:ProductDetailViewModel.kt$import com.woocommerce.android.ui.products.ProductStatus.* WildcardImport:ProductDetailViewModel.kt$import com.woocommerce.android.viewmodel.* WildcardImport:ProductDetailViewModel.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:ProductDetailViewModel.kt$import kotlinx.coroutines.flow.* @@ -642,7 +592,6 @@ WildcardImport:ProductReviewsFragment.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:ProductReviewsViewModel.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:ProductSelectionListFragment.kt$import android.view.* - WildcardImport:ProductVariation.kt$import com.woocommerce.android.extensions.* WildcardImport:Refund.kt$import org.wordpress.android.fluxc.model.refunds.WCRefundModel.* WildcardImport:ResourceProvider.kt$import androidx.annotation.* WildcardImport:ReviewDetailFragment.kt$import com.woocommerce.android.ui.reviews.ProductReviewStatus.* @@ -655,8 +604,6 @@ WildcardImport:ReviewModerationHandler.kt$import kotlinx.coroutines.* WildcardImport:ReviewModerationHandler.kt$import kotlinx.coroutines.flow.* WildcardImport:ScopedViewModel.kt$import androidx.lifecycle.* - WildcardImport:ShippingCarrierRatesAdapter.kt$import com.woocommerce.android.extensions.* - WildcardImport:ShippingCarrierRatesAdapter.kt$import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCarrierRatesAdapter.ShippingRateItem.ShippingCarrier.* WildcardImport:ShippingLabelAddressSuggestionFragment.kt$import com.woocommerce.android.extensions.* WildcardImport:ShippingLabelAddressSuggestionFragment.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:ShippingLabelRepository.kt$import com.woocommerce.android.model.* @@ -673,7 +620,5 @@ WildcardImport:VariationListAdapter.kt$import com.woocommerce.android.ui.products.ProductStockStatus.* WildcardImport:ViewExt.kt$import kotlinx.coroutines.flow.* WildcardImport:WCMaterialOutlinedCurrencyEditTextView.kt$import org.wordpress.android.fluxc.model.WCSettingsModel.CurrencyPosition.* - WildcardImport:WooLogViewerScreen.kt$import androidx.compose.foundation.layout.* - WildcardImport:WooLogViewerScreen.kt$import androidx.compose.material.* From 7372f68d12f7f0cb95a823abd4da63fec35e7d84 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 4 Jul 2022 14:56:29 +0300 Subject: [PATCH 139/173] Analysis: Resolve (no) wildcard imports detekt warnings for product rev. Also, with this change the below such entries are removed from the Detekt related 'baseline.xml' file as they are no longer needed: - NoWildcardImports:com.woocommerce.android.ui.products.reviews. ProductReviewsFragment.kt:28 - WildcardImport:ProductReviewsFragment.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* --- .../android/ui/products/reviews/ProductReviewsFragment.kt | 4 +++- config/detekt/baseline.xml | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/reviews/ProductReviewsFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/reviews/ProductReviewsFragment.kt index 03954dc0c20..8985d46049f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/reviews/ProductReviewsFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/reviews/ProductReviewsFragment.kt @@ -24,7 +24,9 @@ import com.woocommerce.android.ui.reviews.ReviewModerationUi import com.woocommerce.android.ui.reviews.observeModerationStatus import com.woocommerce.android.ui.reviews.reviewList import com.woocommerce.android.util.ChromeCustomTabUtils -import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ExitWithResult +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowSnackbar import com.woocommerce.android.widgets.SkeletonView import com.woocommerce.android.widgets.WCEmptyView.EmptyViewType import dagger.hilt.android.AndroidEntryPoint diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index a6be72224b3..2eee79c2fb2 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -352,7 +352,6 @@ NoWildcardImports:com.woocommerce.android.ui.products.addons.AddonsExt.kt:4 NoWildcardImports:com.woocommerce.android.ui.products.downloads.AddProductDownloadBottomSheetFragment.kt:23 NoWildcardImports:com.woocommerce.android.ui.products.downloads.ProductDownloadDetailsViewModelTest.kt:6 - NoWildcardImports:com.woocommerce.android.ui.products.reviews.ProductReviewsFragment.kt:28 NoWildcardImports:com.woocommerce.android.ui.products.reviews.ProductReviewsViewModel.kt:19 NoWildcardImports:com.woocommerce.android.ui.products.variations.VariationDetailFragment.kt:20 NoWildcardImports:com.woocommerce.android.ui.products.variations.VariationDetailFragment.kt:37 @@ -589,7 +588,6 @@ WildcardImport:ProductListViewModel.kt$import com.woocommerce.android.ui.products.ProductListViewModel.ProductListEvent.* WildcardImport:ProductListViewModel.kt$import kotlinx.coroutines.* WildcardImport:ProductListViewModel.kt$import org.wordpress.android.fluxc.store.WCProductStore.ProductSorting.* - WildcardImport:ProductReviewsFragment.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:ProductReviewsViewModel.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:ProductSelectionListFragment.kt$import android.view.* WildcardImport:Refund.kt$import org.wordpress.android.fluxc.model.refunds.WCRefundModel.* From 5b0359faccbb92c5cb1c8074055ec8f99ad74a6d Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 4 Jul 2022 15:01:47 +0300 Subject: [PATCH 140/173] Analysis: Resolve (no) wildcard imports detekt warnings for lifecycle With this change all the 'import androidx.lifecycle.*' wildcard imports are being replaced with explicit non wildcard imports as per this project standards. Also, with this change the below such entries are removed from the Detekt related 'baseline.xml' file as they are no longer needed: - WildcardImport:LiveDataExt.kt$import androidx.lifecycle.* - WildcardImport:OrderListViewModel.kt$import androidx.lifecycle.* - WildcardImport:ProductDetailViewModel.kt$import androidx.lifecycle.* - WildcardImport:ScopedViewModel.kt$import androidx.lifecycle.* --- .../com/woocommerce/android/extensions/LiveDataExt.kt | 6 +++++- .../android/ui/orders/list/OrderListViewModel.kt | 8 +++++++- .../com/woocommerce/android/viewmodel/ScopedViewModel.kt | 6 +++++- config/detekt/baseline.xml | 4 ---- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/LiveDataExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/LiveDataExt.kt index f199ea694a2..dc9d521e69b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/LiveDataExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/LiveDataExt.kt @@ -1,6 +1,10 @@ package com.woocommerce.android.extensions -import androidx.lifecycle.* +import androidx.lifecycle.LiveData +import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.liveData +import androidx.lifecycle.switchMap fun MutableLiveData>.addNewItem(item: T) { val oldValue = this.value ?: mutableListOf() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt index 8010f7bf2c9..1f119b86437 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt @@ -5,7 +5,13 @@ package com.woocommerce.android.ui.orders.list import android.os.Parcelable import androidx.annotation.StringRes import androidx.annotation.VisibleForTesting -import androidx.lifecycle.* +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.LiveData +import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.SavedStateHandle import androidx.paging.PagedList import com.woocommerce.android.AppPrefsWrapper import com.woocommerce.android.R diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/ScopedViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/ScopedViewModel.kt index 518a323bd37..29c36baa765 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/ScopedViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/viewmodel/ScopedViewModel.kt @@ -1,6 +1,10 @@ package com.woocommerce.android.viewmodel -import androidx.lifecycle.* +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.woocommerce.android.viewmodel.MultiLiveEvent.Event import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 2eee79c2fb2..a125d616539 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -514,7 +514,6 @@ WildcardImport:JetpackInstallViewModel.kt$import com.woocommerce.android.ui.jetpack.JetpackInstallViewModel.FailureType.* WildcardImport:JetpackInstallViewModel.kt$import com.woocommerce.android.ui.jetpack.JetpackInstallViewModel.InstallStatus.* WildcardImport:JetpackInstallViewModel.kt$import com.woocommerce.android.ui.jetpack.PluginRepository.PluginStatus.* - WildcardImport:LiveDataExt.kt$import androidx.lifecycle.* WildcardImport:MagicLinkInterceptRepository.kt$import com.woocommerce.android.model.RequestResult.* WildcardImport:MagicLinkInterceptRepository.kt$import org.wordpress.android.fluxc.store.AccountStore.* WildcardImport:MainActivity.kt$import com.woocommerce.android.* @@ -554,7 +553,6 @@ WildcardImport:OrderListFragment.kt$import com.woocommerce.android.extensions.* WildcardImport:OrderListFragment.kt$import com.woocommerce.android.model.FeatureFeedbackSettings.* WildcardImport:OrderListFragment.kt$import com.woocommerce.android.model.FeatureFeedbackSettings.Feature.* - WildcardImport:OrderListViewModel.kt$import androidx.lifecycle.* WildcardImport:OrderStatusSelectorDialog.kt$import com.woocommerce.android.ui.orders.details.OrderDetailViewModel.* WildcardImport:PaymentErrorMapper.kt$import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CardPaymentStatusErrorType.DeclinedByBackendError.CardDeclined.* WildcardImport:PaymentManager.kt$import com.woocommerce.android.cardreader.payments.CardPaymentStatus.* @@ -569,7 +567,6 @@ WildcardImport:ProductDetailRepository.kt$import com.woocommerce.android.model.* WildcardImport:ProductDetailRepository.kt$import org.wordpress.android.fluxc.action.WCProductAction.* WildcardImport:ProductDetailRepository.kt$import org.wordpress.android.fluxc.store.WCProductStore.* - WildcardImport:ProductDetailViewModel.kt$import androidx.lifecycle.* WildcardImport:ProductDetailViewModel.kt$import com.woocommerce.android.analytics.AnalyticsEvent.* WildcardImport:ProductDetailViewModel.kt$import com.woocommerce.android.extensions.* WildcardImport:ProductDetailViewModel.kt$import com.woocommerce.android.media.MediaFilesRepository.UploadResult.* @@ -601,7 +598,6 @@ WildcardImport:ReviewModerationHandler.kt$import com.woocommerce.android.model.ActionStatus.* WildcardImport:ReviewModerationHandler.kt$import kotlinx.coroutines.* WildcardImport:ReviewModerationHandler.kt$import kotlinx.coroutines.flow.* - WildcardImport:ScopedViewModel.kt$import androidx.lifecycle.* WildcardImport:ShippingLabelAddressSuggestionFragment.kt$import com.woocommerce.android.extensions.* WildcardImport:ShippingLabelAddressSuggestionFragment.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:ShippingLabelRepository.kt$import com.woocommerce.android.model.* From f5f9e3def9cfa6c1bbe0be9c755a40dbcb1b2c6a Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 4 Jul 2022 15:03:38 +0300 Subject: [PATCH 141/173] Analysis: Resolve (no) wildcard imports detekt warnings for shipping lab Also, with this change the below such entries are removed from the Detekt related 'baseline.xml' file as they are no longer needed: - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels .creation.ShippingLabelAddressSuggestionFragment.kt:11 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels .creation.ShippingLabelAddressSuggestionFragment.kt:18 - WildcardImport:ShippingLabelAddressSuggestionFragment.kt$import com.woocommerce.android.extensions.* - WildcardImport:ShippingLabelAddressSuggestionFragment.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* --- .../creation/ShippingLabelAddressSuggestionFragment.kt | 10 ++++++++-- config/detekt/baseline.xml | 4 ---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelAddressSuggestionFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelAddressSuggestionFragment.kt index cb3d5e03fea..1940026ec9d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelAddressSuggestionFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/shippinglabels/creation/ShippingLabelAddressSuggestionFragment.kt @@ -7,14 +7,20 @@ import androidx.fragment.app.viewModels import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.databinding.FragmentShippingLabelAddressSuggestionBinding -import com.woocommerce.android.extensions.* +import com.woocommerce.android.extensions.appendWithIfNotEmpty +import com.woocommerce.android.extensions.navigateBackWithNotice +import com.woocommerce.android.extensions.navigateBackWithResult +import com.woocommerce.android.extensions.setHtmlText +import com.woocommerce.android.extensions.takeIfNotEqualTo import com.woocommerce.android.model.Address import com.woocommerce.android.ui.base.BaseFragment import com.woocommerce.android.ui.base.UIMessageResolver import com.woocommerce.android.ui.main.MainActivity.Companion.BackPressListener import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.EditSelectedAddress import com.woocommerce.android.ui.orders.shippinglabels.creation.CreateShippingLabelEvent.UseSelectedAddress -import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ExitWithResult +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowSnackbar import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index a125d616539..cd52735f8d3 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -279,8 +279,6 @@ NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.EditShippingLabelPaymentViewModelTest.kt:8 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.MoveShippingItemViewModel.kt:9 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingCustomsViewModelTest.kt:16 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressSuggestionFragment.kt:11 - NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelAddressSuggestionFragment.kt:18 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelCreateCustomPackageViewModelTest.kt:9 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelsStateMachine.kt:15 NoWildcardImports:com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelsStateMachine.kt:16 @@ -598,8 +596,6 @@ WildcardImport:ReviewModerationHandler.kt$import com.woocommerce.android.model.ActionStatus.* WildcardImport:ReviewModerationHandler.kt$import kotlinx.coroutines.* WildcardImport:ReviewModerationHandler.kt$import kotlinx.coroutines.flow.* - WildcardImport:ShippingLabelAddressSuggestionFragment.kt$import com.woocommerce.android.extensions.* - WildcardImport:ShippingLabelAddressSuggestionFragment.kt$import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.* WildcardImport:ShippingLabelRepository.kt$import com.woocommerce.android.model.* WildcardImport:ShippingLabelsStateMachine.kt$import com.woocommerce.android.model.* WildcardImport:ShippingLabelsStateMachine.kt$import com.woocommerce.android.ui.orders.shippinglabels.creation.ShippingLabelsStateMachine.Step.* From 4f6e26085b4513b8bd451895624a147fb39f39c7 Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 4 Jul 2022 15:05:18 +0300 Subject: [PATCH 142/173] Analysis: Resolve (no) wildcard imports detekt warnings for review det. Also, with this change the below such entries are removed from the Detekt related 'baseline.xml' file as they are no longer needed: - NoWildcardImports:com.woocommerce.android.ui.reviews .ReviewDetailFragment.kt:32 - NoWildcardImports:com.woocommerce.android.ui.reviews .ReviewDetailFragment.kt:41 - WildcardImport:ReviewDetailFragment.kt$import com.woocommerce.android.ui.reviews.ProductReviewStatus.* - WildcardImport:ReviewDetailFragment.kt$import org.wordpress.android.util.* --- .../android/ui/reviews/ReviewDetailFragment.kt | 11 +++++++++-- config/detekt/baseline.xml | 4 ---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt index ffc55b03882..0044ad0e9ca 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/reviews/ReviewDetailFragment.kt @@ -30,7 +30,10 @@ import com.woocommerce.android.tools.ProductImageMap import com.woocommerce.android.ui.base.BaseFragment import com.woocommerce.android.ui.base.UIMessageResolver import com.woocommerce.android.ui.main.MainActivity.Companion.BackPressListener -import com.woocommerce.android.ui.reviews.ProductReviewStatus.* +import com.woocommerce.android.ui.reviews.ProductReviewStatus.APPROVED +import com.woocommerce.android.ui.reviews.ProductReviewStatus.HOLD +import com.woocommerce.android.ui.reviews.ProductReviewStatus.SPAM +import com.woocommerce.android.ui.reviews.ProductReviewStatus.TRASH import com.woocommerce.android.ui.reviews.ReviewDetailViewModel.ReviewDetailEvent.NavigateBackFromNotification import com.woocommerce.android.util.ChromeCustomTabUtils import com.woocommerce.android.util.WooLog @@ -39,7 +42,11 @@ import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowSnackbar import com.woocommerce.android.widgets.SkeletonView import dagger.hilt.android.AndroidEntryPoint -import org.wordpress.android.util.* +import org.wordpress.android.util.DateTimeUtils +import org.wordpress.android.util.DisplayUtils +import org.wordpress.android.util.HtmlUtils +import org.wordpress.android.util.PhotonUtils +import org.wordpress.android.util.UrlUtils import javax.inject.Inject @AndroidEntryPoint diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index cd52735f8d3..332a805353b 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -356,8 +356,6 @@ NoWildcardImports:com.woocommerce.android.ui.products.variations.VariationDetailViewModel.kt:37 NoWildcardImports:com.woocommerce.android.ui.products.variations.VariationDetailViewModelTest.kt:24 NoWildcardImports:com.woocommerce.android.ui.products.variations.VariationListAdapter.kt:22 - NoWildcardImports:com.woocommerce.android.ui.reviews.ReviewDetailFragment.kt:32 - NoWildcardImports:com.woocommerce.android.ui.reviews.ReviewDetailFragment.kt:41 NoWildcardImports:com.woocommerce.android.ui.reviews.ReviewDetailRepository.kt:6 NoWildcardImports:com.woocommerce.android.ui.reviews.ReviewDetailViewModel.kt:9 NoWildcardImports:com.woocommerce.android.ui.reviews.ReviewDetailViewModelTest.kt:19 @@ -587,8 +585,6 @@ WildcardImport:ProductSelectionListFragment.kt$import android.view.* WildcardImport:Refund.kt$import org.wordpress.android.fluxc.model.refunds.WCRefundModel.* WildcardImport:ResourceProvider.kt$import androidx.annotation.* - WildcardImport:ReviewDetailFragment.kt$import com.woocommerce.android.ui.reviews.ProductReviewStatus.* - WildcardImport:ReviewDetailFragment.kt$import org.wordpress.android.util.* WildcardImport:ReviewDetailRepository.kt$import com.woocommerce.android.model.* WildcardImport:ReviewDetailViewModel.kt$import com.woocommerce.android.model.RequestResult.* WildcardImport:ReviewListRepository.kt$import com.woocommerce.android.model.RequestResult.* From c5f16804379c150e1f5098727439f85c5eb0eabb Mon Sep 17 00:00:00 2001 From: Petros Paraskevopoulos Date: Mon, 4 Jul 2022 15:06:24 +0300 Subject: [PATCH 143/173] Analysis: Resolve no unused imports detekt warnings for ui helpers --- .../src/main/kotlin/com/woocommerce/android/util/UiHelpers.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/UiHelpers.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/UiHelpers.kt index 9bb898b28ed..a76125676fd 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/UiHelpers.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/UiHelpers.kt @@ -1,17 +1,13 @@ package com.woocommerce.android.util -import android.app.Dialog import android.content.Context -import android.graphics.Point import android.graphics.drawable.Drawable import android.view.View -import android.view.WindowManager.LayoutParams import android.widget.ImageView import android.widget.TextView import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.core.text.HtmlCompat -import com.woocommerce.android.R import com.woocommerce.android.model.UiDimen import com.woocommerce.android.model.UiDimen.UiDimenDPInt import com.woocommerce.android.model.UiDimen.UiDimenRes From c74fa84da9c96dfb31e7d2925b45c68383d2b6e3 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Mon, 4 Jul 2022 10:56:33 -0300 Subject: [PATCH 144/173] Clean code and add logic to the buttons --- .../CardReaderOnboardingFragment.kt | 17 +++++++++++- .../CardReaderOnboardingViewModel.kt | 27 ++++++++++--------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt index a13a35f201e..8d69b422ab5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.cardreader.onboarding +import android.content.res.ColorStateList import android.os.Bundle import android.os.Parcelable import android.view.LayoutInflater @@ -118,7 +119,6 @@ class CardReaderOnboardingFragment : BaseFragment(R.layout.fragment_card_reader_ ) { val binding = FragmentCardReaderOnboardingSelectPaymentGatewayBinding.bind(view) UiHelpers.setTextOrHide(binding.textHeader, state.headerLabel) - UiHelpers.setTextOrHide(binding.hintLabel, state.hintLabel) UiHelpers.setImageOrHideInLandscape(binding.cardIllustration, state.cardIllustration) UiHelpers.setImageOrHideInLandscape(binding.icSelectWcPay, state.icWcPayLogo) UiHelpers.setImageOrHideInLandscape(binding.icCheckmarkWcPay, state.icCheckmarkWcPay) @@ -134,6 +134,21 @@ class CardReaderOnboardingFragment : BaseFragment(R.layout.fragment_card_reader_ binding.confirmPaymentMethod.setOnClickListener { state.onConfirmPaymentMethodClicked.invoke() } + + when(state.selectedPlugin) { + PluginType.WOOCOMMERCE_PAYMENTS -> { + binding.selectWcPayButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) + binding.icCheckmarkWcPay.visibility = View.VISIBLE + binding.icCheckmarkStripe.visibility = View.GONE + binding.selectStripeButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) + } + PluginType.STRIPE_EXTENSION_GATEWAY -> { + binding.selectStripeButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) + binding.icCheckmarkWcPay.visibility = View.GONE + binding.icCheckmarkStripe.visibility = View.VISIBLE + binding.selectWcPayButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) + } + } } private fun showBothPluginsInstalledState( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index f0896f0fcbb..692e19b32d1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -204,21 +204,14 @@ class CardReaderOnboardingViewModel @Inject constructor( }.exhaustive } - private fun updateUiWithSelectPaymentPlugin() { + private fun updateUiWithSelectPaymentPlugin(selectedPlugin: PluginType = WOOCOMMERCE_PAYMENTS) { launch { - val userInfo = userEligibilityFetcher.fetchUserInfo() - val canManagePlugins = userInfo?.getUserRoles()?.contains(ADMINISTRATOR) ?: false - viewState.value = OnboardingViewState.SelectPaymentPluginState( - hintLabel = if (canManagePlugins) { - UiString.UiStringRes(R.string.card_reader_onboarding_both_plugins_activated_hint_admin) - } else { - UiString.UiStringRes(R.string.card_reader_onboarding_both_plugins_activated_hint_store_owner) - }, - onWcPayOptionClicked = ::onContactSupportClicked, - onStripeOptionClicked = ::onLearnMoreClicked, - onConfirmPaymentMethodClicked = ::refreshState + selectedPlugin = selectedPlugin, + onWcPayOptionClicked = ::onWCPayOptionClicked, + onStripeOptionClicked = ::onStripeOptionClicked, + onConfirmPaymentMethodClicked = { (::refreshState)(selectedPlugin) } ) } } @@ -248,6 +241,14 @@ class CardReaderOnboardingViewModel @Inject constructor( } } + private fun onWCPayOptionClicked() { + updateUiWithSelectPaymentPlugin(WOOCOMMERCE_PAYMENTS) + } + + private fun onStripeOptionClicked() { + updateUiWithSelectPaymentPlugin(STRIPE_EXTENSION_GATEWAY) + } + private fun onWPAdminActionClicked() { val url = selectedSite.get().url + AppUrls.PLUGIN_MANAGEMENT_SUFFIX if (selectedSite.get().isWPCom || selectedSite.get().isWPComAtomic) { @@ -333,7 +334,7 @@ class CardReaderOnboardingViewModel @Inject constructor( } data class SelectPaymentPluginState( - val hintLabel: UiString, + val selectedPlugin: PluginType, val onWcPayOptionClicked: (() -> Unit), val onStripeOptionClicked: (() -> Unit), val onConfirmPaymentMethodClicked: (() -> Unit), From f01942b789c920d64e34b8377a7d55c023008fda Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Mon, 4 Jul 2022 10:58:35 -0300 Subject: [PATCH 145/173] Format code --- .../onboarding/CardReaderOnboardingFragment.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt index 8d69b422ab5..7a3dba90cc2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt @@ -109,7 +109,7 @@ class CardReaderOnboardingFragment : BaseFragment(R.layout.fragment_card_reader_ is CardReaderOnboardingViewModel.OnboardingViewState.WcPayAndStripeInstalledState -> showBothPluginsInstalledState(layout, state) is CardReaderOnboardingViewModel.OnboardingViewState.SelectPaymentPluginState -> - showPaymentPluginSelectionState(layout,state) + showPaymentPluginSelectionState(layout, state) }.exhaustive } @@ -135,15 +135,17 @@ class CardReaderOnboardingFragment : BaseFragment(R.layout.fragment_card_reader_ state.onConfirmPaymentMethodClicked.invoke() } - when(state.selectedPlugin) { + when (state.selectedPlugin) { PluginType.WOOCOMMERCE_PAYMENTS -> { - binding.selectWcPayButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) + binding.selectWcPayButton.strokeColor = + ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) binding.icCheckmarkWcPay.visibility = View.VISIBLE binding.icCheckmarkStripe.visibility = View.GONE binding.selectStripeButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) } PluginType.STRIPE_EXTENSION_GATEWAY -> { - binding.selectStripeButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) + binding.selectStripeButton.strokeColor = + ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) binding.icCheckmarkWcPay.visibility = View.GONE binding.icCheckmarkStripe.visibility = View.VISIBLE binding.selectWcPayButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) From 03194c5175236fa27579191fff1949a01a9138b9 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Mon, 4 Jul 2022 11:10:36 -0300 Subject: [PATCH 146/173] Format code --- .../ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index 692e19b32d1..3d02368353c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -216,7 +216,6 @@ class CardReaderOnboardingViewModel @Inject constructor( } } - private fun updateUiWithWcPayAndStripeActivated() { launch { val userInfo = userEligibilityFetcher.fetchUserInfo() @@ -351,7 +350,6 @@ class CardReaderOnboardingViewModel @Inject constructor( val icCheckmarkStripe = R.drawable.ic_menu_action_mode_check val confirmPaymentMethodButtonLabel = UiString .UiStringRes(R.string.card_reader_onboarding_confirm_payment_method_button) - } data class WcPayAndStripeInstalledState( From 6199b4268fc032b8aa03d9667cfe093da6ef82c1 Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 4 Jul 2022 16:22:47 +0200 Subject: [PATCH 147/173] Add layouts and strings for the warning section --- .../layout/fragment_order_creation_form.xml | 4 +++ .../res/layout/multiple_lines_warning.xml | 34 +++++++++++++++++++ WooCommerce/src/main/res/values/strings.xml | 3 ++ 3 files changed, 41 insertions(+) create mode 100644 WooCommerce/src/main/res/layout/multiple_lines_warning.xml diff --git a/WooCommerce/src/main/res/layout/fragment_order_creation_form.xml b/WooCommerce/src/main/res/layout/fragment_order_creation_form.xml index 5431ba11041..b745ebc2411 100644 --- a/WooCommerce/src/main/res/layout/fragment_order_creation_form.xml +++ b/WooCommerce/src/main/res/layout/fragment_order_creation_form.xml @@ -33,6 +33,10 @@ app:header="@string/products" app:keepAddButtons="true" /> + + diff --git a/WooCommerce/src/main/res/layout/multiple_lines_warning.xml b/WooCommerce/src/main/res/layout/multiple_lines_warning.xml new file mode 100644 index 00000000000..6d0318a2efb --- /dev/null +++ b/WooCommerce/src/main/res/layout/multiple_lines_warning.xml @@ -0,0 +1,34 @@ + + + + + + + + + + diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index 3355727c0b1..21b801904bc 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -2500,4 +2500,7 @@ Install extension Things to know before installing Proceed With Installation + %1$s are incomplete + To edit all %1$s browse the order in your WooCommerce store admin. + the details From 1593cc25457083aea2f9bb704dc3241abc663f1e Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 4 Jul 2022 16:24:41 +0200 Subject: [PATCH 148/173] Remove multiShippingLinesAvailable --- .../main/kotlin/com/woocommerce/android/model/Order.kt | 8 ++++++-- .../kotlin/com/woocommerce/android/model/OrderMapper.kt | 1 - .../android/ui/orders/details/OrderDetailFragment.kt | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Order.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Order.kt index 16b3ff68a32..e3fad48ba20 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Order.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Order.kt @@ -36,7 +36,6 @@ data class Order( val paymentMethodTitle: String, val isCashPayment: Boolean, val pricesIncludeTax: Boolean, - val multiShippingLinesAvailable: Boolean, val billingAddress: Address, val shippingAddress: Address, val shippingMethods: List, @@ -59,6 +58,12 @@ data class Order( @IgnoredOnParcel val isRefundAvailable = refundTotal < total && availableRefundQuantity > 0 + val hasMultipleShippingLines: Boolean + get() = shippingLines.size > 1 + + val hasMultipleFeeLines: Boolean + get() = feesLines.size > 1 + @Parcelize data class ShippingMethod( val id: String, @@ -314,7 +319,6 @@ data class Order( paymentMethodTitle = "", isCashPayment = false, pricesIncludeTax = false, - multiShippingLinesAvailable = false, billingAddress = Address.EMPTY, shippingAddress = Address.EMPTY, shippingMethods = emptyList(), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt index a20c76ef4c9..c00a2c77e3c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt @@ -45,7 +45,6 @@ class OrderMapper @Inject constructor(private val getLocations: GetLocations) { paymentMethodTitle = databaseEntity.paymentMethodTitle, isCashPayment = CASH_PAYMENTS.contains(databaseEntity.paymentMethod), pricesIncludeTax = databaseEntity.pricesIncludeTax, - multiShippingLinesAvailable = databaseEntity.isMultiShippingLinesAvailable(), billingAddress = databaseEntity.getBillingAddress().mapAddress(), shippingAddress = databaseEntity.getShippingAddress().mapAddress(), shippingMethods = databaseEntity.getShippingLineList().mapShippingMethods(), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailFragment.kt index 189b3bd25dd..330b87e6bc7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/OrderDetailFragment.kt @@ -338,7 +338,7 @@ class OrderDetailFragment : BaseFragment(R.layout.fragment_order_detail), OrderP isReceiptButtonsVisible: Boolean ) { binding.orderDetailOrderStatus.updateOrder(order) - binding.orderDetailShippingMethodNotice.isVisible = order.multiShippingLinesAvailable + binding.orderDetailShippingMethodNotice.isVisible = order.hasMultipleShippingLines binding.orderDetailCustomerInfo.updateCustomerInfo( order = order, isVirtualOrder = viewModel.hasVirtualProductsOnly(), From 5174edc26df5764eb9082ee6efcbdb5847779219 Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 4 Jul 2022 16:25:36 +0200 Subject: [PATCH 149/173] Determine multiple lines context --- .../creation/DetermineMultipleLinesContext.kt | 50 +++++++++++++++++++ .../orders/creation/OrderCreationViewModel.kt | 18 ++++++- .../creation/UnifiedOrderEditViewModelTest.kt | 7 ++- 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/DetermineMultipleLinesContext.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/DetermineMultipleLinesContext.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/DetermineMultipleLinesContext.kt new file mode 100644 index 00000000000..b927c8991b2 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/DetermineMultipleLinesContext.kt @@ -0,0 +1,50 @@ +package com.woocommerce.android.ui.orders.creation + +import com.woocommerce.android.R +import com.woocommerce.android.model.Order +import com.woocommerce.android.ui.orders.creation.OrderCreationViewModel.MultipleLinesContext +import com.woocommerce.android.viewmodel.ResourceProvider +import java.util.Locale +import javax.inject.Inject + +class DetermineMultipleLinesContext @Inject constructor(private val resourceProvider: ResourceProvider) { + operator fun invoke(order: Order) = + when { + order.hasMultipleShippingLines && order.hasMultipleFeeLines -> MultipleLinesContext.Warning( + header = resourceProvider.getString( + R.string.lines_incomplete, + String.format( + Locale.getDefault(), + "%s & %s", + resourceProvider.getString(R.string.order_creation_payment_fee), + resourceProvider.getString(R.string.orderdetail_shipping_details), + ) + ), + explanation = resourceProvider.getString( + R.string.lines_incomplete_explanation, + resourceProvider.getString(R.string.lines_all_details) + ), + ) + order.hasMultipleFeeLines -> MultipleLinesContext.Warning( + header = resourceProvider.getString( + R.string.lines_incomplete, + resourceProvider.getString(R.string.order_creation_payment_fee) + ), + explanation = resourceProvider.getString( + R.string.lines_incomplete_explanation, + resourceProvider.getString(R.string.order_creation_payment_fee).lowercase() + ) + ) + order.hasMultipleShippingLines -> MultipleLinesContext.Warning( + header = resourceProvider.getString( + R.string.lines_incomplete, + resourceProvider.getString(R.string.orderdetail_shipping_details) + ), + explanation = resourceProvider.getString( + R.string.lines_incomplete_explanation, + resourceProvider.getString(R.string.orderdetail_shipping_details).lowercase(), + ), + ) + else -> MultipleLinesContext.None + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt index 3599c41f113..51f3ce19241 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationViewModel.kt @@ -70,6 +70,7 @@ class OrderCreationViewModel @Inject constructor( private val mapItemToProductUiModel: MapItemToProductUiModel, private val createOrUpdateOrderDraft: CreateOrUpdateOrderDraft, private val createOrderItem: CreateOrderItem, + private val determineMultipleLinesContext: DetermineMultipleLinesContext, parameterRepository: ParameterRepository ) : ScopedViewModel(savedState) { companion object { @@ -306,7 +307,8 @@ class OrderCreationViewModel @Inject constructor( viewState = viewState.copy( isUpdatingOrderDraft = false, showOrderUpdateSnackbar = false, - isEditable = updateStatus.order.isEditable || mode is Mode.Creation + isEditable = updateStatus.order.isEditable || mode is Mode.Creation, + multipleLinesContext = determineMultipleLinesContext(updateStatus.order) ) _orderDraft.update { currentDraft -> // Keep the user's selected status @@ -394,7 +396,8 @@ class OrderCreationViewModel @Inject constructor( val willUpdateOrderDraft: Boolean = false, val isUpdatingOrderDraft: Boolean = false, val showOrderUpdateSnackbar: Boolean = false, - val isEditable: Boolean = true + val isEditable: Boolean = true, + val multipleLinesContext: MultipleLinesContext = MultipleLinesContext.None ) : Parcelable { @IgnoredOnParcel val canCreateOrder: Boolean = !willUpdateOrderDraft && !isUpdatingOrderDraft && !showOrderUpdateSnackbar @@ -410,6 +413,17 @@ class OrderCreationViewModel @Inject constructor( @Parcelize data class Edit(val orderId: Long) : Mode() } + + sealed class MultipleLinesContext : Parcelable { + @Parcelize + object None : MultipleLinesContext() + + @Parcelize + data class Warning( + val header: String, + val explanation: String, + ) : MultipleLinesContext() + } } data class ProductUIModel( diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt index a81400524b0..e688e44fdf7 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/UnifiedOrderEditViewModelTest.kt @@ -29,6 +29,7 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { protected lateinit var orderCreationRepository: OrderCreationRepository protected lateinit var orderDetailRepository: OrderDetailRepository protected lateinit var parameterRepository: ParameterRepository + private lateinit var determineMultipleLinesContext: DetermineMultipleLinesContext protected val defaultOrderValue = Order.EMPTY.copy(id = 123) @@ -80,6 +81,9 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { stockStatus = ProductStockStatus.InStock ) } + determineMultipleLinesContext = mock { + on { invoke(any()) } doReturn OrderCreationViewModel.MultipleLinesContext.None + } } protected fun createSut() { @@ -91,7 +95,8 @@ abstract class UnifiedOrderEditViewModelTest : BaseUnitTest() { mapItemToProductUiModel = mapItemToProductUIModel, createOrUpdateOrderDraft = createOrUpdateOrderUseCase, createOrderItem = createOrderItemUseCase, - parameterRepository = parameterRepository + parameterRepository = parameterRepository, + determineMultipleLinesContext = determineMultipleLinesContext, ) } From 8b454aaace30c8a2e798ee90316031e3244e9590 Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Mon, 4 Jul 2022 16:26:16 +0200 Subject: [PATCH 150/173] Show/hide multiple lines warnings --- .../creation/OrderCreationFormFragment.kt | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt index 59448a8f38e..5917218301e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/OrderCreationFormFragment.kt @@ -28,6 +28,9 @@ import com.woocommerce.android.ui.base.UIMessageResolver import com.woocommerce.android.ui.main.AppBarStatus import com.woocommerce.android.ui.main.MainActivity.Companion.BackPressListener import com.woocommerce.android.ui.orders.OrderNavigationTarget.ViewOrderStatusSelector +import com.woocommerce.android.ui.orders.creation.OrderCreationViewModel.Mode +import com.woocommerce.android.ui.orders.creation.OrderCreationViewModel.MultipleLinesContext.None +import com.woocommerce.android.ui.orders.creation.OrderCreationViewModel.MultipleLinesContext.Warning import com.woocommerce.android.ui.orders.creation.navigation.OrderCreationNavigationTarget import com.woocommerce.android.ui.orders.creation.navigation.OrderCreationNavigator import com.woocommerce.android.ui.orders.creation.views.OrderCreationSectionView @@ -66,8 +69,8 @@ class OrderCreationFormFragment : BaseFragment(R.layout.fragment_order_creation_ override val activityAppBarStatus: AppBarStatus get() = AppBarStatus.Visible( navigationIcon = when (viewModel.mode) { - OrderCreationViewModel.Mode.Creation -> R.drawable.ic_back_24dp - is OrderCreationViewModel.Mode.Edit -> null + Mode.Creation -> R.drawable.ic_back_24dp + is Mode.Edit -> null } ) @@ -92,8 +95,8 @@ class OrderCreationFormFragment : BaseFragment(R.layout.fragment_order_creation_ createOrderMenuItem = menu.findItem(R.id.menu_create).apply { title = resources.getString( when (viewModel.mode) { - OrderCreationViewModel.Mode.Creation -> R.string.create - is OrderCreationViewModel.Mode.Edit -> R.string.done + Mode.Creation -> R.string.create + is Mode.Edit -> R.string.done } ) isEnabled = viewModel.viewStateData.liveData.value?.canCreateOrder ?: false @@ -245,6 +248,16 @@ class OrderCreationFormFragment : BaseFragment(R.layout.fragment_order_creation_ new.isEditable.takeIfNotEqualTo(old?.isEditable) { isEditable -> if (isEditable) showEditableControls(binding) else hideEditableControls(binding) } + new.multipleLinesContext.takeIfNotEqualTo(old?.multipleLinesContext) { multipleLinesContext -> + when (multipleLinesContext) { + None -> binding.multipleLinesWarningSection.root.visibility = View.GONE + is Warning -> { + binding.multipleLinesWarningSection.header.text = multipleLinesContext.header + binding.multipleLinesWarningSection.explanation.text = multipleLinesContext.explanation + binding.multipleLinesWarningSection.root.visibility = View.VISIBLE + } + } + } } viewModel.event.observe(viewLifecycleOwner, ::handleViewModelEvents) @@ -427,9 +440,9 @@ class OrderCreationFormFragment : BaseFragment(R.layout.fragment_order_creation_ } override fun getFragmentTitle() = when (viewModel.mode) { - OrderCreationViewModel.Mode.Creation -> getString(R.string.order_creation_fragment_title) - is OrderCreationViewModel.Mode.Edit -> { - val orderId = (viewModel.mode as OrderCreationViewModel.Mode.Edit).orderId.toString() + Mode.Creation -> getString(R.string.order_creation_fragment_title) + is Mode.Edit -> { + val orderId = (viewModel.mode as Mode.Edit).orderId.toString() getString(R.string.orderdetail_orderstatus_ordernum, orderId) } } From d5b06efb33f957511ddf6a8c036280352f4abc32 Mon Sep 17 00:00:00 2001 From: Hafiz Rahman Date: Tue, 5 Jul 2022 14:29:09 +0700 Subject: [PATCH 151/173] Add: Default text color in WCSearchField to make it readable in light & dark mode. --- .../com/woocommerce/android/ui/compose/component/TextFields.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/compose/component/TextFields.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/compose/component/TextFields.kt index 5900a1fa572..5d5c57af22e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/compose/component/TextFields.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/compose/component/TextFields.kt @@ -34,6 +34,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.tooling.preview.Preview @@ -186,6 +187,7 @@ fun WCSearchField( BasicTextField( value = value, onValueChange = onValueChange, + textStyle = TextStyle(color = colorResource(id = R.color.color_on_surface_medium)), modifier = modifier .defaultMinSize(minHeight = dimensionResource(id = R.dimen.major_250)) .background( From b10d1c0f8de5231811ea7d2db8689245a2df7cd0 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Tue, 5 Jul 2022 13:22:14 +0530 Subject: [PATCH 152/173] refactor branch 6623 --- .../CardReaderOnboardingFragment.kt | 40 +++++++++---------- .../CardReaderOnboardingViewModel.kt | 20 ++-------- 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt index 7a3dba90cc2..31368fa5420 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt @@ -117,39 +117,35 @@ class CardReaderOnboardingFragment : BaseFragment(R.layout.fragment_card_reader_ view: View, state: CardReaderOnboardingViewModel.OnboardingViewState.SelectPaymentPluginState ) { + var selectedPluginType: PluginType = PluginType.WOOCOMMERCE_PAYMENTS val binding = FragmentCardReaderOnboardingSelectPaymentGatewayBinding.bind(view) UiHelpers.setTextOrHide(binding.textHeader, state.headerLabel) + UiHelpers.setTextOrHide(binding.hintLabel, state.choosePluginHintLabel) + UiHelpers.setTextOrHide(binding.selectWcPayButton, state.selectWcPayButtonLabel) + UiHelpers.setTextOrHide(binding.selectStripeButton, state.selectStripeButtonLabel) + UiHelpers.setTextOrHide(binding.confirmPaymentMethod, state.confirmPaymentMethodButtonLabel) UiHelpers.setImageOrHideInLandscape(binding.cardIllustration, state.cardIllustration) UiHelpers.setImageOrHideInLandscape(binding.icSelectWcPay, state.icWcPayLogo) UiHelpers.setImageOrHideInLandscape(binding.icCheckmarkWcPay, state.icCheckmarkWcPay) - UiHelpers.setImageOrHideInLandscape(binding.icSelectStripe, state.icStripeLogo) - UiHelpers.setImageOrHideInLandscape(binding.icCheckmarkStripe, state.icCheckmarkStripe) binding.selectWcPayButton.setOnClickListener { - state.onWcPayOptionClicked.invoke() + selectedPluginType = PluginType.WOOCOMMERCE_PAYMENTS + binding.selectWcPayButton.strokeColor = + ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) + binding.icCheckmarkWcPay.visibility = View.VISIBLE + binding.icCheckmarkStripe.visibility = View.GONE + binding.selectStripeButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) } binding.selectStripeButton.setOnClickListener { - state.onStripeOptionClicked.invoke() + selectedPluginType = PluginType.STRIPE_EXTENSION_GATEWAY + binding.selectStripeButton.strokeColor = + ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) + binding.icCheckmarkWcPay.visibility = View.GONE + binding.icCheckmarkStripe.visibility = View.VISIBLE + binding.selectWcPayButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) } binding.confirmPaymentMethod.setOnClickListener { - state.onConfirmPaymentMethodClicked.invoke() - } - - when (state.selectedPlugin) { - PluginType.WOOCOMMERCE_PAYMENTS -> { - binding.selectWcPayButton.strokeColor = - ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) - binding.icCheckmarkWcPay.visibility = View.VISIBLE - binding.icCheckmarkStripe.visibility = View.GONE - binding.selectStripeButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) - } - PluginType.STRIPE_EXTENSION_GATEWAY -> { - binding.selectStripeButton.strokeColor = - ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) - binding.icCheckmarkWcPay.visibility = View.GONE - binding.icCheckmarkStripe.visibility = View.VISIBLE - binding.selectWcPayButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) - } + state.onConfirmPaymentMethodClicked.invoke(selectedPluginType) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index 3d02368353c..0e6124cd07c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -204,14 +204,11 @@ class CardReaderOnboardingViewModel @Inject constructor( }.exhaustive } - private fun updateUiWithSelectPaymentPlugin(selectedPlugin: PluginType = WOOCOMMERCE_PAYMENTS) { + private fun updateUiWithSelectPaymentPlugin() { launch { viewState.value = OnboardingViewState.SelectPaymentPluginState( - selectedPlugin = selectedPlugin, - onWcPayOptionClicked = ::onWCPayOptionClicked, - onStripeOptionClicked = ::onStripeOptionClicked, - onConfirmPaymentMethodClicked = { (::refreshState)(selectedPlugin) } + onConfirmPaymentMethodClicked = { (::refreshState)(it) } ) } } @@ -240,14 +237,6 @@ class CardReaderOnboardingViewModel @Inject constructor( } } - private fun onWCPayOptionClicked() { - updateUiWithSelectPaymentPlugin(WOOCOMMERCE_PAYMENTS) - } - - private fun onStripeOptionClicked() { - updateUiWithSelectPaymentPlugin(STRIPE_EXTENSION_GATEWAY) - } - private fun onWPAdminActionClicked() { val url = selectedSite.get().url + AppUrls.PLUGIN_MANAGEMENT_SUFFIX if (selectedSite.get().isWPCom || selectedSite.get().isWPComAtomic) { @@ -333,10 +322,7 @@ class CardReaderOnboardingViewModel @Inject constructor( } data class SelectPaymentPluginState( - val selectedPlugin: PluginType, - val onWcPayOptionClicked: (() -> Unit), - val onStripeOptionClicked: (() -> Unit), - val onConfirmPaymentMethodClicked: (() -> Unit), + val onConfirmPaymentMethodClicked: ((PluginType) -> Unit), ) : OnboardingViewState(R.layout.fragment_card_reader_onboarding_select_payment_gateway) { val cardIllustration = R.drawable.ic_credit_card_give val headerLabel = UiString.UiStringRes(R.string.card_reader_onboarding_choose_payment_provider) From 203808b3e9cbe2308363176787f7b8dabda6ad7d Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Tue, 5 Jul 2022 13:45:36 +0530 Subject: [PATCH 153/173] Add new event key in AnalyticsEvent.kt for tracking when merchant selects their preferred gateway --- .../kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt index eec15138f9b..63d1312b00b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt @@ -257,6 +257,7 @@ enum class AnalyticsEvent(val siteless: Boolean = false) { // -- Card Present Payments - onboarding CARD_PRESENT_ONBOARDING_LEARN_MORE_TAPPED, CARD_PRESENT_ONBOARDING_NOT_COMPLETED, + CARD_PRESENT_PAYMENT_GATEWAY_SELECTED, // -- Card Present Payments - collection CARD_PRESENT_COLLECT_PAYMENT_TAPPED, From fa00b2af318fd99145745cebb9650cf735a76b36 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Tue, 5 Jul 2022 13:46:32 +0530 Subject: [PATCH 154/173] Add new property key in AnalyticsTracker.kt for tracking when merchant selects their preferred gateway --- .../kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt index c6ecf633987..8d987970798 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsTracker.kt @@ -296,6 +296,7 @@ class AnalyticsTracker private constructor(private val context: Context) { const val KEY_AMOUNT = "amount" const val KEY_PAYMENT_METHOD = "payment_method" + const val KEY_PAYMENT_GATEWAY = "payment_gateway" const val KEY_IS_JETPACK_CP_CONNECTED = "is_jetpack_cp_conntected" const val KEY_ACTIVE_JETPACK_CONNECTION_PLUGINS = "active_jetpack_connection_plugins" From 7c34b7e2ecce54ab1554fbf4c092a2d7049d5254 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Tue, 5 Jul 2022 13:47:08 +0530 Subject: [PATCH 155/173] Add logic to track event when merchant selects their preferred gateway --- .../android/ui/cardreader/CardReaderTracker.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt index 5678910719f..4c2b6a21897 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt @@ -33,6 +33,7 @@ import com.woocommerce.android.analytics.AnalyticsEvent.RECEIPT_PRINT_FAILED import com.woocommerce.android.analytics.AnalyticsEvent.RECEIPT_PRINT_SUCCESS import com.woocommerce.android.analytics.AnalyticsEvent.RECEIPT_PRINT_TAPPED import com.woocommerce.android.analytics.AnalyticsTracker +import com.woocommerce.android.analytics.AnalyticsTracker.Companion.KEY_PAYMENT_GATEWAY import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.cardreader.connection.event.SoftwareUpdateStatus.Failed import com.woocommerce.android.cardreader.payments.CardInteracRefundStatus.RefundStatusErrorType @@ -161,6 +162,18 @@ class CardReaderTracker @Inject constructor( } } + fun trackPaymentGatewaySelected(pluginType: PluginType) { + val preferredPlugin = when (pluginType) { + WOOCOMMERCE_PAYMENTS -> "woocommerce-payments" + STRIPE_EXTENSION_GATEWAY -> "woocommerce-stripe-gateway" + null -> "unknown" + } + track( + AnalyticsEvent.CARD_PRESENT_PAYMENT_GATEWAY_SELECTED, + mutableMapOf(KEY_PAYMENT_GATEWAY to preferredPlugin) + ) + } + fun trackSoftwareUpdateStarted(requiredUpdate: Boolean) { trackSoftwareUpdateEvent(CARD_READER_SOFTWARE_UPDATE_STARTED, requiredUpdate) } From 4d7ad65d0bb2d11bac37aca79172909a14337093 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Tue, 5 Jul 2022 13:52:07 +0530 Subject: [PATCH 156/173] Integrate view model with the card reader tracker. --- .../CardReaderOnboardingViewModel.kt | 5 +++- .../CardReaderOnboardingViewModelTest.kt | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index 0e6124cd07c..55b18969d9a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -208,7 +208,10 @@ class CardReaderOnboardingViewModel @Inject constructor( launch { viewState.value = OnboardingViewState.SelectPaymentPluginState( - onConfirmPaymentMethodClicked = { (::refreshState)(it) } + onConfirmPaymentMethodClicked = { pluginType -> + cardReaderTracker.trackPaymentGatewaySelected(pluginType) + (::refreshState)(pluginType) + } ) } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt index 73ca22057bb..c01c87fecd2 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt @@ -1071,6 +1071,32 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { } // Tracking Begin + @Test + fun `given multiple gateway, when user selects wcpay, then track selected gateway`() = + testBlocking { + whenever(onboardingChecker.getOnboardingState()) + .thenReturn(CardReaderOnboardingState.ChoosePaymentGatewayProvider) + + val viewModel = createVM() + (viewModel.viewStateData.value as OnboardingViewState.SelectPaymentPluginState) + .onConfirmPaymentMethodClicked.invoke(WOOCOMMERCE_PAYMENTS) + + verify(tracker).trackPaymentGatewaySelected(WOOCOMMERCE_PAYMENTS) + } + + @Test + fun `given multiple gateway, when user selects stripe extension, then track selected gateway`() = + testBlocking { + whenever(onboardingChecker.getOnboardingState()) + .thenReturn(CardReaderOnboardingState.ChoosePaymentGatewayProvider) + + val viewModel = createVM() + (viewModel.viewStateData.value as OnboardingViewState.SelectPaymentPluginState) + .onConfirmPaymentMethodClicked.invoke(STRIPE_EXTENSION_GATEWAY) + + verify(tracker).trackPaymentGatewaySelected(STRIPE_EXTENSION_GATEWAY) + } + @Test fun `when learn more tapped, then event tracked`() = testBlocking { From 3b55e6ce010adfb0cd5fcbae05d088691ae3cf85 Mon Sep 17 00:00:00 2001 From: Anirudh Uppunda Date: Tue, 5 Jul 2022 14:00:53 +0530 Subject: [PATCH 157/173] Add tests for CardReaderTracker.kt to verify proper events with parameter are being invoked when merchant selects the plugin --- .../ui/cardreader/CardReaderTracker.kt | 1 - .../ui/cardreader/CardReaderTrackerTest.kt | 23 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt index 4c2b6a21897..07c003cfb3f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTracker.kt @@ -166,7 +166,6 @@ class CardReaderTracker @Inject constructor( val preferredPlugin = when (pluginType) { WOOCOMMERCE_PAYMENTS -> "woocommerce-payments" STRIPE_EXTENSION_GATEWAY -> "woocommerce-stripe-gateway" - null -> "unknown" } track( AnalyticsEvent.CARD_PRESENT_PAYMENT_GATEWAY_SELECTED, diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTrackerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTrackerTest.kt index 4cc0da9f5ab..e56ccaed723 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTrackerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/CardReaderTrackerTest.kt @@ -1,6 +1,7 @@ package com.woocommerce.android.ui.cardreader import com.woocommerce.android.AppPrefsWrapper +import com.woocommerce.android.analytics.AnalyticsEvent import com.woocommerce.android.analytics.AnalyticsEvent.CARD_PRESENT_COLLECT_PAYMENT_CANCELLED import com.woocommerce.android.analytics.AnalyticsEvent.CARD_PRESENT_COLLECT_PAYMENT_FAILED import com.woocommerce.android.analytics.AnalyticsEvent.CARD_PRESENT_COLLECT_PAYMENT_SUCCESS @@ -91,6 +92,28 @@ class CardReaderTrackerTest : BaseUnitTest() { ) } + @Test + fun `when track payment gateway invoked with wcpay, then track event with proper gateway`() = + testBlocking { + cardReaderTracker.trackPaymentGatewaySelected(WOOCOMMERCE_PAYMENTS) + + verify(trackerWrapper).track( + eq(AnalyticsEvent.CARD_PRESENT_PAYMENT_GATEWAY_SELECTED), + check { assertThat(it[AnalyticsTracker.KEY_PAYMENT_GATEWAY]).isEqualTo("woocommerce-payments") } + ) + } + + @Test + fun `when track payment gateway invoked with stripe, then track event with proper gateway`() = + testBlocking { + cardReaderTracker.trackPaymentGatewaySelected(STRIPE_EXTENSION_GATEWAY) + + verify(trackerWrapper).track( + eq(AnalyticsEvent.CARD_PRESENT_PAYMENT_GATEWAY_SELECTED), + check { assertThat(it[AnalyticsTracker.KEY_PAYMENT_GATEWAY]).isEqualTo("woocommerce-stripe-gateway") } + ) + } + @Test fun `when onboarding state GenericError, then reason=generic_error tracked`() = testBlocking { From 025b25002db6cba61b8514fed38f77fdc7eba189 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 5 Jul 2022 06:38:55 -0300 Subject: [PATCH 158/173] Fix blinking screen --- .../CardReaderOnboardingFragment.kt | 40 +++++++++---------- .../CardReaderOnboardingViewModel.kt | 20 ++-------- 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt index 7a3dba90cc2..31368fa5420 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingFragment.kt @@ -117,39 +117,35 @@ class CardReaderOnboardingFragment : BaseFragment(R.layout.fragment_card_reader_ view: View, state: CardReaderOnboardingViewModel.OnboardingViewState.SelectPaymentPluginState ) { + var selectedPluginType: PluginType = PluginType.WOOCOMMERCE_PAYMENTS val binding = FragmentCardReaderOnboardingSelectPaymentGatewayBinding.bind(view) UiHelpers.setTextOrHide(binding.textHeader, state.headerLabel) + UiHelpers.setTextOrHide(binding.hintLabel, state.choosePluginHintLabel) + UiHelpers.setTextOrHide(binding.selectWcPayButton, state.selectWcPayButtonLabel) + UiHelpers.setTextOrHide(binding.selectStripeButton, state.selectStripeButtonLabel) + UiHelpers.setTextOrHide(binding.confirmPaymentMethod, state.confirmPaymentMethodButtonLabel) UiHelpers.setImageOrHideInLandscape(binding.cardIllustration, state.cardIllustration) UiHelpers.setImageOrHideInLandscape(binding.icSelectWcPay, state.icWcPayLogo) UiHelpers.setImageOrHideInLandscape(binding.icCheckmarkWcPay, state.icCheckmarkWcPay) - UiHelpers.setImageOrHideInLandscape(binding.icSelectStripe, state.icStripeLogo) - UiHelpers.setImageOrHideInLandscape(binding.icCheckmarkStripe, state.icCheckmarkStripe) binding.selectWcPayButton.setOnClickListener { - state.onWcPayOptionClicked.invoke() + selectedPluginType = PluginType.WOOCOMMERCE_PAYMENTS + binding.selectWcPayButton.strokeColor = + ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) + binding.icCheckmarkWcPay.visibility = View.VISIBLE + binding.icCheckmarkStripe.visibility = View.GONE + binding.selectStripeButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) } binding.selectStripeButton.setOnClickListener { - state.onStripeOptionClicked.invoke() + selectedPluginType = PluginType.STRIPE_EXTENSION_GATEWAY + binding.selectStripeButton.strokeColor = + ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) + binding.icCheckmarkWcPay.visibility = View.GONE + binding.icCheckmarkStripe.visibility = View.VISIBLE + binding.selectWcPayButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) } binding.confirmPaymentMethod.setOnClickListener { - state.onConfirmPaymentMethodClicked.invoke() - } - - when (state.selectedPlugin) { - PluginType.WOOCOMMERCE_PAYMENTS -> { - binding.selectWcPayButton.strokeColor = - ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) - binding.icCheckmarkWcPay.visibility = View.VISIBLE - binding.icCheckmarkStripe.visibility = View.GONE - binding.selectStripeButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) - } - PluginType.STRIPE_EXTENSION_GATEWAY -> { - binding.selectStripeButton.strokeColor = - ColorStateList.valueOf(resources.getColor(R.color.woo_purple_60)) - binding.icCheckmarkWcPay.visibility = View.GONE - binding.icCheckmarkStripe.visibility = View.VISIBLE - binding.selectWcPayButton.strokeColor = ColorStateList.valueOf(resources.getColor(R.color.gray_5)) - } + state.onConfirmPaymentMethodClicked.invoke(selectedPluginType) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index 3d02368353c..0e6124cd07c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -204,14 +204,11 @@ class CardReaderOnboardingViewModel @Inject constructor( }.exhaustive } - private fun updateUiWithSelectPaymentPlugin(selectedPlugin: PluginType = WOOCOMMERCE_PAYMENTS) { + private fun updateUiWithSelectPaymentPlugin() { launch { viewState.value = OnboardingViewState.SelectPaymentPluginState( - selectedPlugin = selectedPlugin, - onWcPayOptionClicked = ::onWCPayOptionClicked, - onStripeOptionClicked = ::onStripeOptionClicked, - onConfirmPaymentMethodClicked = { (::refreshState)(selectedPlugin) } + onConfirmPaymentMethodClicked = { (::refreshState)(it) } ) } } @@ -240,14 +237,6 @@ class CardReaderOnboardingViewModel @Inject constructor( } } - private fun onWCPayOptionClicked() { - updateUiWithSelectPaymentPlugin(WOOCOMMERCE_PAYMENTS) - } - - private fun onStripeOptionClicked() { - updateUiWithSelectPaymentPlugin(STRIPE_EXTENSION_GATEWAY) - } - private fun onWPAdminActionClicked() { val url = selectedSite.get().url + AppUrls.PLUGIN_MANAGEMENT_SUFFIX if (selectedSite.get().isWPCom || selectedSite.get().isWPComAtomic) { @@ -333,10 +322,7 @@ class CardReaderOnboardingViewModel @Inject constructor( } data class SelectPaymentPluginState( - val selectedPlugin: PluginType, - val onWcPayOptionClicked: (() -> Unit), - val onStripeOptionClicked: (() -> Unit), - val onConfirmPaymentMethodClicked: (() -> Unit), + val onConfirmPaymentMethodClicked: ((PluginType) -> Unit), ) : OnboardingViewState(R.layout.fragment_card_reader_onboarding_select_payment_gateway) { val cardIllustration = R.drawable.ic_credit_card_give val headerLabel = UiString.UiStringRes(R.string.card_reader_onboarding_choose_payment_provider) From db9f3411f2a875c4e70b1a75b69cc505221c11ec Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 5 Jul 2022 06:43:25 -0300 Subject: [PATCH 159/173] Remove unused variables --- .../ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index 0e6124cd07c..c3f0a84b4d3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -332,8 +332,6 @@ class CardReaderOnboardingViewModel @Inject constructor( val icWcPayLogo = R.drawable.ic_wcpay val icCheckmarkWcPay = R.drawable.ic_menu_action_mode_check val selectStripeButtonLabel = UiString.UiStringRes(R.string.card_reader_onboarding_choose_stripe_button) - val icStripeLogo = R.drawable.ic_stripe - val icCheckmarkStripe = R.drawable.ic_menu_action_mode_check val confirmPaymentMethodButtonLabel = UiString .UiStringRes(R.string.card_reader_onboarding_confirm_payment_method_button) } From 19eda03b6d7d95d5b02781cc477d7b19ff4a9c5d Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Tue, 5 Jul 2022 12:26:39 +0100 Subject: [PATCH 160/173] Fixes to avoid race conditions about loading state --- .../android/ui/coupons/CouponListViewModel.kt | 23 ++++++------- .../ProductCategorySelectorViewModel.kt | 19 +++++------ .../selector/ProductSelectorViewModel.kt | 34 ++++++++----------- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/coupons/CouponListViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/coupons/CouponListViewModel.kt index 00522594664..c79450e5927 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/coupons/CouponListViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/coupons/CouponListViewModel.kt @@ -146,19 +146,18 @@ class CouponListViewModel @Inject constructor( if (it.isNullOrEmpty()) 0L else AppConstants.SEARCH_TYPING_DELAY_MS } .collectLatest { query -> - try { - couponListHandler.fetchCoupons(searchQuery = query) - .onFailure { - triggerEvent( - MultiLiveEvent.Event.ShowSnackbar( - if (query == null) R.string.coupon_list_loading_failed - else R.string.coupon_list_search_failed - ) + // Make sure the loading state is correctly set after debounce too + loadingState.value = LoadingState.Loading + couponListHandler.fetchCoupons(searchQuery = query) + .onFailure { + triggerEvent( + MultiLiveEvent.Event.ShowSnackbar( + if (query == null) R.string.coupon_list_loading_failed + else R.string.coupon_list_search_failed ) - } - } finally { - loadingState.value = LoadingState.Idle - } + ) + } + loadingState.value = LoadingState.Idle } } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/selector/ProductCategorySelectorViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/selector/ProductCategorySelectorViewModel.kt index 2bd5c1755f1..6612d1d75e9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/selector/ProductCategorySelectorViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/categories/selector/ProductCategorySelectorViewModel.kt @@ -109,16 +109,15 @@ class ProductCategorySelectorViewModel @Inject constructor( if (it.isNullOrEmpty()) 0L else AppConstants.SEARCH_TYPING_DELAY_MS } .collectLatest { query -> - try { - listHandler.fetchCategories(searchQuery = query) - .onFailure { - val message = if (query.isEmpty()) R.string.product_category_selector_loading_failed - else R.string.product_category_selector_search_failed - triggerEvent(ShowSnackbar(message)) - } - } finally { - loadingState.value = LoadingState.Idle - } + // Make sure the loading state is correctly set after debounce too + loadingState.value = LoadingState.Loading + listHandler.fetchCategories(searchQuery = query) + .onFailure { + val message = if (query.isEmpty()) R.string.product_category_selector_loading_failed + else R.string.product_category_selector_search_failed + triggerEvent(ShowSnackbar(message)) + } + loadingState.value = LoadingState.Idle } } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/selector/ProductSelectorViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/selector/ProductSelectorViewModel.kt index ec4b164352e..27acc6eb63a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/selector/ProductSelectorViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/selector/ProductSelectorViewModel.kt @@ -243,16 +243,15 @@ class ProductSelectorViewModel @Inject constructor( if (it.isEmpty()) 0L else AppConstants.SEARCH_TYPING_DELAY_MS } .collectLatest { query -> - try { - listHandler.fetchProducts(searchQuery = query) - .onFailure { - val message = if (query.isEmpty()) string.product_selector_loading_failed - else string.product_selector_search_failed - triggerEvent(ShowSnackbar(message)) - } - } finally { - loadingState.value = IDLE - } + // Make sure the loading state is correctly set after debounce too + loadingState.value = LOADING + listHandler.fetchProducts(searchQuery = query) + .onFailure { + val message = if (query.isEmpty()) string.product_selector_loading_failed + else string.product_selector_search_failed + triggerEvent(ShowSnackbar(message)) + } + loadingState.value = IDLE } } } @@ -270,15 +269,12 @@ class ProductSelectorViewModel @Inject constructor( loadingState.value = LOADING } .collectLatest { filters -> - try { - listHandler.fetchProducts(filters = filters.filterOptions) - .onFailure { - val message = string.product_selector_loading_failed - triggerEvent(ShowSnackbar(message)) - } - } finally { - loadingState.value = IDLE - } + listHandler.fetchProducts(filters = filters.filterOptions) + .onFailure { + val message = string.product_selector_loading_failed + triggerEvent(ShowSnackbar(message)) + } + loadingState.value = IDLE } } } From b7aa7b25536494320f3a1e7335b81b4f8785d88f Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Tue, 5 Jul 2022 13:31:37 +0200 Subject: [PATCH 161/173] Deprecate ic_info_outline_24dp with grey fill color. Introduce a new, tintable icon. --- .../FeatureAnnouncementListAdapter.kt | 2 +- .../deprecated_ic_info_outline_24dp.xml | 19 +++++++++++++++++++ ....xml => tintable_ic_info_outline_24dp.xml} | 2 +- .../res/layout/dialog_woo_discount_info.xml | 2 +- .../layout/feature_announcement_list_item.xml | 2 +- ...ent_card_reader_detail_connected_state.xml | 2 +- .../fragment_edit_shipping_label_address.xml | 2 +- .../res/layout/fragment_ordered_addon.xml | 2 +- .../layout/fragment_print_shipping_label.xml | 4 ++-- .../res/layout/fragment_product_addons.xml | 2 +- .../fragment_shipping_carrier_rates.xml | 2 +- ...ment_shipping_label_address_suggestion.xml | 2 +- .../res/layout/multiple_lines_warning.xml | 2 +- .../res/layout/order_detail_payment_info.xml | 2 +- .../res/layout/order_detail_product_list.xml | 2 +- .../res/layout/refund_by_items_products.xml | 2 +- ...ipping_label_package_details_list_item.xml | 2 +- .../main/res/layout/view_banner_warning.xml | 2 +- .../view_shipping_label_order_summary.xml | 2 +- 19 files changed, 38 insertions(+), 19 deletions(-) create mode 100644 WooCommerce/src/main/res/drawable/deprecated_ic_info_outline_24dp.xml rename WooCommerce/src/main/res/drawable/{ic_info_outline_24dp.xml => tintable_ic_info_outline_24dp.xml} (90%) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/whatsnew/FeatureAnnouncementListAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/whatsnew/FeatureAnnouncementListAdapter.kt index 63ea22d41d8..71b52b003d1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/whatsnew/FeatureAnnouncementListAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/whatsnew/FeatureAnnouncementListAdapter.kt @@ -47,7 +47,7 @@ class FeatureAnnouncementListAdapter : val placeholder = ContextCompat.getDrawable( viewBinding.root.context, - R.drawable.ic_info_outline_24dp + R.drawable.deprecated_ic_info_outline_24dp ) when { diff --git a/WooCommerce/src/main/res/drawable/deprecated_ic_info_outline_24dp.xml b/WooCommerce/src/main/res/drawable/deprecated_ic_info_outline_24dp.xml new file mode 100644 index 00000000000..60154fbde47 --- /dev/null +++ b/WooCommerce/src/main/res/drawable/deprecated_ic_info_outline_24dp.xml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/WooCommerce/src/main/res/drawable/ic_info_outline_24dp.xml b/WooCommerce/src/main/res/drawable/tintable_ic_info_outline_24dp.xml similarity index 90% rename from WooCommerce/src/main/res/drawable/ic_info_outline_24dp.xml rename to WooCommerce/src/main/res/drawable/tintable_ic_info_outline_24dp.xml index 4695eb17f02..6a4da1a6b67 100644 --- a/WooCommerce/src/main/res/drawable/ic_info_outline_24dp.xml +++ b/WooCommerce/src/main/res/drawable/tintable_ic_info_outline_24dp.xml @@ -6,7 +6,7 @@ android:viewportWidth="24.0" > diff --git a/WooCommerce/src/main/res/layout/dialog_woo_discount_info.xml b/WooCommerce/src/main/res/layout/dialog_woo_discount_info.xml index 3b2979351b9..54fb96efbb9 100644 --- a/WooCommerce/src/main/res/layout/dialog_woo_discount_info.xml +++ b/WooCommerce/src/main/res/layout/dialog_woo_discount_info.xml @@ -11,7 +11,7 @@ + tools:src="@drawable/deprecated_ic_info_outline_24dp" /> diff --git a/WooCommerce/src/main/res/layout/fragment_card_reader_detail_connected_state.xml b/WooCommerce/src/main/res/layout/fragment_card_reader_detail_connected_state.xml index 5e3f787d9bb..609adf0fcbf 100644 --- a/WooCommerce/src/main/res/layout/fragment_card_reader_detail_connected_state.xml +++ b/WooCommerce/src/main/res/layout/fragment_card_reader_detail_connected_state.xml @@ -15,7 +15,7 @@ android:layout_marginStart="0dp" android:layout_marginEnd="0dp" android:background="@color/warning_banner_background_color" - android:drawableStart="@drawable/ic_info_outline_24dp" + android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" android:drawablePadding="@dimen/major_100" android:padding="@dimen/major_100" android:text="@string/card_reader_detail_connected_enforced_update_software" diff --git a/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml b/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml index 31eacf8926e..9ecb2545bdf 100644 --- a/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml +++ b/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml @@ -29,7 +29,7 @@ android:layout_marginStart="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" android:contentDescription="@string/shipping_label_edit_address_validation_error" - android:src="@drawable/ic_info_outline_24dp" + android:src="@drawable/tintable_ic_info_outline_24dp" app:layout_constraintBottom_toTopOf="@id/errorBannerDivider" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@id/errorBannerMessage" diff --git a/WooCommerce/src/main/res/layout/fragment_ordered_addon.xml b/WooCommerce/src/main/res/layout/fragment_ordered_addon.xml index 33edf62dc51..654e7f0450d 100644 --- a/WooCommerce/src/main/res/layout/fragment_ordered_addon.xml +++ b/WooCommerce/src/main/res/layout/fragment_ordered_addon.xml @@ -38,7 +38,7 @@ android:layout_marginStart="@dimen/major_100" android:layout_marginTop="@dimen/minor_10" android:drawablePadding="@dimen/minor_100" - android:drawableStart="@drawable/ic_info_outline_24dp" + android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" android:gravity="center_vertical" android:text="@string/ordered_add_ons_details_info_notice" android:visibility="gone" diff --git a/WooCommerce/src/main/res/layout/fragment_print_shipping_label.xml b/WooCommerce/src/main/res/layout/fragment_print_shipping_label.xml index f7bec28cdc5..8329f1288a7 100644 --- a/WooCommerce/src/main/res/layout/fragment_print_shipping_label.xml +++ b/WooCommerce/src/main/res/layout/fragment_print_shipping_label.xml @@ -46,7 +46,7 @@ android:layout_marginEnd="@dimen/major_100" android:layout_marginBottom="@dimen/major_100" android:contentDescription="@string/shipping_label_print_disclaimer" - android:src="@drawable/ic_info_outline_24dp" + android:src="@drawable/deprecated_ic_info_outline_24dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/shippingLabelPrint_errorMessage" /> @@ -181,7 +181,7 @@ android:layout_height="wrap_content" android:layout_margin="@dimen/major_100" android:contentDescription="@string/shipping_label_print_info" - android:src="@drawable/ic_info_outline_24dp" + android:src="@drawable/deprecated_ic_info_outline_24dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/WooCommerce/src/main/res/layout/fragment_product_addons.xml b/WooCommerce/src/main/res/layout/fragment_product_addons.xml index 55c2ff66689..13c51947be7 100644 --- a/WooCommerce/src/main/res/layout/fragment_product_addons.xml +++ b/WooCommerce/src/main/res/layout/fragment_product_addons.xml @@ -23,7 +23,7 @@ android:layout_marginStart="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" android:text="@string/product_add_ons_details_info_notice" - android:drawableStart="@drawable/ic_info_outline_24dp" + android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" android:drawablePadding="@dimen/minor_100" android:gravity="center_vertical" android:visibility="visible" diff --git a/WooCommerce/src/main/res/layout/fragment_shipping_carrier_rates.xml b/WooCommerce/src/main/res/layout/fragment_shipping_carrier_rates.xml index 4584722703b..fa63e5f848c 100644 --- a/WooCommerce/src/main/res/layout/fragment_shipping_carrier_rates.xml +++ b/WooCommerce/src/main/res/layout/fragment_shipping_carrier_rates.xml @@ -26,7 +26,7 @@ android:layout_marginStart="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" android:contentDescription="@string/shipping_label_edit_address_validation_error" - android:src="@drawable/ic_info_outline_24dp" + android:src="@drawable/tintable_ic_info_outline_24dp" app:layout_constraintBottom_toTopOf="@id/infoBannerDivider" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@id/infoBannerMessage" diff --git a/WooCommerce/src/main/res/layout/fragment_shipping_label_address_suggestion.xml b/WooCommerce/src/main/res/layout/fragment_shipping_label_address_suggestion.xml index 56513d5e525..45b15f263a5 100644 --- a/WooCommerce/src/main/res/layout/fragment_shipping_label_address_suggestion.xml +++ b/WooCommerce/src/main/res/layout/fragment_shipping_label_address_suggestion.xml @@ -31,7 +31,7 @@ android:layout_marginStart="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" android:contentDescription="@string/shipping_label_edit_address_validation_error" - android:src="@drawable/ic_info_outline_24dp" + android:src="@drawable/tintable_ic_info_outline_24dp" app:layout_constraintBottom_toTopOf="@id/bannerDivider" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@id/suggestionBannerMessage" diff --git a/WooCommerce/src/main/res/layout/multiple_lines_warning.xml b/WooCommerce/src/main/res/layout/multiple_lines_warning.xml index 6d0318a2efb..4c67199d626 100644 --- a/WooCommerce/src/main/res/layout/multiple_lines_warning.xml +++ b/WooCommerce/src/main/res/layout/multiple_lines_warning.xml @@ -19,7 +19,7 @@ android:layout_height="wrap_content" android:drawablePadding="@dimen/minor_100" android:textAppearance="@style/TextAppearance.Woo.Subtitle1" - app:drawableStartCompat="@drawable/ic_info_outline_24dp" + app:drawableStartCompat="@drawable/tintable_ic_info_outline_24dp" app:drawableTint="@color/color_primary" tools:text="@string/lines_incomplete" /> diff --git a/WooCommerce/src/main/res/layout/order_detail_payment_info.xml b/WooCommerce/src/main/res/layout/order_detail_payment_info.xml index 34a4c52f454..2e586acc3f7 100644 --- a/WooCommerce/src/main/res/layout/order_detail_payment_info.xml +++ b/WooCommerce/src/main/res/layout/order_detail_payment_info.xml @@ -383,7 +383,7 @@ android:textColor="@color/color_on_surface_medium" android:layout_marginVertical="@dimen/major_100" android:layout_height="wrap_content" - android:drawableStart="@drawable/ic_info_outline_24dp" + android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" android:drawablePadding="@dimen/major_100" android:background="?attr/selectableItemBackground" android:layout_marginEnd="@dimen/major_100" diff --git a/WooCommerce/src/main/res/layout/order_detail_product_list.xml b/WooCommerce/src/main/res/layout/order_detail_product_list.xml index 030c654c392..9517f1c162c 100644 --- a/WooCommerce/src/main/res/layout/order_detail_product_list.xml +++ b/WooCommerce/src/main/res/layout/order_detail_product_list.xml @@ -91,7 +91,7 @@ android:layout_marginBottom="@dimen/major_100" android:layout_marginStart="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" - android:drawableStart="@drawable/ic_info_outline_24dp" + android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" android:drawablePadding="@dimen/major_100" android:text="@string/orderdetail_shipping_label_notice" android:visibility="gone" diff --git a/WooCommerce/src/main/res/layout/refund_by_items_products.xml b/WooCommerce/src/main/res/layout/refund_by_items_products.xml index 34354a542b8..40099a787d4 100644 --- a/WooCommerce/src/main/res/layout/refund_by_items_products.xml +++ b/WooCommerce/src/main/res/layout/refund_by_items_products.xml @@ -75,7 +75,7 @@ android:layout_marginTop="@dimen/major_100" android:layout_marginStart="@dimen/minor_00" android:layout_marginEnd="@dimen/minor_00" - android:drawableStart="@drawable/ic_info_outline_24dp" + android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" android:drawablePadding="@dimen/major_100" tools:text="@string/order_refunds_shipping_refund_variable_notice" android:visibility="visible" diff --git a/WooCommerce/src/main/res/layout/shipping_label_package_details_list_item.xml b/WooCommerce/src/main/res/layout/shipping_label_package_details_list_item.xml index 94de9eefbf8..fd0cccf7b71 100644 --- a/WooCommerce/src/main/res/layout/shipping_label_package_details_list_item.xml +++ b/WooCommerce/src/main/res/layout/shipping_label_package_details_list_item.xml @@ -173,7 +173,7 @@ android:text="@string/shipping_label_package_details_individual_package_dimensions_error" android:textAppearance="?attr/textAppearanceCaption" android:textColor="@color/color_error" - app:drawableStartCompat="@drawable/ic_info_outline_24dp" + app:drawableStartCompat="@drawable/tintable_ic_info_outline_24dp" app:drawableTint="@color/color_error" /> diff --git a/WooCommerce/src/main/res/layout/view_banner_warning.xml b/WooCommerce/src/main/res/layout/view_banner_warning.xml index c6f5c864a31..b2145d0ec96 100644 --- a/WooCommerce/src/main/res/layout/view_banner_warning.xml +++ b/WooCommerce/src/main/res/layout/view_banner_warning.xml @@ -14,7 +14,7 @@ android:layout_marginTop="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" android:contentDescription="@string/product_property_edit" - android:src="@drawable/ic_info_outline_24dp" + android:src="@drawable/tintable_ic_info_outline_24dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:tint="@color/warning_banner_foreground_color" /> diff --git a/WooCommerce/src/main/res/layout/view_shipping_label_order_summary.xml b/WooCommerce/src/main/res/layout/view_shipping_label_order_summary.xml index f2c02b75444..37c40f0b318 100644 --- a/WooCommerce/src/main/res/layout/view_shipping_label_order_summary.xml +++ b/WooCommerce/src/main/res/layout/view_shipping_label_order_summary.xml @@ -100,7 +100,7 @@ app:layout_constraintBottom_toBottomOf="@id/discount_label" app:layout_constraintStart_toEndOf="@id/discount_label" app:layout_constraintTop_toTopOf="@id/discount_label" - app:srcCompat="@drawable/ic_info_outline_24dp" /> + app:srcCompat="@drawable/deprecated_ic_info_outline_24dp" /> Date: Tue, 5 Jul 2022 10:17:16 -0300 Subject: [PATCH 162/173] Add unit tests --- .../CardReaderOnboardingViewModelTest.kt | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt index 73ca22057bb..fe4d92a6b6d 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt @@ -666,6 +666,154 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { ) } + @Test + fun `when wcpay and stripe extension installed-activated, then payment gateway screen is shown`() = + testBlocking { + whenever(onboardingChecker.getOnboardingState()).thenReturn( + CardReaderOnboardingState.ChoosePaymentGatewayProvider + ) + + val viewModel = createVM() + + assertThat(viewModel.viewStateData.value).isInstanceOf( + OnboardingViewState.SelectPaymentPluginState::class.java + ) + } + + @Test + fun `when wcpay and stripe active, then wcpay button shown`() = + testBlocking { + whenever(onboardingChecker.getOnboardingState()).thenReturn( + CardReaderOnboardingState.ChoosePaymentGatewayProvider + ) + + val viewModel = createVM() + + val viewStateData = viewModel.viewStateData.value as OnboardingViewState.SelectPaymentPluginState + assertThat(viewStateData.selectWcPayButtonLabel).isNotNull + } + + @Test + fun `when wcpay and stripe active, then stripe button shown`() = + testBlocking { + whenever(onboardingChecker.getOnboardingState()).thenReturn( + CardReaderOnboardingState.ChoosePaymentGatewayProvider + ) + + val viewModel = createVM() + + val viewStateData = viewModel.viewStateData.value as OnboardingViewState.SelectPaymentPluginState + assertThat(viewStateData.selectStripeButtonLabel).isNotNull + } + + @Test + fun `when wcpay and stripe extension active, then confirm payment method button shown`() = + testBlocking { + whenever(onboardingChecker.getOnboardingState()).thenReturn( + CardReaderOnboardingState.ChoosePaymentGatewayProvider + ) + + val viewModel = createVM() + + val viewStateData = viewModel.viewStateData.value as OnboardingViewState.SelectPaymentPluginState + assertThat(viewStateData.confirmPaymentMethodButtonLabel).isNotNull() + } + + @Test + fun `when wcpay and stripe extension active, then correct labels and illustrations shown`() = + testBlocking { + whenever(onboardingChecker.getOnboardingState()).thenReturn( + CardReaderOnboardingState.ChoosePaymentGatewayProvider + ) + + val viewModel = createVM() + + val state = ( + viewModel.viewStateData.value as OnboardingViewState.SelectPaymentPluginState + ) + assertThat(state.cardIllustration) + .describedAs("Check illustration") + .isEqualTo( + R.drawable.ic_credit_card_give + ) + assertThat(state.headerLabel) + .describedAs("Check header") + .isEqualTo( + UiString.UiStringRes( + R.string.card_reader_onboarding_choose_payment_provider + ) + ) + assertThat(state.choosePluginHintLabel) + .describedAs("Check hint") + .isEqualTo( + UiString.UiStringRes( + R.string.card_reader_onboarding_choose_plugin_hint + ) + ) + assertThat(state.selectWcPayButtonLabel) + .describedAs("Check wcpayButtonLabel") + .isEqualTo( + UiString.UiStringRes( + R.string.card_reader_onboarding_choose_wcpayment_button + ) + ) + assertThat(state.icWcPayLogo) + .describedAs("Check illustration") + .isEqualTo( + R.drawable.ic_wcpay + ) + assertThat(state.icCheckmarkWcPay) + .describedAs("Check illustration") + .isEqualTo( + R.drawable.ic_menu_action_mode_check + ) + assertThat(state.selectStripeButtonLabel) + .describedAs("Check wcpayButtonLabel") + .isEqualTo( + UiString.UiStringRes( + R.string.card_reader_onboarding_choose_stripe_button + ) + ) + assertThat(state.confirmPaymentMethodButtonLabel) + .describedAs("Check wcpayButtonLabel") + .isEqualTo( + UiString.UiStringRes( + R.string.card_reader_onboarding_confirm_payment_method_button + ) + ) + } + + @Test + fun `given wcpay and stripe extension active, when user taps wcpay and confirm button, then load screen shown `() = + testBlocking { + whenever(onboardingChecker.getOnboardingState()).thenReturn( + CardReaderOnboardingState.ChoosePaymentGatewayProvider + ) + + val viewModel = createVM() + + val viewStateData = viewModel.viewStateData.value as OnboardingViewState.SelectPaymentPluginState + viewStateData.onConfirmPaymentMethodClicked.invoke(WOOCOMMERCE_PAYMENTS) + + assertThat(viewModel.viewStateData.value).isEqualTo(LoadingState) + } + + @Test + fun `given wcpay and stripe extension active, when user taps stripe and confirm button, then load screen shown `() = + + testBlocking { + whenever(onboardingChecker.getOnboardingState()).thenReturn( + CardReaderOnboardingState.ChoosePaymentGatewayProvider + ) + + val viewModel = createVM() + + val viewStateData = viewModel.viewStateData.value as OnboardingViewState.SelectPaymentPluginState + viewStateData.onConfirmPaymentMethodClicked.invoke(STRIPE_EXTENSION_GATEWAY) + + assertThat(viewModel.viewStateData.value).isEqualTo(LoadingState) + } + @Test fun `given user is admin, when wcpay and stripe extension active, then open wpadmin button shown`() = testBlocking { From 1dfe1eefd2e46aa14b85d566f80a56670e6ae4fe Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 5 Jul 2022 11:57:09 -0300 Subject: [PATCH 163/173] Add unit tests --- .../CardReaderOnboardingViewModelTest.kt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt index fe4d92a6b6d..e079f78bb09 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModelTest.kt @@ -680,6 +680,45 @@ class CardReaderOnboardingViewModelTest : BaseUnitTest() { ) } + @Test + fun `when wcpay and stripe extension active, then confirm illustration shown`() = + testBlocking { + whenever(onboardingChecker.getOnboardingState()).thenReturn( + CardReaderOnboardingState.ChoosePaymentGatewayProvider + ) + + val viewModel = createVM() + + val viewStateData = viewModel.viewStateData.value as OnboardingViewState.SelectPaymentPluginState + assertThat(viewStateData.cardIllustration).isNotNull() + } + + @Test + fun `when wcpay and stripe extension active, then confirm header shown`() = + testBlocking { + whenever(onboardingChecker.getOnboardingState()).thenReturn( + CardReaderOnboardingState.ChoosePaymentGatewayProvider + ) + + val viewModel = createVM() + + val viewStateData = viewModel.viewStateData.value as OnboardingViewState.SelectPaymentPluginState + assertThat(viewStateData.headerLabel).isNotNull() + } + + @Test + fun `when wcpay and stripe extension active, then confirm hint shown`() = + testBlocking { + whenever(onboardingChecker.getOnboardingState()).thenReturn( + CardReaderOnboardingState.ChoosePaymentGatewayProvider + ) + + val viewModel = createVM() + + val viewStateData = viewModel.viewStateData.value as OnboardingViewState.SelectPaymentPluginState + assertThat(viewStateData.choosePluginHintLabel).isNotNull() + } + @Test fun `when wcpay and stripe active, then wcpay button shown`() = testBlocking { From 516ff27edb25aee45ce666b089b0b484f55df1a1 Mon Sep 17 00:00:00 2001 From: Alejo Date: Tue, 5 Jul 2022 11:45:17 -0500 Subject: [PATCH 164/173] remove redundant @OptIn annotations --- .../woocommerce/android/ui/orders/creation/AutoSyncOrder.kt | 2 +- .../android/ui/orders/creation/AutoSyncPriceModifier.kt | 2 +- .../android/ui/orders/creation/CreateUpdateOrder.kt | 2 +- .../woocommerce/android/ui/orders/creation/SyncStrategy.kt | 2 ++ .../android/ui/orders/creation/AutoSyncOrderStrategyTest.kt | 4 +--- .../ui/orders/creation/AutoSyncPriceModifierStrategyTest.kt | 4 +--- .../android/ui/orders/creation/CreateUpdateOrderTests.kt | 2 ++ 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt index f98db91f950..36cdd418d98 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrder.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import javax.inject.Inject +@ExperimentalCoroutinesApi class AutoSyncOrder @Inject constructor(val createUpdateOrderUseCase: CreateUpdateOrder) : SyncStrategy { private fun areEquivalent(old: Order, new: Order): Boolean { // Make sure to update the prices only when items did change @@ -55,7 +56,6 @@ class AutoSyncOrder @Inject constructor(val createUpdateOrderUseCase: CreateUpda hasSameCustomerInfo } - @OptIn(ExperimentalCoroutinesApi::class) override fun syncOrderChanges( changes: Flow, retryTrigger: Flow diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt index 9ebe05637ed..4496c803633 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifier.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import javax.inject.Inject +@ExperimentalCoroutinesApi class AutoSyncPriceModifier @Inject constructor(val createUpdateOrderUseCase: CreateUpdateOrder) : SyncStrategy { /** * Anything that can be modified during the Order Creation flow that can affect @@ -56,7 +57,6 @@ class AutoSyncPriceModifier @Inject constructor(val createUpdateOrderUseCase: Cr old.billingAddress.isSamePhysicalAddress(new.billingAddress) } - @OptIn(ExperimentalCoroutinesApi::class) override fun syncOrderChanges( changes: Flow, retryTrigger: Flow diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt index 5fbbc6bfdc2..6c75d629273 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrder.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.onStart import javax.inject.Inject +@ExperimentalCoroutinesApi class CreateUpdateOrder @Inject constructor( private val dispatchers: CoroutineDispatchers, private val orderCreationRepository: OrderCreationRepository @@ -37,7 +38,6 @@ class CreateUpdateOrder @Inject constructor( object Failed : OrderUpdateStatus } - @OptIn(ExperimentalCoroutinesApi::class) operator fun invoke(changes: Flow, retryTrigger: Flow): Flow { return changes .flowOn(dispatchers.computation) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategy.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategy.kt index f80e157bd4b..304aa180401 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategy.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/creation/SyncStrategy.kt @@ -1,8 +1,10 @@ package com.woocommerce.android.ui.orders.creation import com.woocommerce.android.model.Order +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +@ExperimentalCoroutinesApi interface SyncStrategy { fun syncOrderChanges(changes: Flow, retryTrigger: Flow): Flow } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrderStrategyTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrderStrategyTest.kt index 1aea213e57f..24cd93f4c7f 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrderStrategyTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncOrderStrategyTest.kt @@ -8,10 +8,10 @@ import org.junit.Test import org.mockito.kotlin.times import org.mockito.kotlin.verify +@ExperimentalCoroutinesApi class AutoSyncOrderStrategyTest : SyncStrategyTest() { private val sut: AutoSyncOrder = AutoSyncOrder(createUpdateOrderUseCase) - @OptIn(ExperimentalCoroutinesApi::class) @Test fun `WHEN the user commits a random change THEN the change is submitted to the API`() = testBlocking { val job = sut.syncOrderChanges(orderDraftChanges, retryTrigger) @@ -23,7 +23,6 @@ class AutoSyncOrderStrategyTest : SyncStrategyTest() { job.cancel() } - @OptIn(ExperimentalCoroutinesApi::class) @Test fun `WHEN the user commits a price modifier change THEN the change is submitted to the API`() = testBlocking { val job = sut.syncOrderChanges(orderDraftChanges, retryTrigger) @@ -35,7 +34,6 @@ class AutoSyncOrderStrategyTest : SyncStrategyTest() { job.cancel() } - @OptIn(ExperimentalCoroutinesApi::class) @Test fun `WHEN the order is NOT changed by the user THEN the change is NOT submitted to the API`() = testBlocking { val job = sut.syncOrderChanges(orderDraftChanges, retryTrigger) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifierStrategyTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifierStrategyTest.kt index 80b3002e10f..9ac1f7ccf7d 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifierStrategyTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/AutoSyncPriceModifierStrategyTest.kt @@ -8,10 +8,10 @@ import org.junit.Test import org.mockito.kotlin.times import org.mockito.kotlin.verify +@ExperimentalCoroutinesApi class AutoSyncPriceModifierStrategyTest : SyncStrategyTest() { private val sut: AutoSyncPriceModifier = AutoSyncPriceModifier(createUpdateOrderUseCase) - @OptIn(ExperimentalCoroutinesApi::class) @Test fun `WHEN the user commits a change NOT affecting the price THEN the change is NOT submitted to the API`() = testBlocking { @@ -24,7 +24,6 @@ class AutoSyncPriceModifierStrategyTest : SyncStrategyTest() { job.cancel() } - @OptIn(ExperimentalCoroutinesApi::class) @Test fun `WHEN the user commits a price modifier change THEN the change is submitted to the API`() = testBlocking { val job = sut.syncOrderChanges(orderDraftChanges, retryTrigger) @@ -36,7 +35,6 @@ class AutoSyncPriceModifierStrategyTest : SyncStrategyTest() { job.cancel() } - @OptIn(ExperimentalCoroutinesApi::class) @Test fun `WHEN the order is NOT changed by the user THEN the change is NOT submitted to the API`() = testBlocking { val job = sut.syncOrderChanges(orderDraftChanges, retryTrigger) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrderTests.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrderTests.kt index 17f9d99250a..20ae606b490 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrderTests.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/creation/CreateUpdateOrderTests.kt @@ -6,6 +6,7 @@ import com.woocommerce.android.ui.orders.creation.CreateUpdateOrder.OrderUpdateS import com.woocommerce.android.util.InlineClassesAnswer import com.woocommerce.android.util.advanceTimeAndRun import com.woocommerce.android.viewmodel.BaseUnitTest +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn @@ -24,6 +25,7 @@ import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import java.math.BigDecimal +@ExperimentalCoroutinesApi class CreateUpdateOrderTests : BaseUnitTest() { private val orderCreationRepository = mock { onBlocking { createOrUpdateDraft(any()) } doAnswer InlineClassesAnswer { From 7960bce93214846e58c29341e3fa31c61a6230d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 20:45:53 +0000 Subject: [PATCH 165/173] Bump flipperVersion from 0.143.0 to 0.152.0 Bumps `flipperVersion` from 0.143.0 to 0.152.0. Updates `flipper` from 0.143.0 to 0.152.0 - [Release notes](https://github.com/facebook/flipper/releases) - [Commits](https://github.com/facebook/flipper/compare/v0.143.0...v0.152.0) Updates `flipper-network-plugin` from 0.143.0 to 0.152.0 - [Release notes](https://github.com/facebook/flipper/releases) - [Commits](https://github.com/facebook/flipper/compare/v0.143.0...v0.152.0) --- updated-dependencies: - dependency-name: com.facebook.flipper:flipper dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.facebook.flipper:flipper-network-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e2b143e403b..788c138f76a 100644 --- a/build.gradle +++ b/build.gradle @@ -92,7 +92,7 @@ ext { coroutinesVersion = '1.6.1' lifecycleVersion = '2.4.1' aztecVersion = 'v1.3.45' - flipperVersion = '0.143.0' + flipperVersion = '0.152.0' stateMachineVersion = '0.2.0' coreKtxVersion = '1.7.0' appCompatVersion = '1.4.1' From 7042fcf42cdd38fee39e625fb806916e108e9c58 Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Wed, 6 Jul 2022 10:38:54 +0200 Subject: [PATCH 166/173] Auto-resize header to fit 1 line --- WooCommerce/src/main/res/layout/multiple_lines_warning.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/res/layout/multiple_lines_warning.xml b/WooCommerce/src/main/res/layout/multiple_lines_warning.xml index 6d0318a2efb..40dd3d99d09 100644 --- a/WooCommerce/src/main/res/layout/multiple_lines_warning.xml +++ b/WooCommerce/src/main/res/layout/multiple_lines_warning.xml @@ -18,10 +18,12 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawablePadding="@dimen/minor_100" + android:lines="1" android:textAppearance="@style/TextAppearance.Woo.Subtitle1" + app:autoSizeTextType="uniform" app:drawableStartCompat="@drawable/ic_info_outline_24dp" app:drawableTint="@color/color_primary" - tools:text="@string/lines_incomplete" /> + tools:text="Fees & Shipping details are incomplete" /> Date: Wed, 6 Jul 2022 10:39:17 +0200 Subject: [PATCH 167/173] Remove dot --- WooCommerce/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index 9285422e02a..ea2b08cf686 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -2502,6 +2502,6 @@ Things to know before installing Proceed With Installation %1$s are incomplete - To edit all %1$s browse the order in your WooCommerce store admin. + To edit all %1$s browse the order in your WooCommerce store admin the details From cd1aad8dd0f69e82bb55891f45dd10ad90ffb207 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 6 Jul 2022 08:43:15 -0300 Subject: [PATCH 168/173] Remove coroutine from updateUiWithSelectPaymentPlugin() --- .../onboarding/CardReaderOnboardingViewModel.kt | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index c3f0a84b4d3..cd4cd8027e9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -13,6 +13,7 @@ import com.woocommerce.android.extensions.formatToMMMMdd import com.woocommerce.android.model.UiString import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.cardreader.CardReaderTracker +import com.woocommerce.android.ui.cardreader.detail.CardReaderDetailViewModel import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingParams.Check import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingParams.Failed import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.ChoosePaymentGatewayProvider @@ -205,12 +206,10 @@ class CardReaderOnboardingViewModel @Inject constructor( } private fun updateUiWithSelectPaymentPlugin() { - launch { - viewState.value = - OnboardingViewState.SelectPaymentPluginState( - onConfirmPaymentMethodClicked = { (::refreshState)(it) } - ) - } + viewState.value = + OnboardingViewState.SelectPaymentPluginState( + onConfirmPaymentMethodClicked = { (::refreshState)(it) } + ) } private fun updateUiWithWcPayAndStripeActivated() { @@ -242,7 +241,7 @@ class CardReaderOnboardingViewModel @Inject constructor( if (selectedSite.get().isWPCom || selectedSite.get().isWPComAtomic) { triggerEvent(NavigateToUrlInWPComWebView(url)) } else { - triggerEvent(NavigateToUrlInGenericWebView(url)) + triggerEvent(CardReaderDetailViewModel.CardReaderDetailEvent.NavigateToUrlInGenericWebView(url)) } } @@ -261,7 +260,7 @@ class CardReaderOnboardingViewModel @Inject constructor( STRIPE_EXTENSION_GATEWAY -> AppUrls.STRIPE_LEARN_MORE_ABOUT_PAYMENTS WOOCOMMERCE_PAYMENTS, null -> AppUrls.WOOCOMMERCE_LEARN_MORE_ABOUT_PAYMENTS } - triggerEvent(NavigateToUrlInGenericWebView(learnMoreUrl)) + triggerEvent(CardReaderDetailViewModel.CardReaderDetailEvent.NavigateToUrlInGenericWebView(learnMoreUrl)) } private fun onSkipPendingRequirementsClicked(storeCountryCode: String) { From 90889c32be7bc20f5201df7daa89e5acf5ef5636 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 6 Jul 2022 10:13:24 -0300 Subject: [PATCH 169/173] Fix casting added by AS --- .../ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index cd4cd8027e9..e0f94edcaaa 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -241,7 +241,7 @@ class CardReaderOnboardingViewModel @Inject constructor( if (selectedSite.get().isWPCom || selectedSite.get().isWPComAtomic) { triggerEvent(NavigateToUrlInWPComWebView(url)) } else { - triggerEvent(CardReaderDetailViewModel.CardReaderDetailEvent.NavigateToUrlInGenericWebView(url)) + triggerEvent(NavigateToUrlInGenericWebView(url)) } } @@ -260,7 +260,7 @@ class CardReaderOnboardingViewModel @Inject constructor( STRIPE_EXTENSION_GATEWAY -> AppUrls.STRIPE_LEARN_MORE_ABOUT_PAYMENTS WOOCOMMERCE_PAYMENTS, null -> AppUrls.WOOCOMMERCE_LEARN_MORE_ABOUT_PAYMENTS } - triggerEvent(CardReaderDetailViewModel.CardReaderDetailEvent.NavigateToUrlInGenericWebView(learnMoreUrl)) + triggerEvent(NavigateToUrlInGenericWebView(learnMoreUrl)) } private fun onSkipPendingRequirementsClicked(storeCountryCode: String) { From 836a67b4945081578444241a1402f11c041e838a Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 6 Jul 2022 10:21:10 -0300 Subject: [PATCH 170/173] Remove unused import --- .../ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt index e0f94edcaaa..91aae524a88 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/cardreader/onboarding/CardReaderOnboardingViewModel.kt @@ -13,7 +13,6 @@ import com.woocommerce.android.extensions.formatToMMMMdd import com.woocommerce.android.model.UiString import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.cardreader.CardReaderTracker -import com.woocommerce.android.ui.cardreader.detail.CardReaderDetailViewModel import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingParams.Check import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingParams.Failed import com.woocommerce.android.ui.cardreader.onboarding.CardReaderOnboardingState.ChoosePaymentGatewayProvider From 0f95df8f5697ebf689759ba21bab4243bbc4bc1a Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Thu, 7 Jul 2022 13:17:56 +0200 Subject: [PATCH 171/173] Rename icons to prefix with ic_ --- .../android/ui/whatsnew/FeatureAnnouncementListAdapter.kt | 2 +- ...o_outline_24dp.xml => ic_deprecated_info_outline_24dp.xml} | 0 ...nfo_outline_24dp.xml => ic_tintable_info_outline_24dp.xml} | 0 WooCommerce/src/main/res/layout/dialog_woo_discount_info.xml | 2 +- .../src/main/res/layout/feature_announcement_list_item.xml | 2 +- .../layout/fragment_card_reader_detail_connected_state.xml | 2 +- .../main/res/layout/fragment_edit_shipping_label_address.xml | 2 +- WooCommerce/src/main/res/layout/fragment_ordered_addon.xml | 2 +- .../src/main/res/layout/fragment_print_shipping_label.xml | 4 ++-- WooCommerce/src/main/res/layout/fragment_product_addons.xml | 2 +- .../src/main/res/layout/fragment_shipping_carrier_rates.xml | 2 +- .../res/layout/fragment_shipping_label_address_suggestion.xml | 2 +- WooCommerce/src/main/res/layout/multiple_lines_warning.xml | 2 +- WooCommerce/src/main/res/layout/order_detail_payment_info.xml | 2 +- WooCommerce/src/main/res/layout/order_detail_product_list.xml | 2 +- WooCommerce/src/main/res/layout/refund_by_items_products.xml | 2 +- .../res/layout/shipping_label_package_details_list_item.xml | 2 +- WooCommerce/src/main/res/layout/view_banner_warning.xml | 2 +- .../src/main/res/layout/view_shipping_label_order_summary.xml | 2 +- 19 files changed, 18 insertions(+), 18 deletions(-) rename WooCommerce/src/main/res/drawable/{deprecated_ic_info_outline_24dp.xml => ic_deprecated_info_outline_24dp.xml} (100%) rename WooCommerce/src/main/res/drawable/{tintable_ic_info_outline_24dp.xml => ic_tintable_info_outline_24dp.xml} (100%) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/whatsnew/FeatureAnnouncementListAdapter.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/whatsnew/FeatureAnnouncementListAdapter.kt index 71b52b003d1..832082715f7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/whatsnew/FeatureAnnouncementListAdapter.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/whatsnew/FeatureAnnouncementListAdapter.kt @@ -47,7 +47,7 @@ class FeatureAnnouncementListAdapter : val placeholder = ContextCompat.getDrawable( viewBinding.root.context, - R.drawable.deprecated_ic_info_outline_24dp + R.drawable.ic_deprecated_info_outline_24dp ) when { diff --git a/WooCommerce/src/main/res/drawable/deprecated_ic_info_outline_24dp.xml b/WooCommerce/src/main/res/drawable/ic_deprecated_info_outline_24dp.xml similarity index 100% rename from WooCommerce/src/main/res/drawable/deprecated_ic_info_outline_24dp.xml rename to WooCommerce/src/main/res/drawable/ic_deprecated_info_outline_24dp.xml diff --git a/WooCommerce/src/main/res/drawable/tintable_ic_info_outline_24dp.xml b/WooCommerce/src/main/res/drawable/ic_tintable_info_outline_24dp.xml similarity index 100% rename from WooCommerce/src/main/res/drawable/tintable_ic_info_outline_24dp.xml rename to WooCommerce/src/main/res/drawable/ic_tintable_info_outline_24dp.xml diff --git a/WooCommerce/src/main/res/layout/dialog_woo_discount_info.xml b/WooCommerce/src/main/res/layout/dialog_woo_discount_info.xml index 54fb96efbb9..990a86f309c 100644 --- a/WooCommerce/src/main/res/layout/dialog_woo_discount_info.xml +++ b/WooCommerce/src/main/res/layout/dialog_woo_discount_info.xml @@ -11,7 +11,7 @@ + tools:src="@drawable/ic_deprecated_info_outline_24dp" /> diff --git a/WooCommerce/src/main/res/layout/fragment_card_reader_detail_connected_state.xml b/WooCommerce/src/main/res/layout/fragment_card_reader_detail_connected_state.xml index 609adf0fcbf..2136a4cd44f 100644 --- a/WooCommerce/src/main/res/layout/fragment_card_reader_detail_connected_state.xml +++ b/WooCommerce/src/main/res/layout/fragment_card_reader_detail_connected_state.xml @@ -15,7 +15,7 @@ android:layout_marginStart="0dp" android:layout_marginEnd="0dp" android:background="@color/warning_banner_background_color" - android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" + android:drawableStart="@drawable/ic_deprecated_info_outline_24dp" android:drawablePadding="@dimen/major_100" android:padding="@dimen/major_100" android:text="@string/card_reader_detail_connected_enforced_update_software" diff --git a/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml b/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml index 9ecb2545bdf..f0fd9547657 100644 --- a/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml +++ b/WooCommerce/src/main/res/layout/fragment_edit_shipping_label_address.xml @@ -29,7 +29,7 @@ android:layout_marginStart="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" android:contentDescription="@string/shipping_label_edit_address_validation_error" - android:src="@drawable/tintable_ic_info_outline_24dp" + android:src="@drawable/ic_tintable_info_outline_24dp" app:layout_constraintBottom_toTopOf="@id/errorBannerDivider" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@id/errorBannerMessage" diff --git a/WooCommerce/src/main/res/layout/fragment_ordered_addon.xml b/WooCommerce/src/main/res/layout/fragment_ordered_addon.xml index 654e7f0450d..8551b014dcf 100644 --- a/WooCommerce/src/main/res/layout/fragment_ordered_addon.xml +++ b/WooCommerce/src/main/res/layout/fragment_ordered_addon.xml @@ -38,7 +38,7 @@ android:layout_marginStart="@dimen/major_100" android:layout_marginTop="@dimen/minor_10" android:drawablePadding="@dimen/minor_100" - android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" + android:drawableStart="@drawable/ic_deprecated_info_outline_24dp" android:gravity="center_vertical" android:text="@string/ordered_add_ons_details_info_notice" android:visibility="gone" diff --git a/WooCommerce/src/main/res/layout/fragment_print_shipping_label.xml b/WooCommerce/src/main/res/layout/fragment_print_shipping_label.xml index 8329f1288a7..60613817971 100644 --- a/WooCommerce/src/main/res/layout/fragment_print_shipping_label.xml +++ b/WooCommerce/src/main/res/layout/fragment_print_shipping_label.xml @@ -46,7 +46,7 @@ android:layout_marginEnd="@dimen/major_100" android:layout_marginBottom="@dimen/major_100" android:contentDescription="@string/shipping_label_print_disclaimer" - android:src="@drawable/deprecated_ic_info_outline_24dp" + android:src="@drawable/ic_deprecated_info_outline_24dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/shippingLabelPrint_errorMessage" /> @@ -181,7 +181,7 @@ android:layout_height="wrap_content" android:layout_margin="@dimen/major_100" android:contentDescription="@string/shipping_label_print_info" - android:src="@drawable/deprecated_ic_info_outline_24dp" + android:src="@drawable/ic_deprecated_info_outline_24dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/WooCommerce/src/main/res/layout/fragment_product_addons.xml b/WooCommerce/src/main/res/layout/fragment_product_addons.xml index 13c51947be7..c4cea8e56a0 100644 --- a/WooCommerce/src/main/res/layout/fragment_product_addons.xml +++ b/WooCommerce/src/main/res/layout/fragment_product_addons.xml @@ -23,7 +23,7 @@ android:layout_marginStart="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" android:text="@string/product_add_ons_details_info_notice" - android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" + android:drawableStart="@drawable/ic_deprecated_info_outline_24dp" android:drawablePadding="@dimen/minor_100" android:gravity="center_vertical" android:visibility="visible" diff --git a/WooCommerce/src/main/res/layout/fragment_shipping_carrier_rates.xml b/WooCommerce/src/main/res/layout/fragment_shipping_carrier_rates.xml index fa63e5f848c..beaef13c89e 100644 --- a/WooCommerce/src/main/res/layout/fragment_shipping_carrier_rates.xml +++ b/WooCommerce/src/main/res/layout/fragment_shipping_carrier_rates.xml @@ -26,7 +26,7 @@ android:layout_marginStart="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" android:contentDescription="@string/shipping_label_edit_address_validation_error" - android:src="@drawable/tintable_ic_info_outline_24dp" + android:src="@drawable/ic_tintable_info_outline_24dp" app:layout_constraintBottom_toTopOf="@id/infoBannerDivider" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@id/infoBannerMessage" diff --git a/WooCommerce/src/main/res/layout/fragment_shipping_label_address_suggestion.xml b/WooCommerce/src/main/res/layout/fragment_shipping_label_address_suggestion.xml index 45b15f263a5..e0465dabdc0 100644 --- a/WooCommerce/src/main/res/layout/fragment_shipping_label_address_suggestion.xml +++ b/WooCommerce/src/main/res/layout/fragment_shipping_label_address_suggestion.xml @@ -31,7 +31,7 @@ android:layout_marginStart="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" android:contentDescription="@string/shipping_label_edit_address_validation_error" - android:src="@drawable/tintable_ic_info_outline_24dp" + android:src="@drawable/ic_tintable_info_outline_24dp" app:layout_constraintBottom_toTopOf="@id/bannerDivider" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@id/suggestionBannerMessage" diff --git a/WooCommerce/src/main/res/layout/multiple_lines_warning.xml b/WooCommerce/src/main/res/layout/multiple_lines_warning.xml index b145a5aaca2..8b0c0752aa0 100644 --- a/WooCommerce/src/main/res/layout/multiple_lines_warning.xml +++ b/WooCommerce/src/main/res/layout/multiple_lines_warning.xml @@ -21,7 +21,7 @@ android:lines="1" android:textAppearance="@style/TextAppearance.Woo.Subtitle1" app:autoSizeTextType="uniform" - app:drawableStartCompat="@drawable/tintable_ic_info_outline_24dp" + app:drawableStartCompat="@drawable/ic_tintable_info_outline_24dp" app:drawableTint="@color/color_primary" tools:text="Fees & Shipping details are incomplete" /> diff --git a/WooCommerce/src/main/res/layout/order_detail_payment_info.xml b/WooCommerce/src/main/res/layout/order_detail_payment_info.xml index 2e586acc3f7..a14c34852bc 100644 --- a/WooCommerce/src/main/res/layout/order_detail_payment_info.xml +++ b/WooCommerce/src/main/res/layout/order_detail_payment_info.xml @@ -383,7 +383,7 @@ android:textColor="@color/color_on_surface_medium" android:layout_marginVertical="@dimen/major_100" android:layout_height="wrap_content" - android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" + android:drawableStart="@drawable/ic_deprecated_info_outline_24dp" android:drawablePadding="@dimen/major_100" android:background="?attr/selectableItemBackground" android:layout_marginEnd="@dimen/major_100" diff --git a/WooCommerce/src/main/res/layout/order_detail_product_list.xml b/WooCommerce/src/main/res/layout/order_detail_product_list.xml index 9517f1c162c..edddd0378b7 100644 --- a/WooCommerce/src/main/res/layout/order_detail_product_list.xml +++ b/WooCommerce/src/main/res/layout/order_detail_product_list.xml @@ -91,7 +91,7 @@ android:layout_marginBottom="@dimen/major_100" android:layout_marginStart="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" - android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" + android:drawableStart="@drawable/ic_deprecated_info_outline_24dp" android:drawablePadding="@dimen/major_100" android:text="@string/orderdetail_shipping_label_notice" android:visibility="gone" diff --git a/WooCommerce/src/main/res/layout/refund_by_items_products.xml b/WooCommerce/src/main/res/layout/refund_by_items_products.xml index 40099a787d4..12e9ab86472 100644 --- a/WooCommerce/src/main/res/layout/refund_by_items_products.xml +++ b/WooCommerce/src/main/res/layout/refund_by_items_products.xml @@ -75,7 +75,7 @@ android:layout_marginTop="@dimen/major_100" android:layout_marginStart="@dimen/minor_00" android:layout_marginEnd="@dimen/minor_00" - android:drawableStart="@drawable/deprecated_ic_info_outline_24dp" + android:drawableStart="@drawable/ic_deprecated_info_outline_24dp" android:drawablePadding="@dimen/major_100" tools:text="@string/order_refunds_shipping_refund_variable_notice" android:visibility="visible" diff --git a/WooCommerce/src/main/res/layout/shipping_label_package_details_list_item.xml b/WooCommerce/src/main/res/layout/shipping_label_package_details_list_item.xml index fd0cccf7b71..f364b286395 100644 --- a/WooCommerce/src/main/res/layout/shipping_label_package_details_list_item.xml +++ b/WooCommerce/src/main/res/layout/shipping_label_package_details_list_item.xml @@ -173,7 +173,7 @@ android:text="@string/shipping_label_package_details_individual_package_dimensions_error" android:textAppearance="?attr/textAppearanceCaption" android:textColor="@color/color_error" - app:drawableStartCompat="@drawable/tintable_ic_info_outline_24dp" + app:drawableStartCompat="@drawable/ic_tintable_info_outline_24dp" app:drawableTint="@color/color_error" /> diff --git a/WooCommerce/src/main/res/layout/view_banner_warning.xml b/WooCommerce/src/main/res/layout/view_banner_warning.xml index b2145d0ec96..13a04a36fc3 100644 --- a/WooCommerce/src/main/res/layout/view_banner_warning.xml +++ b/WooCommerce/src/main/res/layout/view_banner_warning.xml @@ -14,7 +14,7 @@ android:layout_marginTop="@dimen/major_100" android:layout_marginEnd="@dimen/major_100" android:contentDescription="@string/product_property_edit" - android:src="@drawable/tintable_ic_info_outline_24dp" + android:src="@drawable/ic_tintable_info_outline_24dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:tint="@color/warning_banner_foreground_color" /> diff --git a/WooCommerce/src/main/res/layout/view_shipping_label_order_summary.xml b/WooCommerce/src/main/res/layout/view_shipping_label_order_summary.xml index 37c40f0b318..4eff40fcbe1 100644 --- a/WooCommerce/src/main/res/layout/view_shipping_label_order_summary.xml +++ b/WooCommerce/src/main/res/layout/view_shipping_label_order_summary.xml @@ -100,7 +100,7 @@ app:layout_constraintBottom_toBottomOf="@id/discount_label" app:layout_constraintStart_toEndOf="@id/discount_label" app:layout_constraintTop_toTopOf="@id/discount_label" - app:srcCompat="@drawable/deprecated_ic_info_outline_24dp" /> + app:srcCompat="@drawable/ic_deprecated_info_outline_24dp" /> Date: Thu, 7 Jul 2022 08:26:43 -0300 Subject: [PATCH 172/173] Fix navgraph action --- .../src/main/res/navigation/nav_graph_card_reader_flow.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/res/navigation/nav_graph_card_reader_flow.xml b/WooCommerce/src/main/res/navigation/nav_graph_card_reader_flow.xml index 18c925a0821..843985f17d8 100644 --- a/WooCommerce/src/main/res/navigation/nav_graph_card_reader_flow.xml +++ b/WooCommerce/src/main/res/navigation/nav_graph_card_reader_flow.xml @@ -74,7 +74,7 @@ Date: Thu, 7 Jul 2022 15:28:21 +0200 Subject: [PATCH 173/173] Exclude tracks experiments dependency from dependabot --- .github/dependabot.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b565ff00f0c..aea3409cc8b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -22,3 +22,4 @@ updates: - dependency-name: "org.wordpress.fluxc.plugins:woocommerce" - dependency-name: "org.wordpress:login" - dependency-name: "com.automattic:Automattic-Tracks-Android" + - dependency-name: "com.automattic.tracks:experimentation"