From d82215b6dcd7748e658f31e5cb26076fb571fa49 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Wed, 17 Jan 2024 10:14:35 +0100 Subject: [PATCH 01/53] Bump React Native version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2e48dcf200d7..72ed3b55e209 100644 --- a/build.gradle +++ b/build.gradle @@ -87,7 +87,7 @@ ext { zendeskVersion = '5.1.2' // react native - facebookReactVersion = '0.71.11' + facebookReactVersion = '0.71.15' // test assertjVersion = '3.23.1' From 01e0bf8a0dd3bcfdd22af68ff36e43b56ade68eb Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Wed, 17 Jan 2024 10:14:45 +0100 Subject: [PATCH 02/53] Update Gutenberg Mobile ref --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 72ed3b55e209..dd21103445b8 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ ext { automatticRestVersion = '1.0.8' automatticStoriesVersion = '2.4.0' automatticTracksVersion = '3.3.0' - gutenbergMobileVersion = 'v1.111.0-alpha2' + gutenbergMobileVersion = '6522-6f8c346ef8a182d8ece2c4f041392f7f8962f9e4' wordPressAztecVersion = 'v1.9.0' wordPressFluxCVersion = '2.61.0' wordPressLoginVersion = '1.10.0' From 5fd198164e13a9db78962a2584f7cac93d68dfea Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Thu, 25 Jan 2024 18:54:15 +0200 Subject: [PATCH 03/53] Disables saving react root view from parent --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5cb7f225ec83..5dfe04128efc 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ ext { automatticRestVersion = '1.0.8' automatticStoriesVersion = '2.4.0' automatticTracksVersion = '3.3.0' - gutenbergMobileVersion = 'v1.111.1' + gutenbergMobileVersion = '6575-ce96b678ecac7bfba81c20f2642c305164db9301' wordPressAztecVersion = 'v1.9.0' wordPressFluxCVersion = '2.61.0' wordPressLoginVersion = '1.10.0' From ce3cda92cf2aefdc24657c3c71ed636f21e34f0e Mon Sep 17 00:00:00 2001 From: Jarvis Lin Date: Fri, 26 Jan 2024 15:25:39 +0800 Subject: [PATCH 04/53] Integrate Flipper --- WordPress/build.gradle | 14 ++++++++---- WordPress/src/debug/AndroidManifest.xml | 2 ++ .../org/wordpress/android/WordPressDebug.java | 22 ++++++++++++++++--- .../android/modules/InterceptorModule.java | 9 +++++--- build.gradle | 3 ++- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 710331e05165..ad82cea61187 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -391,10 +391,6 @@ dependencies { } implementation "org.wordpress:persistentedittext:$wordPressPersistentEditTextVersion" - // To enable Stetho, a debug bridge that enables the Chrome Developer Tools for debug purposes. - debugImplementation "com.facebook.stetho:stetho:$stethoVersion" - debugImplementation "com.facebook.stetho:stetho-okhttp3:$stethoVersion" - implementation "androidx.arch.core:core-common:$androidxArchCoreVersion" implementation "androidx.arch.core:core-runtime:$androidxArchCoreVersion" implementation "com.google.code.gson:gson:$googleGsonVersion" @@ -562,6 +558,16 @@ dependencies { // - Jetpack Compose - UI Tests androidTestImplementation "androidx.compose.ui:ui-test-junit4" implementation "androidx.compose.material3:material3:$androidxComposeMaterial3Version" + + // - Flipper + debugImplementation ("com.facebook.flipper:flipper:$flipperVersion") { + exclude group:'org.jetbrains.kotlinx', module:'kotlinx-serialization-json-jvm' + } + debugImplementation "com.facebook.soloader:soloader:$soLoaderVersion" + debugImplementation ("com.facebook.flipper:flipper-network-plugin:$flipperVersion"){ + exclude group:'org.jetbrains.kotlinx', module:'kotlinx-serialization-json-jvm' + } + releaseImplementation "com.facebook.flipper:flipper-noop:$flipperVersion" } configurations.all { diff --git a/WordPress/src/debug/AndroidManifest.xml b/WordPress/src/debug/AndroidManifest.xml index e961d134552f..f8c9e84b0392 100644 --- a/WordPress/src/debug/AndroidManifest.xml +++ b/WordPress/src/debug/AndroidManifest.xml @@ -38,5 +38,7 @@ android:name=".ui.debug.preferences.DebugSharedPreferenceFlagsActivity" android:label="@string/debug_settings_debug_flags_screen" android:theme="@style/WordPress.NoActionBar" /> + diff --git a/WordPress/src/debug/java/org/wordpress/android/WordPressDebug.java b/WordPress/src/debug/java/org/wordpress/android/WordPressDebug.java index 18c86dd485b9..8672794c9767 100644 --- a/WordPress/src/debug/java/org/wordpress/android/WordPressDebug.java +++ b/WordPress/src/debug/java/org/wordpress/android/WordPressDebug.java @@ -2,7 +2,14 @@ import android.os.StrictMode; -import com.facebook.stetho.Stetho; +import com.facebook.flipper.android.AndroidFlipperClient; +import com.facebook.flipper.android.utils.FlipperUtils; +import com.facebook.flipper.core.FlipperClient; +import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; +import com.facebook.flipper.plugins.inspector.DescriptorMapping; +import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; +import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; +import com.facebook.soloader.SoLoader; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.AppLog.T; @@ -11,14 +18,23 @@ @HiltAndroidApp public class WordPressDebug extends WordPressApp { + public static final NetworkFlipperPlugin NETWORK_FLIPPER_PLUGIN = new NetworkFlipperPlugin(); @Override public void onCreate() { super.onCreate(); // enableStrictMode() - // Init Stetho - Stetho.initializeWithDefaults(this); + // init Flipper + SoLoader.init(this, false); + + if (BuildConfig.DEBUG && FlipperUtils.shouldEnableFlipper(this)) { + final FlipperClient client = AndroidFlipperClient.getInstance(this); + client.addPlugin(new InspectorFlipperPlugin(this, DescriptorMapping.withDefaults())); + client.addPlugin(NETWORK_FLIPPER_PLUGIN); + client.addPlugin(new DatabasesFlipperPlugin(this)); + client.start(); + } } /** diff --git a/WordPress/src/debug/java/org/wordpress/android/modules/InterceptorModule.java b/WordPress/src/debug/java/org/wordpress/android/modules/InterceptorModule.java index cba40b8795c0..a3fff589ff72 100644 --- a/WordPress/src/debug/java/org/wordpress/android/modules/InterceptorModule.java +++ b/WordPress/src/debug/java/org/wordpress/android/modules/InterceptorModule.java @@ -1,6 +1,8 @@ package org.wordpress.android.modules; -import com.facebook.stetho.okhttp3.StethoInterceptor; +import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; + +import org.wordpress.android.WordPressDebug; import javax.inject.Named; @@ -11,11 +13,12 @@ import dagger.multibindings.IntoSet; import okhttp3.Interceptor; + @InstallIn(SingletonComponent.class) @Module public class InterceptorModule { @Provides @IntoSet @Named("network-interceptors") - public Interceptor provideStethoInterceptor() { - return new StethoInterceptor(); + public Interceptor provideFlipperInterceptor() { + return new FlipperOkhttpInterceptor(WordPressDebug.NETWORK_FLIPPER_PLUGIN); } } diff --git a/build.gradle b/build.gradle index 5cb7f225ec83..42109a395199 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,8 @@ ext { indexosMediaForMobileVersion = '43a9026f0973a2f0a74fa813132f6a16f7499c3a' // debug - stethoVersion = '1.6.0' + flipperVersion = '0.245.0' + soLoaderVersion = '0.10.5' // main androidInstallReferrerVersion = '2.2' From 1224b53a09cd471124e38affa98092e115f442e9 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Fri, 26 Jan 2024 13:30:17 +0200 Subject: [PATCH 05/53] Adds release note --- RELEASE-NOTES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index e835d3e7d3e2..78ebafcb858a 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -2,7 +2,7 @@ 24.2 ----- - +* [**] Fix editor crash occurring on large posts [https://github.com/wordpress-mobile/WordPress-Android/pull/20046] 24.1 ----- From 1b254adc28ed06e4266ff21e74f95c73dd573d02 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Mon, 29 Jan 2024 20:55:04 +0300 Subject: [PATCH 06/53] Make dateSelector parameter nullable in `StatsViewAllViewModel` --- .../ui/stats/refresh/StatsViewAllFragment.kt | 2 +- .../ui/stats/refresh/StatsViewAllViewModel.kt | 24 +++++------ .../refresh/StatsViewAllViewModelFactory.kt | 40 ++++++++----------- 3 files changed, 30 insertions(+), 36 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllFragment.kt index 952113eb5ee0..65af0a803741 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllFragment.kt @@ -240,7 +240,7 @@ class StatsViewAllFragment : Fragment(R.layout.stats_view_all_fragment) { navigator.navigate(activity, target) }) - viewModel.selectedDate.observe(viewLifecycleOwner, { event -> + viewModel.selectedDate?.observe(viewLifecycleOwner, { event -> if (event != null) { viewModel.onDateChanged() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModel.kt index 57785b26a6be..73de971c26d3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModel.kt @@ -20,8 +20,8 @@ import org.wordpress.android.ui.stats.refresh.lists.sections.granular.SelectedDa import org.wordpress.android.ui.stats.refresh.utils.StatsDateSelector import org.wordpress.android.ui.stats.refresh.utils.StatsSiteProvider import org.wordpress.android.ui.utils.UiString.UiStringRes -import org.wordpress.android.util.mapSafe import org.wordpress.android.util.mapNullable +import org.wordpress.android.util.mapSafe import org.wordpress.android.util.throttle import org.wordpress.android.viewmodel.Event import org.wordpress.android.viewmodel.ScopedViewModel @@ -31,14 +31,14 @@ class StatsViewAllViewModel( val bgDispatcher: CoroutineDispatcher, val useCase: BaseStatsUseCase<*, *>, private val statsSiteProvider: StatsSiteProvider, - private val dateSelector: StatsDateSelector, + private val dateSelector: StatsDateSelector?, @StringRes val title: Int ) : ScopedViewModel(mainDispatcher) { - val selectedDate = dateSelector.selectedDate + val selectedDate = dateSelector?.selectedDate - val dateSelectorData: LiveData = dateSelector.dateSelectorData.mapNullable { + val dateSelectorData: LiveData = dateSelector?.dateSelectorData?.mapNullable { it ?: DateSelectorUiModel(false) - } + } ?: MutableLiveData(DateSelectorUiModel(false)) val navigationTarget: LiveData> = useCase.navigationTarget @@ -62,12 +62,12 @@ class StatsViewAllViewModel( fun start(startDate: SelectedDate?) { launch { startDate?.let { - dateSelector.start(startDate) + dateSelector?.start(startDate) } loadData(refresh = false, forced = false) - dateSelector.updateDateSelector() + dateSelector?.updateDateSelector() } - dateSelector.updateDateSelector() + dateSelector?.updateDateSelector() } @SuppressLint("NullSafeMutableLiveData") @@ -109,13 +109,13 @@ class StatsViewAllViewModel( fun onNextDateSelected() { launch(mainDispatcher) { - dateSelector.onNextDateSelected() + dateSelector?.onNextDateSelected() } } fun onPreviousDateSelected() { launch(mainDispatcher) { - dateSelector.onPreviousDateSelected() + dateSelector?.onPreviousDateSelected() } } @@ -131,7 +131,7 @@ class StatsViewAllViewModel( } } - fun getSelectedDate(): SelectedDate { - return dateSelector.getSelectedDate() + fun getSelectedDate(): SelectedDate? { + return dateSelector?.getSelectedDate() } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModelFactory.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModelFactory.kt index 167735228b8c..463afd2eee92 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModelFactory.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModelFactory.kt @@ -30,7 +30,6 @@ import org.wordpress.android.ui.stats.StatsViewType.TAGS_AND_CATEGORIES import org.wordpress.android.ui.stats.StatsViewType.TOP_POSTS_AND_PAGES import org.wordpress.android.ui.stats.StatsViewType.VIDEO_PLAYS import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.INSIGHTS import org.wordpress.android.ui.stats.refresh.lists.detail.PostAverageViewsPerDayUseCase import org.wordpress.android.ui.stats.refresh.lists.detail.PostMonthsAndYearsUseCase import org.wordpress.android.ui.stats.refresh.lists.detail.PostRecentWeeksUseCase @@ -66,7 +65,7 @@ class StatsViewAllViewModelFactory( private val bgDispatcher: CoroutineDispatcher, private val useCase: BaseStatsUseCase<*, *>, private val statsSiteProvider: StatsSiteProvider, - private val dateSelector: StatsDateSelector, + private val dateSelector: StatsDateSelector?, @StringRes private val titleResource: Int ) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { @@ -92,34 +91,29 @@ class StatsViewAllViewModelFactory( private val statsSiteProvider: StatsSiteProvider, private val dateSelectorFactory: StatsDateSelector.Factory ) { - fun build(type: StatsViewType, granularity: StatsGranularity?): StatsViewAllViewModelFactory { - return when { - type == ANNUAL_STATS -> buildAnnualStatsFactory() - granularity == null -> buildFactory(type) - else -> buildFactory(type, granularity) - } - } - - private fun buildFactory(type: StatsViewType, granularity: StatsGranularity): StatsViewAllViewModelFactory { - val (useCase, title) = getGranularUseCase(type, granularity, granularFactories) - return StatsViewAllViewModelFactory( - mainDispatcher, - bgDispatcher, - useCase, - statsSiteProvider, - dateSelectorFactory.build(granularity.toStatsSection()), - title - ) + fun build(type: StatsViewType, granularity: StatsGranularity?) = if (type == ANNUAL_STATS) { + buildAnnualStatsFactory() + } else { + buildFactory(type, granularity) } - private fun buildFactory(type: StatsViewType): StatsViewAllViewModelFactory { - val (useCase, title) = getInsightsUseCase(type, insightsUseCases) + private fun buildFactory(type: StatsViewType, granularity: StatsGranularity?): StatsViewAllViewModelFactory { + val (useCase, title) = if (granularity == null) { + getInsightsUseCase(type, insightsUseCases) + } else { + getGranularUseCase(type, granularity, granularFactories) + } + val dateSelector = if (granularity == null) { + null + } else { + dateSelectorFactory.build(granularity.toStatsSection()) + } return StatsViewAllViewModelFactory( mainDispatcher, bgDispatcher, useCase, statsSiteProvider, - dateSelectorFactory.build(INSIGHTS), + dateSelector, title ) } From 71322d6c4008a89debc793912a961d9b244d7231 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Mon, 29 Jan 2024 20:59:37 +0300 Subject: [PATCH 07/53] Move lambda arguments out of parentheses in `StatsViewAllFragment` --- .../ui/stats/refresh/StatsViewAllFragment.kt | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllFragment.kt index 65af0a803741..80d8688c73a7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllFragment.kt @@ -191,17 +191,17 @@ class StatsViewAllFragment : Fragment(R.layout.stats_view_all_fragment) { } private fun StatsViewAllFragmentBinding.setupObservers(activity: FragmentActivity) { - viewModel.isRefreshing.observe(viewLifecycleOwner, { + viewModel.isRefreshing.observe(viewLifecycleOwner) { it?.let { isRefreshing -> swipeToRefreshHelper.isRefreshing = isRefreshing } - }) + } - viewModel.showSnackbarMessage.observeEvent(viewLifecycleOwner, { holder -> + viewModel.showSnackbarMessage.observeEvent(viewLifecycleOwner) { holder -> showSnackbar(activity, holder) - }) + } - viewModel.data.observe(viewLifecycleOwner, { + viewModel.data.observe(viewLifecycleOwner) { if (it != null) { with(statsListFragment) { recyclerView.visibility = if (it is Success) View.VISIBLE else View.GONE @@ -214,41 +214,44 @@ class StatsViewAllFragment : Fragment(R.layout.stats_view_all_fragment) { is Success -> { loadData(recyclerView, prepareLayout(it.data, it.type)) } + is Loading -> { loadData(loadingRecyclerView, prepareLayout(it.data, it.type)) } + is Error -> { errorView.statsErrorView.button.setOnClickListener { viewModel.onRetryClick() } } + is EmptyBlock -> { } } } } - }) - viewModel.navigationTarget.observeEvent(viewLifecycleOwner, { target -> + } + viewModel.navigationTarget.observeEvent(viewLifecycleOwner) { target -> navigator.navigate(activity, target) - }) + } - viewModel.dateSelectorData.observe(viewLifecycleOwner, { dateSelectorUiModel -> + viewModel.dateSelectorData.observe(viewLifecycleOwner) { dateSelectorUiModel -> statsListFragment.drawDateSelector(dateSelectorUiModel) - }) + } - viewModel.navigationTarget.observeEvent(viewLifecycleOwner, { target -> + viewModel.navigationTarget.observeEvent(viewLifecycleOwner) { target -> navigator.navigate(activity, target) - }) + } - viewModel.selectedDate?.observe(viewLifecycleOwner, { event -> + viewModel.selectedDate?.observe(viewLifecycleOwner) { event -> if (event != null) { viewModel.onDateChanged() } - }) + } - viewModel.toolbarHasShadow.observe(viewLifecycleOwner, { hasShadow -> + viewModel.toolbarHasShadow.observe(viewLifecycleOwner) { hasShadow -> appBarLayout.showShadow(hasShadow == true) - }) + } } private fun showSnackbar( From 964fd10b6de5c0c3cd6d12484235fe190a0ab323 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Tue, 30 Jan 2024 15:02:11 +0530 Subject: [PATCH 08/53] + Adds: model to loaded state --- .../wordpress/android/ui/sitemonitor/SiteMonitorUiState.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUiState.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUiState.kt index 50bca3c0dec8..7bdbae624d3f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUiState.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUiState.kt @@ -10,7 +10,9 @@ sealed class SiteMonitorUiState { val model: SiteMonitorModel ) : SiteMonitorUiState() - object Loaded : SiteMonitorUiState() + data class Loaded( + val model: SiteMonitorModel + ) : SiteMonitorUiState() open class Error( val title: UiString, From ae9ca81a7cf54cf9676a060a2c29d70eb4252993 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Tue, 30 Jan 2024 15:02:37 +0530 Subject: [PATCH 09/53] =?UTF-8?q?=E2=86=91=20Updates:=20the=20webview=20cl?= =?UTF-8?q?ient=20to=20use=20tab=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/sitemonitor/SiteMonitorWebViewClient.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClient.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClient.kt index 29305e0d2ea0..9938522b782d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClient.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClient.kt @@ -1,19 +1,22 @@ package org.wordpress.android.ui.sitemonitor import android.graphics.Bitmap +import android.util.Log import android.webkit.WebResourceError import android.webkit.WebResourceRequest import android.webkit.WebView import android.webkit.WebViewClient class SiteMonitorWebViewClient( - private val listener: SiteMonitorWebViewClientListener + private val listener: SiteMonitorWebViewClientListener, + private val tabType: SiteMonitorType ) : WebViewClient() { private var errorReceived = false private var requestedUrl: String? = null + interface SiteMonitorWebViewClientListener { - fun onWebViewPageLoaded(url: String) - fun onWebViewReceivedError(url: String) + fun onWebViewPageLoaded(url: String, tabType: SiteMonitorType) + fun onWebViewReceivedError(url: String, tabType: SiteMonitorType) } override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { return false @@ -26,9 +29,10 @@ class SiteMonitorWebViewClient( } override fun onPageFinished(view: WebView, url: String?) { + Log.e("Site Monitor Webview client", "onPageFinished: $url") super.onPageFinished(view, url) if (!errorReceived) { - url?.let { listener.onWebViewPageLoaded(it) } + url?.let { listener.onWebViewPageLoaded(it, tabType) } } } @@ -40,7 +44,7 @@ class SiteMonitorWebViewClient( // > Thus, it is recommended to perform minimum required work in this callback. if (request?.isForMainFrame == true && requestedUrl == request.url.toString()) { errorReceived = true - listener.onWebViewReceivedError(request.url.toString()) + listener.onWebViewReceivedError(request.url.toString(), tabType) } } } From 236b45044cdb36f583b6959501f6e36e8fc4e711 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Tue, 30 Jan 2024 15:04:11 +0530 Subject: [PATCH 10/53] + Adds: SiteMonitorParentViewModel --- .../sitemonitor/SiteMonitorParentViewModel.kt | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt new file mode 100644 index 000000000000..b430397116d6 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt @@ -0,0 +1,91 @@ +package org.wordpress.android.ui.sitemonitor + +import androidx.compose.runtime.MutableState +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.CoroutineDispatcher +import org.wordpress.android.analytics.AnalyticsTracker +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.modules.BG_THREAD +import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper +import org.wordpress.android.viewmodel.ScopedViewModel +import javax.inject.Inject +import javax.inject.Named + +@HiltViewModel +class SiteMonitorParentViewModel @Inject constructor( + @param:Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, + private val analyticsTrackerWrapper: AnalyticsTrackerWrapper, + private val metricsViewModel: SiteMonitorTabViewModelSlice, + private val phpLogViewModel: SiteMonitorTabViewModelSlice, + private val webServerViewModel: SiteMonitorTabViewModelSlice +) : ScopedViewModel(bgDispatcher) { + private lateinit var site: SiteModel + + init { + metricsViewModel.initialize(viewModelScope) + phpLogViewModel.initialize(viewModelScope) + webServerViewModel.initialize(viewModelScope) + } + + fun start(site: SiteModel) { + this.site = site + trackActivityLaunched() + metricsViewModel.start(SiteMonitorType.METRICS, SiteMonitorTabItem.Metrics.urlTemplate, site) + phpLogViewModel.start(SiteMonitorType.PHP_LOGS, SiteMonitorTabItem.PHPLogs.urlTemplate, site) + webServerViewModel.start(SiteMonitorType.WEB_SERVER_LOGS, SiteMonitorTabItem.WebServerLogs.urlTemplate, site) + } + + fun getUiState(siteMonitorType: SiteMonitorType): MutableState { + return when (siteMonitorType) { + SiteMonitorType.METRICS -> { + metricsViewModel.uiState + } + SiteMonitorType.PHP_LOGS -> { + phpLogViewModel.uiState + } + SiteMonitorType.WEB_SERVER_LOGS -> { + webServerViewModel.uiState + } + } + } + + fun onUrlLoaded(siteMonitorType: SiteMonitorType, url: String) { + when (siteMonitorType) { + SiteMonitorType.METRICS -> { + metricsViewModel.onUrlLoaded(url) + } + SiteMonitorType.PHP_LOGS -> { + phpLogViewModel.onUrlLoaded(url) + } + SiteMonitorType.WEB_SERVER_LOGS -> { + webServerViewModel.onUrlLoaded(url) + } + } + } + + fun onWebViewError(siteMonitorType: SiteMonitorType) { + when (siteMonitorType) { + SiteMonitorType.METRICS -> { + metricsViewModel.onWebViewError() + } + SiteMonitorType.PHP_LOGS -> { + phpLogViewModel.onWebViewError() + } + SiteMonitorType.WEB_SERVER_LOGS -> { + webServerViewModel.onWebViewError() + } + } + } + + private fun trackActivityLaunched() { + analyticsTrackerWrapper.track(AnalyticsTracker.Stat.SITE_MONITORING_SCREEN_SHOWN) + } + + override fun onCleared() { + super.onCleared() + metricsViewModel.onCleared() + phpLogViewModel.onCleared() + webServerViewModel.onCleared() + } +} From 586e3ed7207b8fc391445a452cc32db405a0f2a7 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Tue, 30 Jan 2024 15:04:33 +0530 Subject: [PATCH 11/53] =?UTF-8?q?=E2=86=91=20Updates:=20the=20logic=20in?= =?UTF-8?q?=20activity=20to=20use=20tabs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sitemonitor/SiteMonitorParentActivity.kt | 205 +++++++++++++----- 1 file changed, 148 insertions(+), 57 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index c2118117baf2..020bd6f5d857 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -2,38 +2,56 @@ package org.wordpress.android.ui.sitemonitor import android.annotation.SuppressLint import android.os.Bundle +import android.util.Log import android.util.SparseArray +import android.view.View +import android.view.ViewGroup +import android.webkit.WebView import androidx.activity.compose.setContent +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material.Scaffold +import androidx.compose.material.Button +import androidx.compose.material.MaterialTheme +import androidx.compose.material.TabRow +import androidx.compose.material.Text import androidx.compose.material3.Surface +import androidx.compose.material3.Tab import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentTransaction import dagger.hilt.android.AndroidEntryPoint import org.wordpress.android.R import org.wordpress.android.WordPress import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.ui.compose.components.MainTopAppBar -import org.wordpress.android.ui.compose.components.NavigationIcons +import org.wordpress.android.ui.WPWebViewActivity import org.wordpress.android.ui.compose.theme.AppTheme +import org.wordpress.android.ui.compose.utils.uiStringText import org.wordpress.android.util.extensions.getSerializableExtraCompat @AndroidEntryPoint -class SiteMonitorParentActivity: AppCompatActivity() { +class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient.SiteMonitorWebViewClientListener { private var savedStateSparseArray = SparseArray() private var currentSelectItemId = 0 + private val siteMonitorParentViewModel: SiteMonitorParentViewModel by viewModels() + @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -43,6 +61,8 @@ class SiteMonitorParentActivity: AppCompatActivity() { ) ?: savedStateSparseArray currentSelectItemId = savedInstanceState.getInt(SAVED_STATE_CURRENT_TAB_KEY) + } else { + siteMonitorParentViewModel.start(getSite()) } setContent { AppTheme { @@ -78,66 +98,137 @@ class SiteMonitorParentActivity: AppCompatActivity() { @Composable @SuppressLint("UnusedMaterialScaffoldPaddingParameter") - fun SiteMonitorScreen() { - var selectedTab by rememberSaveable { mutableStateOf(SiteMonitorTabItem.Metrics.route) } - Scaffold( - topBar = { - MainTopAppBar( - title = stringResource(id = R.string.site_monitoring), - navigationIcon = NavigationIcons.BackIcon, - onNavigationIconClick = onBackPressedDispatcher::onBackPressed, - ) - } - ) { padding -> - Column(modifier = Modifier.padding(padding)) { - SiteMonitorTabHeader { clickTab -> - selectedTab = clickTab - } - SiteMonitorTabNavigation(selectedTab) { selectedTab -> - val item = enumValues().find { - it.route == selectedTab - } ?: initialItem(getInitialTab()) - - SiteMonitorFragmentContainer( - modifier = Modifier.fillMaxSize(), - commit = getCommitFunction( - SiteMonitorTabFragment.newInstance(item.urlTemplate, item.siteMonitorType, getSite()), - item.route - ) + fun SiteMonitorScreen(modifier: Modifier = Modifier) { + var tabIndex by remember { mutableStateOf(0) } + + val tabs = listOf( + R.string.site_monitoring_tab_title_metrics, + R.string.site_monitoring_tab_title_php_logs, + R.string.site_monitoring_tab_title_web_server_logs + ) + + Column(modifier = modifier.fillMaxWidth()) { + TabRow( + selectedTabIndex = tabIndex, + backgroundColor = MaterialTheme.colors.surface, + contentColor = MaterialTheme.colors.onSurface, + ) { + tabs.forEachIndexed { index, title -> + Tab(text = { Text(stringResource(id = title)) }, + selected = tabIndex == index, + onClick = { tabIndex = index } ) } } + when (tabIndex) { + 0 -> SiteMonitorTabContent(SiteMonitorType.METRICS, modifier) + 1 -> SiteMonitorTabContent(SiteMonitorType.PHP_LOGS, modifier) + 2 -> SiteMonitorTabContent(SiteMonitorType.WEB_SERVER_LOGS, modifier) + } } } - private fun initialItem(type: SiteMonitorType): SiteMonitorTabItem { - return enumValues().find { - it.siteMonitorType == type - } ?: SiteMonitorTabItem.Metrics + @Composable + private fun SiteMonitorTabContent(tabType: SiteMonitorType, modifier: Modifier) { + val uiState by remember(key1 = tabType) { + siteMonitorParentViewModel.getUiState(tabType) + } + when (uiState) { + is SiteMonitorUiState.Preparing -> LoadingState(modifier) + is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> + SiteMonitorWebView(uiState, tabType, modifier) + is SiteMonitorUiState.Error -> SiteMonitorError(uiState as SiteMonitorUiState.Error, modifier) + } } - private fun getCommitFunction( - fragment : Fragment, - tag: String - ): FragmentTransaction.(containerId: Int) -> Unit = - { - saveAndRetrieveFragment(supportFragmentManager, it, fragment) - replace(it, fragment, tag) + @Composable + fun SiteMonitorError(error: SiteMonitorUiState.Error, modifier: Modifier = Modifier) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = modifier + .padding(20.dp) + .fillMaxWidth() + .fillMaxHeight(), + ) { + androidx.compose.material.Text( + text = uiStringText(uiString = error.title), + style = androidx.compose.material.MaterialTheme.typography.h5, + textAlign = TextAlign.Center + ) + androidx.compose.material.Text( + text = uiStringText(uiString = error.description), + style = androidx.compose.material.MaterialTheme.typography.body1, + textAlign = TextAlign.Center, + modifier = Modifier.padding(top = 8.dp) + ) + if (error.button != null) { + Button( + modifier = Modifier.padding(top = 8.dp), + onClick = error.button.click + ) { + Text(text = uiStringText(uiString = error.button.text)) + } + } } + } - private fun saveAndRetrieveFragment( - supportFragmentManager: FragmentManager, - tabId: Int, - fragment: Fragment - ) { - val currentFragment = supportFragmentManager.findFragmentById(currentSelectItemId) - if (currentFragment != null) { - savedStateSparseArray.put( - currentSelectItemId, - supportFragmentManager.saveFragmentInstanceState(currentFragment) - ) + @SuppressLint("SetJavaScriptEnabled") + @Composable + private fun SiteMonitorWebView(uiState: SiteMonitorUiState, tabType: SiteMonitorType, modifier: Modifier) { + Log.e("Track", "SiteMonitorWebView $uiState") + var webView: WebView? by remember { mutableStateOf(null) } + + Log.e("Track", "SiteMonitorWebView $webView") + + val model = when (uiState) { + is SiteMonitorUiState.Prepared -> uiState.model + is SiteMonitorUiState.Loaded -> uiState.model + else -> null + } + + model?.let { + LaunchedEffect(true) { + webView = WebView(this@SiteMonitorParentActivity).apply { + layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY + settings.userAgentString = model.userAgent + settings.javaScriptEnabled = true + settings.domStorageEnabled = true + webViewClient = SiteMonitorWebViewClient(this@SiteMonitorParentActivity, tabType) + } + } + if(uiState is SiteMonitorUiState.Prepared) { + webView?.postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, model.addressToLoad.toByteArray()) + } else { + webView?.loadUrl(model.url) + } + } + + Box( + modifier = modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + if (uiState is SiteMonitorUiState.Prepared) { + LoadingState() + } else { + webView?.let { theWebView -> + AndroidView( + factory = { theWebView }, + update = { webView = it }, + modifier = Modifier.fillMaxSize() + ) + } + } } - currentSelectItemId = tabId - fragment.setInitialSavedState(savedStateSparseArray[currentSelectItemId]) } + + override fun onWebViewPageLoaded(url: String, tabType: SiteMonitorType) = + siteMonitorParentViewModel.onUrlLoaded(tabType, url) + + override fun onWebViewReceivedError(url: String, tabType: SiteMonitorType) = + siteMonitorParentViewModel.onWebViewError(tabType) } From 84d25bfd665432c13cdd87bcb060c6feaefcb229 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Tue, 30 Jan 2024 15:05:20 +0530 Subject: [PATCH 12/53] =?UTF-8?q?=E2=86=91=20Updates:=20the=20site=20monit?= =?UTF-8?q?or=20tab=20view=20model=20to=20use=20state=20flow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/sitemonitor/SiteMonitorTabViewModel.kt | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt index aaae3507f424..aebbb08c9423 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt @@ -2,34 +2,34 @@ package org.wordpress.android.ui.sitemonitor import android.text.TextUtils import android.util.Log -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow +import androidx.compose.runtime.mutableStateOf +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.AccountStore import org.wordpress.android.fluxc.store.SiteStore -import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.util.NetworkUtilsWrapper -import org.wordpress.android.viewmodel.ScopedViewModel import javax.inject.Inject -import javax.inject.Named - -@HiltViewModel -class SiteMonitorTabViewModel @Inject constructor( - @param:Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, +class SiteMonitorTabViewModelSlice @Inject constructor( private val networkUtilsWrapper: NetworkUtilsWrapper, private val accountStore: AccountStore, private val mapper: SiteMonitorMapper, private val siteMonitorUtils: SiteMonitorUtils, private val siteStore: SiteStore, -) : ScopedViewModel(bgDispatcher) { +){ + private lateinit var scope: CoroutineScope + private lateinit var site: SiteModel private lateinit var siteMonitorType: SiteMonitorType private lateinit var urlTemplate: String - private val _uiState = MutableStateFlow(SiteMonitorUiState.Preparing) - val uiState: StateFlow = _uiState + private val _uiState = mutableStateOf(SiteMonitorUiState.Preparing) + val uiState = _uiState + + fun initialize(scope: CoroutineScope) { + this.scope = scope + } fun start(type: SiteMonitorType, urlTemplate: String, site: SiteModel) { Log.i("Track", "TheViewModel start with $urlTemplate and $type") @@ -52,13 +52,13 @@ class SiteMonitorTabViewModel @Inject constructor( private fun checkForInternetConnectivityAndPostErrorIfNeeded() : Boolean { if (networkUtilsWrapper.isNetworkAvailable()) return true - postUiState(mapper.toNoNetworkError(this@SiteMonitorTabViewModel::loadView)) + postUiState(mapper.toNoNetworkError(::loadView)) return false } private fun validateAndPostErrorIfNeeded(): Boolean { if (accountStore.account.userName.isNullOrEmpty() || accountStore.accessToken.isNullOrEmpty()) { - postUiState(mapper.toGenericError(this@SiteMonitorTabViewModel::loadView)) + postUiState(mapper.toGenericError(this::loadView)) return false } return true @@ -100,18 +100,28 @@ class SiteMonitorTabViewModel @Inject constructor( } private fun postUiState(state: SiteMonitorUiState) { - launch { + scope.launch { _uiState.value = state } } - fun onUrlLoaded() { + fun onUrlLoaded(url: String) { + Log.i("Track", "TheViewModel onUrlLoaded $url") siteMonitorUtils.trackTabLoaded(siteMonitorType) - postUiState(SiteMonitorUiState.Loaded) + if (uiState.value is SiteMonitorUiState.Prepared){ + postUiState(SiteMonitorUiState + .Loaded((_uiState.value as SiteMonitorUiState.Prepared).model.copy(url = url))) + } } + fun onWebViewError() { - postUiState(mapper.toGenericError(this@SiteMonitorTabViewModel::loadView)) + postUiState(mapper.toGenericError(::loadView)) + } + + fun onCleared() { + Log.i("Track", "TheViewModel onCleared") + scope.cancel() } companion object { From d73c94216d5da235b5e7e4bb548ccdfbfae3db26 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Tue, 30 Jan 2024 15:05:59 +0530 Subject: [PATCH 13/53] =?UTF-8?q?=E2=86=91=20Updates:=20the=20fragment=20t?= =?UTF-8?q?o=20use=20loaded=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/sitemonitor/SiteMonitorTabFragment.kt | 57 ++++++++++++------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabFragment.kt index 8fb61cc8ed03..841612550ae8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabFragment.kt @@ -2,6 +2,7 @@ package org.wordpress.android.ui.sitemonitor import android.annotation.SuppressLint import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -17,7 +18,6 @@ import androidx.compose.material.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -29,7 +29,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels +import androidx.fragment.app.activityViewModels import dagger.hilt.android.AndroidEntryPoint import org.wordpress.android.WordPress import org.wordpress.android.fluxc.model.SiteModel @@ -38,6 +38,11 @@ import org.wordpress.android.ui.compose.utils.uiStringText @AndroidEntryPoint class SiteMonitorTabFragment : Fragment(), SiteMonitorWebViewClient.SiteMonitorWebViewClientListener { + val tabType by lazy { getSiteMonitorType() } + + private val siteMonitorWebViewClient = SiteMonitorWebViewClient(this@SiteMonitorTabFragment, SiteMonitorType.PHP_LOGS) + + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -47,20 +52,14 @@ class SiteMonitorTabFragment : Fragment(), SiteMonitorWebViewClient.SiteMonitorW } } - private val viewModel: SiteMonitorTabViewModel by viewModels() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initViewModel(getSiteMonitorType(), getUrlTemplate(), getSite()) + override fun onResume() { + super.onResume() } - @Suppress("DEPRECATION") - private fun getSite(): SiteModel { - return requireNotNull(arguments?.getSerializable(WordPress.SITE)) as SiteModel - } + private val viewModel: SiteMonitorParentViewModel by activityViewModels() - private fun getUrlTemplate(): String { - return requireNotNull(arguments?.getString(KEY_URL_TEMPLATE)) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) } @Suppress("DEPRECATION") @@ -68,13 +67,11 @@ class SiteMonitorTabFragment : Fragment(), SiteMonitorWebViewClient.SiteMonitorW return requireNotNull(arguments?.getSerializable(KEY_SITE_MONITOR_TYPE)) as SiteMonitorType } - private fun initViewModel(type: SiteMonitorType, urlTemplate: String, site: SiteModel) { - viewModel.start(type, urlTemplate, site) - } - - override fun onWebViewPageLoaded(url: String) = viewModel.onUrlLoaded() + override fun onWebViewPageLoaded(url: String, tabType: SiteMonitorType) = + viewModel.onUrlLoaded(tabType, url) - override fun onWebViewReceivedError(url: String) = viewModel.onWebViewError() + override fun onWebViewReceivedError(url: String, tabType: SiteMonitorType) = + viewModel.onWebViewError(tabType) companion object { const val KEY_URL_TEMPLATE = "KEY_URL" @@ -92,7 +89,7 @@ class SiteMonitorTabFragment : Fragment(), SiteMonitorWebViewClient.SiteMonitorW @Composable private fun SiteMonitorTabContent() { - val uiState by viewModel.uiState.collectAsState() + val uiState by viewModel.getUiState(tabType) when (uiState) { is SiteMonitorUiState.Preparing -> LoadingState() is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitorWebView(uiState) @@ -135,8 +132,11 @@ class SiteMonitorTabFragment : Fragment(), SiteMonitorWebViewClient.SiteMonitorW @SuppressLint("SetJavaScriptEnabled") @Composable private fun SiteMonitorWebView(uiState: SiteMonitorUiState) { + Log.e("Track", "SiteMonitorWebView $uiState") var webView: WebView? by remember { mutableStateOf(null) } + Log.e("Track", "SiteMonitorWebView $webView") + if (uiState is SiteMonitorUiState.Prepared) { val model = uiState.model LaunchedEffect(true) { @@ -149,10 +149,25 @@ class SiteMonitorTabFragment : Fragment(), SiteMonitorWebViewClient.SiteMonitorW settings.userAgentString = model.userAgent settings.javaScriptEnabled = true settings.domStorageEnabled = true - webViewClient = SiteMonitorWebViewClient(this@SiteMonitorTabFragment) + webViewClient = SiteMonitorWebViewClient(this@SiteMonitorTabFragment, SiteMonitorType.PHP_LOGS) postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, model.addressToLoad.toByteArray()) } } + } else if (uiState is SiteMonitorUiState.Loaded) { + val model = uiState.model + LaunchedEffect(true) { + webView = WebView(requireContext()).apply { + layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY + settings.userAgentString = model.userAgent + settings.javaScriptEnabled = true + settings.domStorageEnabled = true + loadUrl(model.url) + } + } } Box( From 0a04666daf19c672b33caf416682eae748a945ed Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Tue, 30 Jan 2024 16:39:16 +0300 Subject: [PATCH 14/53] Make dateSelector parameter nullable in `StatsListViewModel` --- .../stats/refresh/lists/StatsListFragment.kt | 2 +- .../stats/refresh/lists/StatsListViewModel.kt | 18 +++++++++--------- .../lists/detail/DetailListViewModel.kt | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt index 8169b738f924..30ca269635ce 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt @@ -243,7 +243,7 @@ class StatsListFragment : ViewPagerFragment(R.layout.stats_list_fragment) { navigator.navigate(activity, target) } - viewModel.selectedDate.observe(viewLifecycleOwner) { event -> + viewModel.selectedDate?.observe(viewLifecycleOwner) { event -> if (event != null) { viewModel.onDateChanged(event.selectedSection) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt index 386a6575a3a7..a3b14286a6f8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt @@ -49,7 +49,7 @@ abstract class StatsListViewModel( defaultDispatcher: CoroutineDispatcher, private val statsUseCase: BaseListUseCase, private val analyticsTracker: AnalyticsTrackerWrapper, - protected val dateSelector: StatsDateSelector, + protected val dateSelector: StatsDateSelector?, popupMenuHandler: ItemPopupMenuHandler? = null, private val newsCardHandler: NewsCardHandler? = null, actionCardHandler: ActionCardHandler? = null @@ -72,7 +72,7 @@ abstract class StatsListViewModel( ANNUAL_STATS(R.string.stats_insights_annual_site_stats); } - val selectedDate = dateSelector.selectedDate + val selectedDate = dateSelector?.selectedDate private val mutableNavigationTarget = MutableLiveData>() val navigationTarget: LiveData> = mergeNotNull( @@ -85,9 +85,9 @@ abstract class StatsListViewModel( statsUseCase.data.throttle(viewModelScope, distinct = true) } - val dateSelectorData: LiveData = dateSelector.dateSelectorData.mapNullable { + val dateSelectorData: LiveData = dateSelector?.dateSelectorData?.mapNullable { it ?: DateSelectorUiModel(false) - } + } ?: MutableLiveData(DateSelectorUiModel(false)) val typesChanged = merge( popupMenuHandler?.typeMoved, @@ -115,13 +115,13 @@ abstract class StatsListViewModel( fun onNextDateSelected() { launch(Dispatchers.Default) { - dateSelector.onNextDateSelected() + dateSelector?.onNextDateSelected() } } fun onPreviousDateSelected() { launch(Dispatchers.Default) { - dateSelector.onPreviousDateSelected() + dateSelector?.onPreviousDateSelected() } } @@ -138,7 +138,7 @@ abstract class StatsListViewModel( } fun onListSelected() { - dateSelector.updateDateSelector() + dateSelector?.updateDateSelector() } fun onEmptyInsightsButtonClicked() { @@ -156,10 +156,10 @@ abstract class StatsListViewModel( isInitialized = true launch { statsUseCase.loadData() - dateSelector.updateDateSelector() + dateSelector?.updateDateSelector() } } - dateSelector.updateDateSelector() + dateSelector?.updateDateSelector() } sealed class UiModel { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/DetailListViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/DetailListViewModel.kt index 553ff06d2997..23199d7b74f4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/DetailListViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/DetailListViewModel.kt @@ -20,6 +20,6 @@ class DetailListViewModel ) : StatsListViewModel(mainDispatcher, detailUseCase, analyticsTracker, dateSelectorFactory.build(DETAIL)) { override fun onCleared() { super.onCleared() - dateSelector.clear() + dateSelector?.clear() } } From 1cf65082d402167b962ec3d0fb4d2ad139f43740 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Mon, 29 Jan 2024 18:00:40 +0300 Subject: [PATCH 15/53] Add `SelectedTrafficGranularityManager` for traffic tab's granularity `SelectedTrafficGranularityManager` will be used to cache granularity selection of the TRAFFIC tab. --- .../stats/refresh/lists/StatsListFragment.kt | 11 +++++++++- .../SelectedTrafficGranularityManager.kt | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedTrafficGranularityManager.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt index 30ca269635ce..4bba42e5aab9 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt @@ -27,6 +27,7 @@ import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.UiModel.E import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.UiModel.Error import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.UiModel.Success import org.wordpress.android.ui.stats.refresh.lists.detail.DetailListViewModel +import org.wordpress.android.ui.stats.refresh.utils.SelectedTrafficGranularityManager import org.wordpress.android.ui.stats.refresh.utils.StatsDateFormatter import org.wordpress.android.ui.stats.refresh.utils.StatsNavigator import org.wordpress.android.ui.stats.refresh.utils.drawDateSelector @@ -57,6 +58,9 @@ class StatsListFragment : ViewPagerFragment(R.layout.stats_list_fragment) { @Inject lateinit var statsTrafficTabFeatureConfig: StatsTrafficTabFeatureConfig + @Inject + lateinit var selectedTrafficGranularityManager: SelectedTrafficGranularityManager + private lateinit var viewModel: StatsListViewModel private lateinit var statsSection: StatsSection @@ -158,9 +162,14 @@ class StatsListFragment : ViewPagerFragment(R.layout.stats_list_fragment) { StatsGranularity.entries.map { getString(it.toNameResource()) } ).apply { setDropDownViewResource(R.layout.toolbar_spinner_dropdown_item) } + val selectedGranularityItemPos = StatsGranularity.entries.indexOf( + selectedTrafficGranularityManager.getSelectedTrafficGranularity() + ) + dateSelector.granularitySpinner.setSelection(selectedGranularityItemPos) + dateSelector.granularitySpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - // TODO update TRAFFIC tab + selectedTrafficGranularityManager.setSelectedTrafficGranularity(StatsGranularity.entries[position]) } @Suppress("EmptyFunctionBlock") diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedTrafficGranularityManager.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedTrafficGranularityManager.kt new file mode 100644 index 000000000000..c17ec67b92aa --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedTrafficGranularityManager.kt @@ -0,0 +1,20 @@ +package org.wordpress.android.ui.stats.refresh.utils + +import android.content.SharedPreferences +import org.wordpress.android.fluxc.network.utils.StatsGranularity +import org.wordpress.android.fluxc.network.utils.StatsGranularity.DAYS +import javax.inject.Inject + +const val SELECTED_TRAFFIC_GRANULARITY_KEY = "SELECTED_TRAFFIC_GRANULARITY_KEY" + +class SelectedTrafficGranularityManager +@Inject constructor(private val sharedPrefs: SharedPreferences) { + fun getSelectedTrafficGranularity(): StatsGranularity { + val value = sharedPrefs.getString(SELECTED_TRAFFIC_GRANULARITY_KEY, DAYS.name) + return value?.let { StatsGranularity.valueOf(value) } ?: DAYS + } + + fun setSelectedTrafficGranularity(selectedTrafficGranularity: StatsGranularity) { + sharedPrefs.edit().putString(SELECTED_TRAFFIC_GRANULARITY_KEY, selectedTrafficGranularity.name).apply() + } +} From 26150b995c768db71a32b490d986e00ff37cb958 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Mon, 29 Jan 2024 18:19:14 +0300 Subject: [PATCH 16/53] Add `TRAFFIC_USE_CASE` for use cases of the traffic tab --- .../android/ui/stats/refresh/StatsModule.kt | 29 +++++++++++++++++++ .../stats/refresh/lists/StatsListViewModel.kt | 15 +++++----- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt index a3cbd2848638..27115506c0c2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt @@ -67,6 +67,7 @@ import javax.inject.Named import javax.inject.Singleton const val INSIGHTS_USE_CASE = "InsightsUseCase" +const val TRAFFIC_USE_CASE = "TrafficStatsUseCase" const val DAY_STATS_USE_CASE = "DayStatsUseCase" const val WEEK_STATS_USE_CASE = "WeekStatsUseCase" const val MONTH_STATS_USE_CASE = "MonthStatsUseCase" @@ -265,6 +266,32 @@ class StatsModule { ) } + /** + * Provides a singleton usecase that represents the TRAFFIC stats screen. + * @param useCasesFactories build the use cases for the DAYS granularity + */ + @Provides + @Singleton + @Named(TRAFFIC_USE_CASE) + @Suppress("LongParameterList") + fun provideTrafficUseCase( + statsStore: StatsStore, + @Named(BG_THREAD) bgDispatcher: CoroutineDispatcher, + @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, + statsSiteProvider: StatsSiteProvider, + @Named(GRANULAR_USE_CASE_FACTORIES) useCasesFactories: List<@JvmSuppressWildcards GranularUseCaseFactory>, + uiModelMapper: UiModelMapper + ): BaseListUseCase { + return BaseListUseCase( + bgDispatcher, + mainDispatcher, + statsSiteProvider, + useCasesFactories.map { it.build(DAYS, BLOCK) }, + { statsStore.getTimeStatsTypes(it) }, + uiModelMapper::mapTimeStats + ) + } + /** * Provides a singleton usecase that represents the Day stats screen. * @param useCasesFactories build the use cases for the DAYS granularity @@ -376,6 +403,7 @@ class StatsModule { @Named(LIST_STATS_USE_CASES) fun provideListStatsUseCases( @Named(INSIGHTS_USE_CASE) insightsUseCase: BaseListUseCase, + @Named(TRAFFIC_USE_CASE) trafficUseCase: BaseListUseCase, @Named(DAY_STATS_USE_CASE) dayStatsUseCase: BaseListUseCase, @Named(WEEK_STATS_USE_CASE) weekStatsUseCase: BaseListUseCase, @Named(MONTH_STATS_USE_CASE) monthStatsUseCase: BaseListUseCase, @@ -383,6 +411,7 @@ class StatsModule { ): Map { return mapOf( StatsSection.INSIGHTS to insightsUseCase, + StatsSection.TRAFFIC to trafficUseCase, StatsSection.DAYS to dayStatsUseCase, StatsSection.WEEKS to weekStatsUseCase, StatsSection.MONTHS to monthStatsUseCase, diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt index a3b14286a6f8..0961b8e4baf8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt @@ -20,6 +20,7 @@ import org.wordpress.android.ui.stats.refresh.StatsViewModel.DateSelectorUiModel import org.wordpress.android.ui.stats.refresh.TOTAL_COMMENTS_DETAIL_USE_CASE import org.wordpress.android.ui.stats.refresh.TOTAL_FOLLOWERS_DETAIL_USE_CASE import org.wordpress.android.ui.stats.refresh.TOTAL_LIKES_DETAIL_USE_CASE +import org.wordpress.android.ui.stats.refresh.TRAFFIC_USE_CASE import org.wordpress.android.ui.stats.refresh.VIEWS_AND_VISITORS_USE_CASE import org.wordpress.android.ui.stats.refresh.WEEK_STATS_USE_CASE import org.wordpress.android.ui.stats.refresh.YEAR_STATS_USE_CASE @@ -199,6 +200,13 @@ class InsightsListViewModel actionCardHandler ) +class TrafficListViewModel @Inject constructor( + @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, + @Named(TRAFFIC_USE_CASE) statsUseCase: BaseListUseCase, + analyticsTracker: AnalyticsTrackerWrapper, + dateSelectorFactory: StatsDateSelector.Factory +) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(TRAFFIC)) + class YearsListViewModel @Inject constructor( @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, @Named(YEAR_STATS_USE_CASE) statsUseCase: BaseListUseCase, @@ -227,13 +235,6 @@ class DaysListViewModel @Inject constructor( dateSelectorFactory: StatsDateSelector.Factory ) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(DAYS)) -class TrafficListViewModel @Inject constructor( - @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, - @Named(DAY_STATS_USE_CASE) statsUseCase: BaseListUseCase, - analyticsTracker: AnalyticsTrackerWrapper, - dateSelectorFactory: StatsDateSelector.Factory -) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(TRAFFIC)) - // Using Weeks granularity on new insight details screens class InsightsDetailListViewModel @Inject constructor( @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, From 7dc3d4cec0a9d9a8bf9ddf456af7eb8edc3a8613 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Mon, 29 Jan 2024 19:25:05 +0300 Subject: [PATCH 17/53] Remove `StatsSection.INSIGHTS` and `StatsSection.TRAFFIC` imports The imports for`StatsSection.INSIGHTS` and `StatsSection.TRAFFIC` are removed to maintain consistency within the class, as the class does not import other `StatsSection`s separately. --- .../android/ui/stats/refresh/utils/StatsDateSelector.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsDateSelector.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsDateSelector.kt index 89a34a9786bf..d5e7f976cd62 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsDateSelector.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsDateSelector.kt @@ -9,8 +9,6 @@ import org.wordpress.android.fluxc.network.utils.StatsGranularity.WEEKS import org.wordpress.android.fluxc.network.utils.StatsGranularity.YEARS import org.wordpress.android.ui.stats.refresh.StatsViewModel.DateSelectorUiModel import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.INSIGHTS -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.TRAFFIC import org.wordpress.android.ui.stats.refresh.lists.sections.granular.SelectedDateProvider import org.wordpress.android.ui.stats.refresh.lists.sections.granular.SelectedDateProvider.SelectedDate import org.wordpress.android.util.config.StatsTrafficTabFeatureConfig @@ -38,8 +36,8 @@ constructor( } fun updateDateSelector() { - val shouldShowDateSelection = this.statsSection != INSIGHTS - val shouldShowGranularitySpinner = statsTrafficTabFeatureConfig.isEnabled() && this.statsSection == TRAFFIC + val shouldShowDateSelection = this.statsSection != StatsSection.INSIGHTS + val shouldShowGranularitySpinner = statsTrafficTabFeatureConfig.isEnabled() && this.statsSection == StatsSection.TRAFFIC val updatedDate = getDateLabelForSection() val currentState = dateSelectorData.value @@ -87,7 +85,7 @@ constructor( StatsSection.TOTAL_FOLLOWERS_DETAIL, StatsSection.INSIGHTS, StatsSection.INSIGHT_DETAIL, - StatsSection.DAYS, TRAFFIC -> DAYS // Replace with TRAFFIC when it's implemented + StatsSection.DAYS, StatsSection.TRAFFIC -> DAYS // Replace with TRAFFIC when it's implemented StatsSection.WEEKS -> WEEKS StatsSection.MONTHS -> MONTHS StatsSection.ANNUAL_STATS, From 1e2391cc8713a2891308cce7263d736923ebb049 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Tue, 30 Jan 2024 16:04:40 +0100 Subject: [PATCH 18/53] Update Gutenberg Mobile reference with alpha tag --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8f156a07b617..28d1f1e020a2 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ ext { automatticRestVersion = '1.0.8' automatticStoriesVersion = '2.4.0' automatticTracksVersion = '3.3.0' - gutenbergMobileVersion = 'v1.112.0-alpha3' + gutenbergMobileVersion = 'v1.112.0-alpha4' wordPressAztecVersion = 'v2.0' wordPressFluxCVersion = '2.64.0' wordPressLoginVersion = '1.11.0' From 66cea78d569d993b00df1105141467bf922eb792 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Tue, 30 Jan 2024 20:59:46 +0200 Subject: [PATCH 19/53] Updates FluxC version to v1.112.0-alpha5 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 58ad6e1dfb7c..949cd82ae741 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ ext { automatticRestVersion = '1.0.8' automatticStoriesVersion = '2.4.0' automatticTracksVersion = '3.3.0' - gutenbergMobileVersion = '6575-3f952dec8abd0121abae011d3f96cc02eeb8912b' + gutenbergMobileVersion = 'v1.112.0-alpha5' wordPressAztecVersion = 'v2.0' wordPressFluxCVersion = '2.64.0' wordPressLoginVersion = '1.11.0' From 8848c79a4409ef7ad8c3f8c02673a561d5a9e583 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Tue, 30 Jan 2024 21:18:01 +0300 Subject: [PATCH 20/53] Remove `statsSection` from `StatsDateSelector` `StatsDateSelector` should not be aware of `statsSection`. It has been removed from `StatsDateSelector`, and `statsGranularity` has been added in its place. --- .../refresh/StatsViewAllViewModelFactory.kt | 6 +- .../stats/refresh/lists/StatsListViewModel.kt | 75 ++++++++++++----- .../lists/detail/DetailListViewModel.kt | 9 ++- .../usecases/AnnualSiteStatsUseCase.kt | 6 +- .../refresh/utils/SelectedSectionManager.kt | 3 +- .../stats/refresh/utils/StatsDateSelector.kt | 80 +++++++------------ .../refresh/lists/StatsDateSelectorTest.kt | 50 ++++-------- .../usecases/AnnualSiteStatsUseCaseTest.kt | 8 +- 8 files changed, 117 insertions(+), 120 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModelFactory.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModelFactory.kt index 463afd2eee92..cec09374d5c0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModelFactory.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewAllViewModelFactory.kt @@ -29,7 +29,6 @@ import org.wordpress.android.ui.stats.StatsViewType.SEARCH_TERMS import org.wordpress.android.ui.stats.StatsViewType.TAGS_AND_CATEGORIES import org.wordpress.android.ui.stats.StatsViewType.TOP_POSTS_AND_PAGES import org.wordpress.android.ui.stats.StatsViewType.VIDEO_PLAYS -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection import org.wordpress.android.ui.stats.refresh.lists.detail.PostAverageViewsPerDayUseCase import org.wordpress.android.ui.stats.refresh.lists.detail.PostMonthsAndYearsUseCase import org.wordpress.android.ui.stats.refresh.lists.detail.PostRecentWeeksUseCase @@ -55,7 +54,6 @@ import org.wordpress.android.ui.stats.refresh.lists.sections.insights.usecases.T import org.wordpress.android.ui.stats.refresh.lists.sections.insights.usecases.ViewsAndVisitorsUseCase import org.wordpress.android.ui.stats.refresh.utils.StatsDateSelector import org.wordpress.android.ui.stats.refresh.utils.StatsSiteProvider -import org.wordpress.android.ui.stats.refresh.utils.toStatsSection import java.security.InvalidParameterException import javax.inject.Inject import javax.inject.Named @@ -106,7 +104,7 @@ class StatsViewAllViewModelFactory( val dateSelector = if (granularity == null) { null } else { - dateSelectorFactory.build(granularity.toStatsSection()) + dateSelectorFactory.build(granularity) } return StatsViewAllViewModelFactory( mainDispatcher, @@ -127,7 +125,7 @@ class StatsViewAllViewModelFactory( bgDispatcher, useCase, statsSiteProvider, - dateSelectorFactory.build(StatsSection.ANNUAL_STATS), + dateSelectorFactory.build(StatsGranularity.YEARS), R.string.stats_insights_annual_site_stats ) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt index 0961b8e4baf8..9780f5feade0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt @@ -10,6 +10,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.delay import org.wordpress.android.R import org.wordpress.android.analytics.AnalyticsTracker.Stat +import org.wordpress.android.fluxc.network.utils.StatsGranularity import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.stats.refresh.DAY_STATS_USE_CASE import org.wordpress.android.ui.stats.refresh.INSIGHTS_USE_CASE @@ -24,12 +25,6 @@ import org.wordpress.android.ui.stats.refresh.TRAFFIC_USE_CASE import org.wordpress.android.ui.stats.refresh.VIEWS_AND_VISITORS_USE_CASE import org.wordpress.android.ui.stats.refresh.WEEK_STATS_USE_CASE import org.wordpress.android.ui.stats.refresh.YEAR_STATS_USE_CASE -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.DAYS -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.INSIGHTS -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.MONTHS -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.TRAFFIC -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.WEEKS -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.YEARS import org.wordpress.android.ui.stats.refresh.utils.ActionCardHandler import org.wordpress.android.ui.stats.refresh.utils.ItemPopupMenuHandler import org.wordpress.android.ui.stats.refresh.utils.NewsCardHandler @@ -186,7 +181,6 @@ class InsightsListViewModel @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, @Named(INSIGHTS_USE_CASE) private val insightsUseCase: BaseListUseCase, analyticsTracker: AnalyticsTrackerWrapper, - dateSelectorFactory: StatsDateSelector.Factory, popupMenuHandler: ItemPopupMenuHandler, newsCardHandler: NewsCardHandler, actionCardHandler: ActionCardHandler @@ -194,7 +188,7 @@ class InsightsListViewModel mainDispatcher, insightsUseCase, analyticsTracker, - dateSelectorFactory.build(INSIGHTS), + null, popupMenuHandler, newsCardHandler, actionCardHandler @@ -205,61 +199,106 @@ class TrafficListViewModel @Inject constructor( @Named(TRAFFIC_USE_CASE) statsUseCase: BaseListUseCase, analyticsTracker: AnalyticsTrackerWrapper, dateSelectorFactory: StatsDateSelector.Factory -) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(TRAFFIC)) +) : StatsListViewModel( + mainDispatcher, + statsUseCase, + analyticsTracker, + dateSelectorFactory.build(StatsGranularity.DAYS, isGranularitySpinnerVisible = true) +) class YearsListViewModel @Inject constructor( @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, @Named(YEAR_STATS_USE_CASE) statsUseCase: BaseListUseCase, analyticsTracker: AnalyticsTrackerWrapper, dateSelectorFactory: StatsDateSelector.Factory -) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(YEARS)) +) : StatsListViewModel( + mainDispatcher, + statsUseCase, + analyticsTracker, + dateSelectorFactory.build(StatsGranularity.YEARS) +) class MonthsListViewModel @Inject constructor( @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, @Named(MONTH_STATS_USE_CASE) statsUseCase: BaseListUseCase, analyticsTracker: AnalyticsTrackerWrapper, dateSelectorFactory: StatsDateSelector.Factory -) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(MONTHS)) +) : StatsListViewModel( + mainDispatcher, + statsUseCase, + analyticsTracker, + dateSelectorFactory.build(StatsGranularity.MONTHS) +) class WeeksListViewModel @Inject constructor( @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, @Named(WEEK_STATS_USE_CASE) statsUseCase: BaseListUseCase, analyticsTracker: AnalyticsTrackerWrapper, dateSelectorFactory: StatsDateSelector.Factory -) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(WEEKS)) +) : StatsListViewModel( + mainDispatcher, + statsUseCase, + analyticsTracker, + dateSelectorFactory.build(StatsGranularity.WEEKS) +) class DaysListViewModel @Inject constructor( @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, @Named(DAY_STATS_USE_CASE) statsUseCase: BaseListUseCase, analyticsTracker: AnalyticsTrackerWrapper, dateSelectorFactory: StatsDateSelector.Factory -) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(DAYS)) +) : StatsListViewModel( + mainDispatcher, + statsUseCase, + analyticsTracker, + dateSelectorFactory.build(StatsGranularity.DAYS) +) -// Using Weeks granularity on new insight details screens +// Using Weeks granularity on insight details screens class InsightsDetailListViewModel @Inject constructor( @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, @Named(VIEWS_AND_VISITORS_USE_CASE) statsUseCase: BaseListUseCase, analyticsTracker: AnalyticsTrackerWrapper, dateSelectorFactory: StatsDateSelector.Factory -) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(WEEKS)) +) : StatsListViewModel( + mainDispatcher, + statsUseCase, + analyticsTracker, + dateSelectorFactory.build(StatsGranularity.WEEKS) +) class TotalLikesDetailListViewModel @Inject constructor( @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, @Named(TOTAL_LIKES_DETAIL_USE_CASE) statsUseCase: BaseListUseCase, analyticsTracker: AnalyticsTrackerWrapper, dateSelectorFactory: StatsDateSelector.Factory -) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(WEEKS)) +) : StatsListViewModel( + mainDispatcher, + statsUseCase, + analyticsTracker, + dateSelectorFactory.build(StatsGranularity.WEEKS) +) class TotalCommentsDetailListViewModel @Inject constructor( @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, @Named(TOTAL_COMMENTS_DETAIL_USE_CASE) statsUseCase: BaseListUseCase, analyticsTracker: AnalyticsTrackerWrapper, dateSelectorFactory: StatsDateSelector.Factory -) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(WEEKS)) +) : StatsListViewModel( + mainDispatcher, + statsUseCase, + analyticsTracker, + dateSelectorFactory.build(StatsGranularity.WEEKS) +) class TotalFollowersDetailListViewModel @Inject constructor( @Named(UI_THREAD) mainDispatcher: CoroutineDispatcher, @Named(TOTAL_FOLLOWERS_DETAIL_USE_CASE) statsUseCase: BaseListUseCase, analyticsTracker: AnalyticsTrackerWrapper, dateSelectorFactory: StatsDateSelector.Factory -) : StatsListViewModel(mainDispatcher, statsUseCase, analyticsTracker, dateSelectorFactory.build(WEEKS)) +) : StatsListViewModel( + mainDispatcher, + statsUseCase, + analyticsTracker, + dateSelectorFactory.build(StatsGranularity.WEEKS) +) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/DetailListViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/DetailListViewModel.kt index 23199d7b74f4..9ceb3563f701 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/DetailListViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/DetailListViewModel.kt @@ -1,11 +1,11 @@ package org.wordpress.android.ui.stats.refresh.lists.detail import kotlinx.coroutines.CoroutineDispatcher +import org.wordpress.android.fluxc.network.utils.StatsGranularity import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.stats.refresh.BLOCK_DETAIL_USE_CASE import org.wordpress.android.ui.stats.refresh.lists.BaseListUseCase import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.DETAIL import org.wordpress.android.ui.stats.refresh.utils.StatsDateSelector import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper import javax.inject.Inject @@ -17,7 +17,12 @@ class DetailListViewModel @Named(BLOCK_DETAIL_USE_CASE) private val detailUseCase: BaseListUseCase, analyticsTracker: AnalyticsTrackerWrapper, dateSelectorFactory: StatsDateSelector.Factory -) : StatsListViewModel(mainDispatcher, detailUseCase, analyticsTracker, dateSelectorFactory.build(DETAIL)) { +) : StatsListViewModel( + mainDispatcher, + detailUseCase, + analyticsTracker, + dateSelectorFactory.build(StatsGranularity.DAYS) +) { override fun onCleared() { super.onCleared() dateSelector?.clear() diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/AnnualSiteStatsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/AnnualSiteStatsUseCase.kt index 3b4faa13812e..f9e5d4e8a284 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/AnnualSiteStatsUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/AnnualSiteStatsUseCase.kt @@ -4,12 +4,12 @@ import android.view.View import kotlinx.coroutines.CoroutineDispatcher import org.wordpress.android.R import org.wordpress.android.fluxc.model.stats.YearsInsightsModel +import org.wordpress.android.fluxc.network.utils.StatsGranularity import org.wordpress.android.fluxc.store.StatsStore.InsightType.ANNUAL_SITE_STATS import org.wordpress.android.fluxc.store.stats.insights.MostPopularInsightsStore import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.stats.refresh.NavigationTarget -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.ANNUAL_STATS import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase.StatelessUseCase import org.wordpress.android.ui.stats.refresh.lists.sections.BlockListItem import org.wordpress.android.ui.stats.refresh.lists.sections.BlockListItem.Link @@ -59,13 +59,13 @@ class AnnualSiteStatsUseCase( override fun buildLoadingItem(): List = listOf(Title(R.string.stats_insights_this_year_site_stats)) override fun buildUiModel(domainModel: YearsInsightsModel): List { - val periodFromProvider = selectedDateProvider.getSelectedDate(ANNUAL_STATS) + val periodFromProvider = selectedDateProvider.getSelectedDate(StatsGranularity.YEARS) val availablePeriods = domainModel.years val availableDates = availablePeriods.map { yearToDate(it.year) } val selectedPeriod = periodFromProvider ?: availableDates.last() val index = availableDates.indexOf(selectedPeriod) - selectedDateProvider.selectDate(selectedPeriod, availableDates, ANNUAL_STATS) + selectedDateProvider.selectDate(selectedPeriod, availableDates, StatsGranularity.YEARS) val items = mutableListOf() diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt index a71f504a41af..cc81dcc1df0b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt @@ -47,9 +47,8 @@ class SelectedSectionManager fun StatsSection.toStatsGranularity(): StatsGranularity? { return when (this) { - ANNUAL_STATS, DETAIL, TOTAL_LIKES_DETAIL, TOTAL_COMMENTS_DETAIL, TOTAL_FOLLOWERS_DETAIL, INSIGHTS -> null + StatsSection.TRAFFIC, ANNUAL_STATS, DETAIL, TOTAL_LIKES_DETAIL, TOTAL_COMMENTS_DETAIL, TOTAL_FOLLOWERS_DETAIL, INSIGHTS -> null StatsSection.INSIGHT_DETAIL, - StatsSection.TRAFFIC -> DAYS // Replace with TRAFFIC when it's implemented StatsSection.DAYS -> DAYS StatsSection.WEEKS -> WEEKS StatsSection.MONTHS -> MONTHS diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsDateSelector.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsDateSelector.kt index d5e7f976cd62..bf7d89e37a20 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsDateSelector.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsDateSelector.kt @@ -3,12 +3,7 @@ package org.wordpress.android.ui.stats.refresh.utils import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import org.wordpress.android.fluxc.network.utils.StatsGranularity -import org.wordpress.android.fluxc.network.utils.StatsGranularity.DAYS -import org.wordpress.android.fluxc.network.utils.StatsGranularity.MONTHS -import org.wordpress.android.fluxc.network.utils.StatsGranularity.WEEKS -import org.wordpress.android.fluxc.network.utils.StatsGranularity.YEARS import org.wordpress.android.ui.stats.refresh.StatsViewModel.DateSelectorUiModel -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection import org.wordpress.android.ui.stats.refresh.lists.sections.granular.SelectedDateProvider import org.wordpress.android.ui.stats.refresh.lists.sections.granular.SelectedDateProvider.SelectedDate import org.wordpress.android.util.config.StatsTrafficTabFeatureConfig @@ -20,45 +15,39 @@ constructor( private val selectedDateProvider: SelectedDateProvider, private val statsDateFormatter: StatsDateFormatter, private val siteProvider: StatsSiteProvider, - private val statsTrafficTabFeatureConfig: StatsTrafficTabFeatureConfig, - private val statsSection: StatsSection + private val statsGranularity: StatsGranularity, + private val isGranularitySpinnerVisible: Boolean, + private val statsTrafficTabFeatureConfig: StatsTrafficTabFeatureConfig ) { private val _dateSelectorUiModel = MutableLiveData() val dateSelectorData: LiveData = _dateSelectorUiModel - val selectedDate = selectedDateProvider.granularSelectedDateChanged(this.statsSection) + val selectedDate = selectedDateProvider.granularSelectedDateChanged(statsGranularity) .perform { updateDateSelector() } fun start(startDate: SelectedDate) { - selectedDateProvider.updateSelectedDate(startDate, statsSection) + selectedDateProvider.updateSelectedDate(startDate, statsGranularity) } fun updateDateSelector() { - val shouldShowDateSelection = this.statsSection != StatsSection.INSIGHTS - val shouldShowGranularitySpinner = statsTrafficTabFeatureConfig.isEnabled() && this.statsSection == StatsSection.TRAFFIC - val updatedDate = getDateLabelForSection() val currentState = dateSelectorData.value - if (!shouldShowDateSelection && currentState?.isVisible != false) { - emitValue(currentState, DateSelectorUiModel(false)) + val timeZone = if (statsTrafficTabFeatureConfig.isEnabled()) { + null } else { - val timeZone = if (statsTrafficTabFeatureConfig.isEnabled()) { - null - } else { - statsDateFormatter.printTimeZone(siteProvider.siteModel) - } - val updatedState = DateSelectorUiModel( - shouldShowDateSelection, - shouldShowGranularitySpinner, - updatedDate, - enableSelectPrevious = selectedDateProvider.hasPreviousDate(statsSection), - enableSelectNext = selectedDateProvider.hasNextDate(statsSection), - timeZone = timeZone - ) - emitValue(currentState, updatedState) + statsDateFormatter.printTimeZone(siteProvider.siteModel) } + val updatedState = DateSelectorUiModel( + true, + isGranularitySpinnerVisible, + updatedDate, + enableSelectPrevious = selectedDateProvider.hasPreviousDate(statsGranularity), + enableSelectNext = selectedDateProvider.hasNextDate(statsGranularity), + timeZone = timeZone + ) + emitValue(currentState, updatedState) } private fun emitValue( @@ -72,41 +61,25 @@ constructor( private fun getDateLabelForSection(): String? { return statsDateFormatter.printGranularDate( - selectedDateProvider.getSelectedDate(statsSection) ?: selectedDateProvider.getCurrentDate(), - toStatsGranularity() + selectedDateProvider.getSelectedDate(statsGranularity) ?: selectedDateProvider.getCurrentDate(), + statsGranularity ) } - private fun toStatsGranularity(): StatsGranularity { - return when (statsSection) { - StatsSection.DETAIL, - StatsSection.TOTAL_LIKES_DETAIL, - StatsSection.TOTAL_COMMENTS_DETAIL, - StatsSection.TOTAL_FOLLOWERS_DETAIL, - StatsSection.INSIGHTS, - StatsSection.INSIGHT_DETAIL, - StatsSection.DAYS, StatsSection.TRAFFIC -> DAYS // Replace with TRAFFIC when it's implemented - StatsSection.WEEKS -> WEEKS - StatsSection.MONTHS -> MONTHS - StatsSection.ANNUAL_STATS, - StatsSection.YEARS -> YEARS - } - } - fun onNextDateSelected() { - selectedDateProvider.selectNextDate(statsSection) + selectedDateProvider.selectNextDate(statsGranularity) } fun onPreviousDateSelected() { - selectedDateProvider.selectPreviousDate(statsSection) + selectedDateProvider.selectPreviousDate(statsGranularity) } fun clear() { - selectedDateProvider.clear(statsSection) + selectedDateProvider.clear(statsGranularity) } fun getSelectedDate(): SelectedDate { - return selectedDateProvider.getSelectedDateState(statsSection) + return selectedDateProvider.getSelectedDateState(statsGranularity) } class Factory @@ -116,13 +89,14 @@ constructor( private val statsDateFormatter: StatsDateFormatter, private val statsTrafficTabFeatureConfig: StatsTrafficTabFeatureConfig ) { - fun build(statsSection: StatsSection): StatsDateSelector { + fun build(statsGranularity: StatsGranularity, isGranularitySpinnerVisible: Boolean = false): StatsDateSelector { return StatsDateSelector( selectedDateProvider, statsDateFormatter, siteProvider, - statsTrafficTabFeatureConfig, - statsSection + statsGranularity, + isGranularitySpinnerVisible, + statsTrafficTabFeatureConfig ) } } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/StatsDateSelectorTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/StatsDateSelectorTest.kt index dd6096d09abd..5859eef1477e 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/StatsDateSelectorTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/StatsDateSelectorTest.kt @@ -10,9 +10,8 @@ import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest import org.wordpress.android.fluxc.network.utils.StatsGranularity import org.wordpress.android.ui.stats.refresh.StatsViewModel.DateSelectorUiModel -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection import org.wordpress.android.ui.stats.refresh.lists.sections.granular.SelectedDateProvider -import org.wordpress.android.ui.stats.refresh.lists.sections.granular.SelectedDateProvider.SectionChange +import org.wordpress.android.ui.stats.refresh.lists.sections.granular.SelectedDateProvider.GranularityChange import org.wordpress.android.ui.stats.refresh.utils.StatsDateFormatter import org.wordpress.android.ui.stats.refresh.utils.StatsDateSelector import org.wordpress.android.ui.stats.refresh.utils.StatsSiteProvider @@ -34,28 +33,28 @@ class StatsDateSelectorTest : BaseUnitTest() { lateinit var statsTrafficTabFeatureConfig: StatsTrafficTabFeatureConfig private val selectedDate = Date(0) private val selectedDateLabel = "Jan 1" - private val statsSection = StatsSection.DAYS private val statsGranularity = StatsGranularity.DAYS private val updatedDate = Date(10) private val updatedLabel = "Jan 2" - private val dateProviderSelectedDate = MutableLiveData() + private val dateProviderSelectedDate = MutableLiveData() private lateinit var dateSelector: StatsDateSelector @Before fun setUp() { - dateProviderSelectedDate.value = SectionChange(statsSection) - whenever(selectedDateProvider.granularSelectedDateChanged(statsSection)).thenReturn(dateProviderSelectedDate) + dateProviderSelectedDate.value = GranularityChange(statsGranularity) + whenever(selectedDateProvider.granularSelectedDateChanged(statsGranularity)).thenReturn(dateProviderSelectedDate) dateSelector = StatsDateSelector( selectedDateProvider, statsDateFormatter, siteProvider, - statsTrafficTabFeatureConfig, - statsSection + statsGranularity, + false, + statsTrafficTabFeatureConfig ) - whenever(selectedDateProvider.getSelectedDate(statsSection)).thenReturn(selectedDate) + whenever(selectedDateProvider.getSelectedDate(statsGranularity)).thenReturn(selectedDate) whenever(statsDateFormatter.printGranularDate(selectedDate, statsGranularity)).thenReturn(selectedDateLabel) whenever(statsDateFormatter.printGranularDate(updatedDate, statsGranularity)).thenReturn(updatedLabel) whenever(statsTrafficTabFeatureConfig.isEnabled()).thenReturn(true) @@ -77,9 +76,9 @@ class StatsDateSelectorTest : BaseUnitTest() { @Test fun `shows date selector on days screen`() { - whenever(selectedDateProvider.getSelectedDate(statsSection)).thenReturn(selectedDate) - whenever(selectedDateProvider.hasPreviousDate(statsSection)).thenReturn(true) - whenever(selectedDateProvider.hasNextDate(statsSection)).thenReturn(true) + whenever(selectedDateProvider.getSelectedDate(statsGranularity)).thenReturn(selectedDate) + whenever(selectedDateProvider.hasPreviousDate(statsGranularity)).thenReturn(true) + whenever(selectedDateProvider.hasNextDate(statsGranularity)).thenReturn(true) var model: DateSelectorUiModel? = null dateSelector.dateSelectorData.observeForever { model = it } @@ -95,8 +94,8 @@ class StatsDateSelectorTest : BaseUnitTest() { @Test fun `updates date selector on date change`() { - whenever(selectedDateProvider.hasPreviousDate(statsSection)).thenReturn(true) - whenever(selectedDateProvider.hasNextDate(statsSection)).thenReturn(true) + whenever(selectedDateProvider.hasPreviousDate(statsGranularity)).thenReturn(true) + whenever(selectedDateProvider.hasNextDate(statsGranularity)).thenReturn(true) var model: DateSelectorUiModel? = null dateSelector.dateSelectorData.observeForever { model = it } @@ -104,31 +103,10 @@ class StatsDateSelectorTest : BaseUnitTest() { Assertions.assertThat(model?.date).isEqualTo(selectedDateLabel) - whenever(selectedDateProvider.getSelectedDate(statsSection)).thenReturn(updatedDate) + whenever(selectedDateProvider.getSelectedDate(statsGranularity)).thenReturn(updatedDate) dateSelector.updateDateSelector() Assertions.assertThat(model?.date).isEqualTo(updatedLabel) } - - @Test - fun `verify date selector hidden for insights`() { - whenever(selectedDateProvider.granularSelectedDateChanged(StatsSection.INSIGHTS)).thenReturn( - dateProviderSelectedDate - ) - dateSelector = StatsDateSelector( - selectedDateProvider, - statsDateFormatter, - siteProvider, - statsTrafficTabFeatureConfig, - StatsSection.INSIGHTS - ) - var model: DateSelectorUiModel? = null - dateSelector.dateSelectorData.observeForever { model = it } - - dateSelector.updateDateSelector() - - Assertions.assertThat(model).isNotNull - Assertions.assertThat(model?.isVisible).isFalse() - } } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/AnnualSiteStatsUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/AnnualSiteStatsUseCaseTest.kt index 260266fd77dd..22bddae81009 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/AnnualSiteStatsUseCaseTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/AnnualSiteStatsUseCaseTest.kt @@ -13,12 +13,12 @@ import org.wordpress.android.R import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.model.stats.YearsInsightsModel import org.wordpress.android.fluxc.model.stats.YearsInsightsModel.YearInsights +import org.wordpress.android.fluxc.network.utils.StatsGranularity import org.wordpress.android.fluxc.store.StatsStore.OnStatsFetched import org.wordpress.android.fluxc.store.StatsStore.StatsError import org.wordpress.android.fluxc.store.StatsStore.StatsErrorType.GENERIC_ERROR import org.wordpress.android.fluxc.store.stats.insights.MostPopularInsightsStore import org.wordpress.android.ui.stats.refresh.NavigationTarget -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.ANNUAL_STATS import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase.UseCaseMode.BLOCK import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase.UseCaseMode.VIEW_ALL import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase.UseCaseModel @@ -107,7 +107,11 @@ class AnnualSiteStatsUseCaseTest : BaseUnitTest() { selectedDate.set(Calendar.YEAR, 2019) selectedDate.set(Calendar.MONTH, Calendar.DECEMBER) selectedDate.set(Calendar.DAY_OF_MONTH, 31) - verify(selectedDateProvider, times(1)).selectDate(selectedDate.time, listOf(selectedDate.time), ANNUAL_STATS) + verify(selectedDateProvider, times(1)).selectDate( + selectedDate.time, + listOf(selectedDate.time), + StatsGranularity.YEARS + ) } @Test From 87ebfbf7ff5e4af77da15833b961de70386e8ec6 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Tue, 30 Jan 2024 22:18:20 +0300 Subject: [PATCH 21/53] Change `BaseStatsUseCase`'s parameter with `StatsGranularity` `BaseStatsUseCase` was getting `StatsSection` as parameter, then --- .../android/ui/stats/refresh/lists/BaseListUseCase.kt | 5 +++-- .../android/ui/stats/refresh/lists/StatsListFragment.kt | 2 +- .../android/ui/stats/refresh/lists/StatsListViewModel.kt | 4 ++-- .../ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt | 2 +- .../ui/stats/refresh/lists/sections/BaseStatsUseCase.kt | 4 ++-- .../lists/sections/granular/GranularStatefulUseCase.kt | 3 +-- .../lists/sections/granular/GranularStatelessUseCase.kt | 2 +- .../lists/sections/granular/usecases/OverviewUseCase.kt | 3 +-- .../sections/insights/usecases/ViewsAndVisitorsUseCase.kt | 3 +-- 9 files changed, 13 insertions(+), 15 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/BaseListUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/BaseListUseCase.kt index 6c8632bbb5f3..91dc8fbeaa7e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/BaseListUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/BaseListUseCase.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.wordpress.android.R import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.network.utils.StatsGranularity import org.wordpress.android.fluxc.store.StatsStore.StatsType import org.wordpress.android.ui.pages.SnackbarMessageHolder import org.wordpress.android.ui.stats.refresh.NavigationTarget @@ -140,8 +141,8 @@ class BaseListUseCase( data.value = null } - suspend fun onDateChanged(selectedSection: StatsSection) { - onParamChanged(UseCaseParam.SelectedDateParam(selectedSection)) + suspend fun onDateChanged(selectedGranularity: StatsGranularity) { + onParamChanged(UseCaseParam.SelectedDateParam(selectedGranularity)) } fun onListSelected() { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt index 4bba42e5aab9..1469325b5c26 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListFragment.kt @@ -254,7 +254,7 @@ class StatsListFragment : ViewPagerFragment(R.layout.stats_list_fragment) { viewModel.selectedDate?.observe(viewLifecycleOwner) { event -> if (event != null) { - viewModel.onDateChanged(event.selectedSection) + viewModel.onDateChanged(event.selectedGranularity) } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt index 9780f5feade0..1643bedabaae 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/StatsListViewModel.kt @@ -127,9 +127,9 @@ abstract class StatsListViewModel( } } - fun onDateChanged(selectedSection: StatsSection) { + fun onDateChanged(selectedGranularity: StatsGranularity) { launch { - statsUseCase.onDateChanged(selectedSection) + statsUseCase.onDateChanged(selectedGranularity) } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt index c5e7c1809c52..5ff9c6956c83 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt @@ -39,7 +39,7 @@ class PostDayViewsUseCase mainDispatcher, backgroundDispatcher, UiState(), - uiUpdateParams = listOf(UseCaseParam.SelectedDateParam(DETAIL)) + uiUpdateParams = listOf(UseCaseParam.SelectedDateParam(DAYS)) ) { override suspend fun loadCachedData(): PostDetailStatsModel? { return statsPostProvider.postId?.let { postId -> diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/BaseStatsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/BaseStatsUseCase.kt index ec7c148fdc3c..7b86388e0e3a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/BaseStatsUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/BaseStatsUseCase.kt @@ -9,9 +9,9 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.wordpress.android.R +import org.wordpress.android.fluxc.network.utils.StatsGranularity import org.wordpress.android.fluxc.store.StatsStore.StatsType import org.wordpress.android.ui.stats.refresh.NavigationTarget -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase.State.Data import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase.State.Empty import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase.State.Error @@ -282,6 +282,6 @@ abstract class BaseStatsUseCase( } sealed class UseCaseParam { - data class SelectedDateParam(val statsSection: StatsSection) : UseCaseParam() + data class SelectedDateParam(val statsGranularity: StatsGranularity) : UseCaseParam() } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatefulUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatefulUseCase.kt index 30d1e2ae7bc3..dce50cf9b582 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatefulUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatefulUseCase.kt @@ -8,7 +8,6 @@ import org.wordpress.android.fluxc.store.StatsStore.StatsType import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase import org.wordpress.android.ui.stats.refresh.lists.sections.BlockListItem import org.wordpress.android.ui.stats.refresh.utils.StatsSiteProvider -import org.wordpress.android.ui.stats.refresh.utils.toStatsSection import java.util.Date @Suppress("LongParameterList") @@ -25,7 +24,7 @@ abstract class GranularStatefulUseCase( mainDispatcher, backgroundDispatcher, defaultUiState, - listOf(UseCaseParam.SelectedDateParam(statsGranularity.toStatsSection())) + listOf(UseCaseParam.SelectedDateParam(statsGranularity)) ) { abstract suspend fun loadCachedData(selectedDate: Date, site: SiteModel): DOMAIN_MODEL? diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatelessUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatelessUseCase.kt index 8b6ffb02ff39..576a551a2677 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatelessUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatelessUseCase.kt @@ -22,7 +22,7 @@ abstract class GranularStatelessUseCase( type, mainDispatcher, backgroundDispatcher, - listOf(UseCaseParam.SelectedDateParam(statsGranularity.toStatsSection())) + listOf(UseCaseParam.SelectedDateParam(statsGranularity)) ) { abstract suspend fun loadCachedData(selectedDate: Date, site: SiteModel): DOMAIN_MODEL? diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/OverviewUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/OverviewUseCase.kt index ef7b192d6ba7..104ebebb120c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/OverviewUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/OverviewUseCase.kt @@ -24,7 +24,6 @@ import org.wordpress.android.ui.stats.refresh.lists.widget.WidgetUpdater.StatsWi import org.wordpress.android.ui.stats.refresh.utils.StatsDateFormatter import org.wordpress.android.ui.stats.refresh.utils.StatsSiteProvider import org.wordpress.android.ui.stats.refresh.utils.StatsUtils -import org.wordpress.android.ui.stats.refresh.utils.toStatsSection import org.wordpress.android.ui.stats.refresh.utils.trackGranular import org.wordpress.android.util.AppLog import org.wordpress.android.util.AppLog.T @@ -60,7 +59,7 @@ class OverviewUseCase constructor( mainDispatcher, backgroundDispatcher, UiState(), - uiUpdateParams = listOf(UseCaseParam.SelectedDateParam(statsGranularity.toStatsSection())) + uiUpdateParams = listOf(UseCaseParam.SelectedDateParam(statsGranularity)) ) { override fun buildLoadingItem(): List = listOf( diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsUseCase.kt index 930d1bd04e49..01b1e4d5d106 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/ViewsAndVisitorsUseCase.kt @@ -29,7 +29,6 @@ import org.wordpress.android.ui.stats.refresh.lists.sections.insights.usecases.V import org.wordpress.android.ui.stats.refresh.lists.widget.WidgetUpdater.StatsWidgetUpdaters import org.wordpress.android.ui.stats.refresh.utils.StatsDateFormatter import org.wordpress.android.ui.stats.refresh.utils.StatsSiteProvider -import org.wordpress.android.ui.stats.refresh.utils.toStatsSection import org.wordpress.android.ui.stats.refresh.utils.trackGranular import org.wordpress.android.ui.stats.refresh.utils.trackViewsVisitorsChips import org.wordpress.android.ui.stats.refresh.utils.trackWithType @@ -68,7 +67,7 @@ class ViewsAndVisitorsUseCase mainDispatcher, backgroundDispatcher, UiState(), - uiUpdateParams = listOf(UseCaseParam.SelectedDateParam(statsGranularity.toStatsSection())) + uiUpdateParams = listOf(UseCaseParam.SelectedDateParam(statsGranularity)) ) { override fun buildLoadingItem(): List = listOf( From d7c573047e425b46c5fb249fceb8d98a94ccf015 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Tue, 30 Jan 2024 22:33:45 +0300 Subject: [PATCH 22/53] Change section parameters with granularity in `SelectedDateProvider` --- .../lists/detail/PostDayViewsUseCase.kt | 14 +- .../sections/granular/SelectedDateProvider.kt | 126 ++++++++---------- 2 files changed, 59 insertions(+), 81 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt index 5ff9c6956c83..09d5cd36a78f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt @@ -59,15 +59,15 @@ class PostDayViewsUseCase return when { error != null -> { - selectedDateProvider.onDateLoadingFailed(DETAIL) + selectedDateProvider.onDateLoadingFailed(DAYS) State.Error(error.message ?: error.type.name) } model != null && model.hasData() -> { - selectedDateProvider.onDateLoadingSucceeded(DETAIL) + selectedDateProvider.onDateLoadingSucceeded(DAYS) State.Data(model) } else -> { - selectedDateProvider.onDateLoadingSucceeded(DETAIL) + selectedDateProvider.onDateLoadingSucceeded(DAYS) State.Empty() } } @@ -78,14 +78,14 @@ class PostDayViewsUseCase val visibleBarCount = uiState.visibleBarCount ?: domainModel.dayViews.size if (domainModel.hasData() && visibleBarCount > 0) { - val periodFromProvider = selectedDateProvider.getSelectedDate(DETAIL) + val periodFromProvider = selectedDateProvider.getSelectedDate(DAYS) val availablePeriods = domainModel.dayViews.takeLast(visibleBarCount) val availableDates = availablePeriods.map { statsDateFormatter.parseStatsDate(DAYS, it.period) } val selectedPeriod = periodFromProvider ?: availableDates.last() val index = availableDates.indexOf(selectedPeriod) - selectedDateProvider.selectDate(selectedPeriod, availableDates, DETAIL) + selectedDateProvider.selectDate(selectedPeriod, availableDates, DAYS) val shiftedIndex = index + domainModel.dayViews.size - visibleBarCount val selectedItem = domainModel.dayViews.getOrNull(shiftedIndex) ?: domainModel.dayViews.last() @@ -107,7 +107,7 @@ class PostDayViewsUseCase ) ) } else { - selectedDateProvider.onDateLoadingFailed(DETAIL) + selectedDateProvider.onDateLoadingFailed(DAYS) AppLog.e(T.STATS, "There is no data to be shown in the post day view block") } return items @@ -129,7 +129,7 @@ class PostDayViewsUseCase val selectedDate = statsDateFormatter.parseStatsDate(DAYS, period) selectedDateProvider.selectDate( selectedDate, - DETAIL + DAYS ) } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/SelectedDateProvider.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/SelectedDateProvider.kt index 6cc52b2e5572..1ce18f0db9b7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/SelectedDateProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/SelectedDateProvider.kt @@ -11,17 +11,11 @@ import kotlinx.parcelize.Parcelize import org.wordpress.android.analytics.AnalyticsTracker.Stat.STATS_NEXT_DATE_TAPPED import org.wordpress.android.analytics.AnalyticsTracker.Stat.STATS_PREVIOUS_DATE_TAPPED import org.wordpress.android.fluxc.network.utils.StatsGranularity -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.DAYS -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.MONTHS -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.WEEKS -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.YEARS import org.wordpress.android.ui.stats.refresh.utils.StatsDateFormatter -import org.wordpress.android.ui.stats.refresh.utils.toStatsSection -import org.wordpress.android.ui.stats.refresh.utils.trackWithSection +import org.wordpress.android.ui.stats.refresh.utils.trackWithGranularity import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper -import org.wordpress.android.util.extensions.readListCompat import org.wordpress.android.util.extensions.getParcelableCompat +import org.wordpress.android.util.extensions.readListCompat import org.wordpress.android.util.filter import java.util.Date import javax.inject.Inject @@ -36,121 +30,100 @@ class SelectedDateProvider private val analyticsTrackerWrapper: AnalyticsTrackerWrapper ) { private val mutableDates = mutableMapOf( - DAYS to SelectedDate(loading = true), - WEEKS to SelectedDate(loading = true), - MONTHS to SelectedDate(loading = true), - YEARS to SelectedDate(loading = true) + StatsGranularity.DAYS to SelectedDate(loading = true), + StatsGranularity.WEEKS to SelectedDate(loading = true), + StatsGranularity.MONTHS to SelectedDate(loading = true), + StatsGranularity.YEARS to SelectedDate(loading = true) ) - private val selectedDateChanged = MutableLiveData() - - fun granularSelectedDateChanged(statsSection: StatsSection): LiveData { - return selectedDateChanged.filter { it?.selectedSection == statsSection } - } + private val selectedDateChanged = MutableLiveData() - fun selectDate(date: Date, statsSection: StatsSection) { - val selectedDate = getSelectedDateState(statsSection) - updateSelectedDate(selectedDate.copy(dateValue = date), statsSection) + fun granularSelectedDateChanged(statsGranularity: StatsGranularity): LiveData { + return selectedDateChanged.filter { it?.selectedGranularity == statsGranularity } } fun selectDate(date: Date, statsGranularity: StatsGranularity) { - selectDate(date, statsGranularity.toStatsSection()) + val selectedDate = getSelectedDateState(statsGranularity) + updateSelectedDate(selectedDate.copy(dateValue = date), statsGranularity) } - fun selectDate(updatedDate: Date, availableDates: List, statsSection: StatsSection) { - val selectedDate = getSelectedDateState(statsSection) + fun selectDate(updatedDate: Date, availableDates: List, statsGranularity: StatsGranularity) { + val selectedDate = getSelectedDateState(statsGranularity) if (selectedDate.dateValue != updatedDate || selectedDate.availableDates != availableDates) { updateSelectedDate( selectedDate.copy(dateValue = updatedDate, availableDates = availableDates), - statsSection + statsGranularity ) } } - fun selectDate(updatedDate: Date, availableDates: List, statsGranularity: StatsGranularity) { - selectDate(updatedDate, availableDates, statsGranularity.toStatsSection()) - } - - fun updateSelectedDate(selectedDate: SelectedDate, statsSection: StatsSection) { - val currentDate = mutableDates[statsSection] - mutableDates[statsSection] = selectedDate + fun updateSelectedDate(selectedDate: SelectedDate, statsGranularity: StatsGranularity) { + val currentDate = mutableDates[statsGranularity] + mutableDates[statsGranularity] = selectedDate if (selectedDate != currentDate) { - selectedDateChanged.postValue(SectionChange(statsSection)) + selectedDateChanged.postValue(GranularityChange(statsGranularity)) } } fun setInitialSelectedPeriod(statsGranularity: StatsGranularity, period: String) { val updatedDate = statsDateFormatter.parseStatsDate(statsGranularity, period) val selectedDate = getSelectedDateState(statsGranularity) - updateSelectedDate(selectedDate.copy(dateValue = updatedDate), statsGranularity.toStatsSection()) + updateSelectedDate(selectedDate.copy(dateValue = updatedDate), statsGranularity) } fun getSelectedDate(statsGranularity: StatsGranularity): Date? { - return getSelectedDate(statsGranularity.toStatsSection()) - } - - fun getSelectedDate(statsSection: StatsSection): Date? { - return getSelectedDateState(statsSection).dateValue + return getSelectedDateState(statsGranularity).dateValue } fun getSelectedDateState(statsGranularity: StatsGranularity): SelectedDate { - return getSelectedDateState(statsGranularity.toStatsSection()) + return mutableDates[statsGranularity] ?: SelectedDate(loading = true) } - fun getSelectedDateState(statsSection: StatsSection): SelectedDate { - return mutableDates[statsSection] ?: SelectedDate(loading = true) - } - - fun hasPreviousDate(statsSection: StatsSection): Boolean { - val selectedDate = getSelectedDateState(statsSection) + fun hasPreviousDate(statsGranularity: StatsGranularity): Boolean { + val selectedDate = getSelectedDateState(statsGranularity) return selectedDate.hasData() && selectedDate.getDateIndex() > 0 } - fun hasNextDate(statsSection: StatsSection): Boolean { - val selectedDate = getSelectedDateState(statsSection) + fun hasNextDate(statsGranularity: StatsGranularity): Boolean { + val selectedDate = getSelectedDateState(statsGranularity) return selectedDate.hasData() && selectedDate.getDateIndex() < selectedDate.availableDates.size - 1 } - fun selectPreviousDate(statsSection: StatsSection) { - val selectedDateState = getSelectedDateState(statsSection) + fun selectPreviousDate(statsGranularity: StatsGranularity) { + val selectedDateState = getSelectedDateState(statsGranularity) if (selectedDateState.hasData()) { - analyticsTrackerWrapper.trackWithSection(STATS_PREVIOUS_DATE_TAPPED, statsSection) - updateSelectedDate(selectedDateState.copy(dateValue = selectedDateState.getPreviousDate()), statsSection) + analyticsTrackerWrapper.trackWithGranularity(STATS_PREVIOUS_DATE_TAPPED, statsGranularity) + updateSelectedDate( + selectedDateState.copy(dateValue = selectedDateState.getPreviousDate()), + statsGranularity + ) } } - fun selectNextDate(statsSection: StatsSection) { - val selectedDateState = getSelectedDateState(statsSection) + fun selectNextDate(statsGranularity: StatsGranularity) { + val selectedDateState = getSelectedDateState(statsGranularity) if (selectedDateState.hasData()) { - analyticsTrackerWrapper.trackWithSection(STATS_NEXT_DATE_TAPPED, statsSection) - updateSelectedDate(selectedDateState.copy(dateValue = selectedDateState.getNextDate()), statsSection) + analyticsTrackerWrapper.trackWithGranularity(STATS_NEXT_DATE_TAPPED, statsGranularity) + updateSelectedDate(selectedDateState.copy(dateValue = selectedDateState.getNextDate()), statsGranularity) } } fun onDateLoadingFailed(statsGranularity: StatsGranularity) { - onDateLoadingFailed(statsGranularity.toStatsSection()) - } - - fun onDateLoadingFailed(statsSection: StatsSection) { - val selectedDate = getSelectedDateState(statsSection) + val selectedDate = getSelectedDateState(statsGranularity) if (selectedDate.dateValue != null && !selectedDate.error) { - updateSelectedDate(selectedDate.copy(error = true, loading = false), statsSection) + updateSelectedDate(selectedDate.copy(error = true, loading = false), statsGranularity) } else if (selectedDate.dateValue == null) { - updateSelectedDate(SelectedDate(error = true, loading = false), statsSection) + updateSelectedDate(SelectedDate(error = true, loading = false), statsGranularity) } } fun onDateLoadingSucceeded(statsGranularity: StatsGranularity) { - onDateLoadingSucceeded(statsGranularity.toStatsSection()) - } - - fun onDateLoadingSucceeded(statsSection: StatsSection) { - val selectedDate = getSelectedDateState(statsSection) + val selectedDate = getSelectedDateState(statsGranularity) if (selectedDate.dateValue != null && selectedDate.error) { - updateSelectedDate(selectedDate.copy(error = false, loading = false), statsSection) + updateSelectedDate(selectedDate.copy(error = false, loading = false), statsGranularity) } else if (selectedDate.dateValue == null) { - updateSelectedDate(SelectedDate(error = false, loading = false), statsSection) + updateSelectedDate(SelectedDate(error = false, loading = false), statsGranularity) } } @@ -161,8 +134,8 @@ class SelectedDateProvider selectedDateChanged.value = null } - fun clear(statsSection: StatsSection) { - mutableDates[statsSection] = SelectedDate(loading = true) + fun clear(statsGranularity: StatsGranularity) { + mutableDates[statsGranularity] = SelectedDate(loading = true) selectedDateChanged.value = null } @@ -173,7 +146,12 @@ class SelectedDateProvider } fun onRestoreInstanceState(savedState: Bundle) { - for (period in listOf(DAYS, WEEKS, MONTHS, YEARS)) { + for (period in listOf( + StatsGranularity.DAYS, + StatsGranularity.WEEKS, + StatsGranularity.MONTHS, + StatsGranularity.YEARS + )) { val selectedDate = savedState.getParcelableCompat(buildStateKey(period)) if (selectedDate != null) { mutableDates[period] = selectedDate @@ -181,7 +159,7 @@ class SelectedDateProvider } } - private fun buildStateKey(key: StatsSection) = SELECTED_DATE_STATE_KEY + key + private fun buildStateKey(key: StatsGranularity) = SELECTED_DATE_STATE_KEY + key @Parcelize @SuppressLint("ParcelCreator") @@ -241,5 +219,5 @@ class SelectedDateProvider } } - data class SectionChange(val selectedSection: StatsSection) + data class GranularityChange(val selectedGranularity: StatsGranularity) } From 4ea21b3bf70e24db275e5a5026a4988259614edd Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Tue, 30 Jan 2024 22:36:01 +0300 Subject: [PATCH 23/53] Update property values of date selector events on stats screen The granularity property was setting with section names. Now it will be granularity values: "day", "week", "month" or "year". --- .../refresh/utils/StatsAnalyticsUtils.kt | 25 ++----------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsAnalyticsUtils.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsAnalyticsUtils.kt index 95bb9b5e0f79..8113a9b097e7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsAnalyticsUtils.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsAnalyticsUtils.kt @@ -4,9 +4,6 @@ import org.wordpress.android.analytics.AnalyticsTracker.Stat import org.wordpress.android.analytics.AnalyticsTracker.Stat.STATS_INSIGHTS_VIEWS_VISITORS_TOGGLED import org.wordpress.android.fluxc.network.utils.StatsGranularity import org.wordpress.android.fluxc.store.StatsStore.InsightType -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.INSIGHT_DETAIL -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.TRAFFIC import org.wordpress.android.ui.stats.refresh.lists.widget.configuration.StatsWidgetConfigureFragment.WidgetType import org.wordpress.android.ui.stats.refresh.lists.widget.configuration.StatsWidgetConfigureFragment.WidgetType.ALL_TIME_VIEWS import org.wordpress.android.ui.stats.refresh.lists.widget.configuration.StatsWidgetConfigureFragment.WidgetType.TODAY_VIEWS @@ -19,9 +16,6 @@ private const val DAYS_PROPERTY = "days" private const val WEEKS_PROPERTY = "weeks" private const val MONTHS_PROPERTY = "months" private const val YEARS_PROPERTY = "years" -private const val INSIGHTS_PROPERTY = "insights" -private const val DETAIL_PROPERTY = "detail" -private const val ANNUAL_STATS_PROPERTY = "annual_stats" private const val TYPE = "type" private const val TYPES = "types" private const val WIDGET_TYPE = "widget_type" @@ -30,9 +24,6 @@ private const val WEEKLY_VIEWS_WIDGET_PROPERTY = "weekly_views" private const val WEEK_TOTALS_WIDGET_PROPERTY = "week_totals" private const val ALL_TIME_WIDGET_PROPERTY = "all_time" private const val MINIFIED_WIDGET_PROPERTY = "minified" -private const val TOTAL_LIKES_PROPERTY = "total_likes_detail" -private const val TOTAL_COMMENTS_PROPERTY = "total_comments_detail" -private const val TOTAL_FOLLOWERS_PROPERTY = "total_followers_detail" private const val CHIP_VIEWS_PROPERTY = "views" private const val CHIP_VISITORS__PROPERTY = "visitors" @@ -54,20 +45,8 @@ fun AnalyticsTrackerWrapper.trackViewsVisitorsChips(position: Int) { this.track(STATS_INSIGHTS_VIEWS_VISITORS_TOGGLED, mapOf(TYPE to property)) } -fun AnalyticsTrackerWrapper.trackWithSection(stat: Stat, section: StatsSection) { - val property = when (section) { - StatsSection.DAYS, TRAFFIC -> DAYS_PROPERTY // Replace with TRAFFIC when it's implemented - StatsSection.WEEKS -> WEEKS_PROPERTY - StatsSection.MONTHS -> MONTHS_PROPERTY - StatsSection.YEARS -> YEARS_PROPERTY - StatsSection.INSIGHTS, INSIGHT_DETAIL -> INSIGHTS_PROPERTY - StatsSection.DETAIL -> DETAIL_PROPERTY - StatsSection.ANNUAL_STATS -> ANNUAL_STATS_PROPERTY - StatsSection.TOTAL_LIKES_DETAIL -> TOTAL_LIKES_PROPERTY - StatsSection.TOTAL_COMMENTS_DETAIL -> TOTAL_COMMENTS_PROPERTY - StatsSection.TOTAL_FOLLOWERS_DETAIL -> TOTAL_FOLLOWERS_PROPERTY - } - this.track(stat, mapOf(GRANULARITY_PROPERTY to property)) +fun AnalyticsTrackerWrapper.trackWithGranularity(stat: Stat, granularity: StatsGranularity) { + this.track(stat, mapOf(GRANULARITY_PROPERTY to granularity)) } fun AnalyticsTrackerWrapper.trackWithType(stat: Stat, insightType: InsightType) { From e910a0277d11455cabcaef1f85a5464fb3bd6e10 Mon Sep 17 00:00:00 2001 From: Ravi Date: Wed, 31 Jan 2024 15:31:28 +1100 Subject: [PATCH 24/53] Fix detekt reported issues --- .../android/ui/stats/refresh/StatsModule.kt | 1 + .../ui/stats/refresh/lists/BaseListUseCase.kt | 1 - .../refresh/lists/detail/PostDayViewsUseCase.kt | 1 - .../sections/granular/GranularStatelessUseCase.kt | 1 - .../stats/refresh/utils/SelectedSectionManager.kt | 13 +++++++------ .../ui/stats/refresh/lists/StatsDateSelectorTest.kt | 3 ++- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt index 27115506c0c2..74984c278010 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsModule.kt @@ -401,6 +401,7 @@ class StatsModule { @Provides @Singleton @Named(LIST_STATS_USE_CASES) + @Suppress("LongParameterList") fun provideListStatsUseCases( @Named(INSIGHTS_USE_CASE) insightsUseCase: BaseListUseCase, @Named(TRAFFIC_USE_CASE) trafficUseCase: BaseListUseCase, diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/BaseListUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/BaseListUseCase.kt index 91dc8fbeaa7e..b01c21f2abc7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/BaseListUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/BaseListUseCase.kt @@ -13,7 +13,6 @@ import org.wordpress.android.fluxc.network.utils.StatsGranularity import org.wordpress.android.fluxc.store.StatsStore.StatsType import org.wordpress.android.ui.pages.SnackbarMessageHolder import org.wordpress.android.ui.stats.refresh.NavigationTarget -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.UiModel import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase.UseCaseModel diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt index 09d5cd36a78f..d6dd4e02c4d6 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/detail/PostDayViewsUseCase.kt @@ -8,7 +8,6 @@ import org.wordpress.android.fluxc.store.StatsStore.PostDetailType import org.wordpress.android.fluxc.store.stats.PostDetailStore import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.DETAIL import org.wordpress.android.ui.stats.refresh.lists.detail.PostDayViewsUseCase.UiState import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase import org.wordpress.android.ui.stats.refresh.lists.sections.BlockListItem diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatelessUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatelessUseCase.kt index 576a551a2677..f4fc676d1b99 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatelessUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/GranularStatelessUseCase.kt @@ -8,7 +8,6 @@ import org.wordpress.android.fluxc.store.StatsStore.StatsType import org.wordpress.android.ui.stats.refresh.lists.sections.BaseStatsUseCase.StatelessUseCase import org.wordpress.android.ui.stats.refresh.lists.sections.BlockListItem import org.wordpress.android.ui.stats.refresh.utils.StatsSiteProvider -import org.wordpress.android.ui.stats.refresh.utils.toStatsSection import java.util.Date abstract class GranularStatelessUseCase( diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt index cc81dcc1df0b..fc69e6cd1837 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt @@ -10,12 +10,7 @@ import org.wordpress.android.fluxc.network.utils.StatsGranularity.MONTHS import org.wordpress.android.fluxc.network.utils.StatsGranularity.WEEKS import org.wordpress.android.fluxc.network.utils.StatsGranularity.YEARS import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.ANNUAL_STATS -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.DETAIL import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.INSIGHTS -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.TOTAL_COMMENTS_DETAIL -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.TOTAL_FOLLOWERS_DETAIL -import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.TOTAL_LIKES_DETAIL import javax.inject.Inject const val SELECTED_SECTION_KEY = "SELECTED_STATS_SECTION_KEY" @@ -47,7 +42,13 @@ class SelectedSectionManager fun StatsSection.toStatsGranularity(): StatsGranularity? { return when (this) { - StatsSection.TRAFFIC, ANNUAL_STATS, DETAIL, TOTAL_LIKES_DETAIL, TOTAL_COMMENTS_DETAIL, TOTAL_FOLLOWERS_DETAIL, INSIGHTS -> null + StatsSection.TRAFFIC, + StatsSection.ANNUAL_STATS, + StatsSection.DETAIL, + StatsSection.TOTAL_LIKES_DETAIL, + StatsSection.TOTAL_COMMENTS_DETAIL, + StatsSection.TOTAL_FOLLOWERS_DETAIL, + StatsSection.INSIGHTS -> null StatsSection.INSIGHT_DETAIL, StatsSection.DAYS -> DAYS StatsSection.WEEKS -> WEEKS diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/StatsDateSelectorTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/StatsDateSelectorTest.kt index 5859eef1477e..af7fd0adf5f2 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/StatsDateSelectorTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/StatsDateSelectorTest.kt @@ -44,7 +44,8 @@ class StatsDateSelectorTest : BaseUnitTest() { @Before fun setUp() { dateProviderSelectedDate.value = GranularityChange(statsGranularity) - whenever(selectedDateProvider.granularSelectedDateChanged(statsGranularity)).thenReturn(dateProviderSelectedDate) + whenever(selectedDateProvider.granularSelectedDateChanged(statsGranularity)) + .thenReturn(dateProviderSelectedDate) dateSelector = StatsDateSelector( selectedDateProvider, From 47471c790678669f41ca120da27f372417edb844 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 11:46:29 +0530 Subject: [PATCH 25/53] =?UTF-8?q?=E2=86=91=20Updates:=20the=20logic=20to?= =?UTF-8?q?=20use=20three=20web=20views=20for=20each=20tab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sitemonitor/SiteMonitorParentActivity.kt | 86 ++++++++++++------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index 020bd6f5d857..52915c9ec16d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -1,8 +1,8 @@ package org.wordpress.android.ui.sitemonitor import android.annotation.SuppressLint +import android.os.Build import android.os.Bundle -import android.util.Log import android.util.SparseArray import android.view.View import android.view.ViewGroup @@ -24,7 +24,6 @@ import androidx.compose.material.Text import androidx.compose.material3.Surface import androidx.compose.material3.Tab 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 @@ -44,7 +43,9 @@ import org.wordpress.android.ui.WPWebViewActivity import org.wordpress.android.ui.compose.theme.AppTheme import org.wordpress.android.ui.compose.utils.uiStringText import org.wordpress.android.util.extensions.getSerializableExtraCompat +import javax.inject.Inject +@SuppressLint("SetJavaScriptEnabled") @AndroidEntryPoint class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient.SiteMonitorWebViewClientListener { private var savedStateSparseArray = SparseArray() @@ -52,6 +53,39 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. private val siteMonitorParentViewModel: SiteMonitorParentViewModel by viewModels() + @Inject + lateinit var siteMonitorUtils: SiteMonitorUtils + + private val metricsWebView by lazy { + commonWebView(SiteMonitorType.METRICS) + } + + private val phpLogsWebView by lazy { + commonWebView(SiteMonitorType.PHP_LOGS) + } + + private val webServerLogsWebView by lazy { + commonWebView(SiteMonitorType.WEB_SERVER_LOGS) + } + + private fun commonWebView( + siteMonitorType: SiteMonitorType + ) = WebView(this@SiteMonitorParentActivity).apply { + layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY + settings.userAgentString = siteMonitorUtils.getUserAgent() + settings.javaScriptEnabled = true + settings.domStorageEnabled = true + webViewClient = SiteMonitorWebViewClient(this@SiteMonitorParentActivity, siteMonitorType) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // not sure about this one, double check if this works as expected + settings.isAlgorithmicDarkeningAllowed =true + } + } + @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -176,36 +210,15 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. @SuppressLint("SetJavaScriptEnabled") @Composable private fun SiteMonitorWebView(uiState: SiteMonitorUiState, tabType: SiteMonitorType, modifier: Modifier) { - Log.e("Track", "SiteMonitorWebView $uiState") - var webView: WebView? by remember { mutableStateOf(null) } - - Log.e("Track", "SiteMonitorWebView $webView") - - val model = when (uiState) { - is SiteMonitorUiState.Prepared -> uiState.model - is SiteMonitorUiState.Loaded -> uiState.model - else -> null + // retrieve the webview from the actvity + var webView = when (tabType) { + SiteMonitorType.METRICS -> metricsWebView + SiteMonitorType.PHP_LOGS -> phpLogsWebView + SiteMonitorType.WEB_SERVER_LOGS -> webServerLogsWebView } - model?.let { - LaunchedEffect(true) { - webView = WebView(this@SiteMonitorParentActivity).apply { - layoutParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT - ) - scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY - settings.userAgentString = model.userAgent - settings.javaScriptEnabled = true - settings.domStorageEnabled = true - webViewClient = SiteMonitorWebViewClient(this@SiteMonitorParentActivity, tabType) - } - } - if(uiState is SiteMonitorUiState.Prepared) { - webView?.postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, model.addressToLoad.toByteArray()) - } else { - webView?.loadUrl(model.url) - } + if (uiState is SiteMonitorUiState.Prepared) { + webView.postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, uiState.model.addressToLoad.toByteArray()) } Box( @@ -213,19 +226,26 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. contentAlignment = Alignment.Center ) { if (uiState is SiteMonitorUiState.Prepared) { - LoadingState() + LoadingState(modifier) } else { - webView?.let { theWebView -> + webView.let { theWebView -> AndroidView( factory = { theWebView }, update = { webView = it }, - modifier = Modifier.fillMaxSize() + modifier = modifier.fillMaxSize() ) } } } } + override fun onDestroy() { + super.onDestroy() + metricsWebView.destroy() + phpLogsWebView.destroy() + webServerLogsWebView.destroy() + } + override fun onWebViewPageLoaded(url: String, tabType: SiteMonitorType) = siteMonitorParentViewModel.onUrlLoaded(tabType, url) From 5ada1fadf841432b1636865a89425faa900f4063 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 12:14:00 +0530 Subject: [PATCH 26/53] + Adds: top bar view to the activity --- .../sitemonitor/SiteMonitorParentActivity.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index 52915c9ec16d..417393c5ddfc 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.Button import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold import androidx.compose.material.TabRow import androidx.compose.material.Text import androidx.compose.material3.Surface @@ -40,6 +41,8 @@ import org.wordpress.android.R import org.wordpress.android.WordPress import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.ui.WPWebViewActivity +import org.wordpress.android.ui.compose.components.MainTopAppBar +import org.wordpress.android.ui.compose.components.NavigationIcons import org.wordpress.android.ui.compose.theme.AppTheme import org.wordpress.android.ui.compose.utils.uiStringText import org.wordpress.android.util.extensions.getSerializableExtraCompat @@ -103,7 +106,7 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. Surface( modifier = Modifier.fillMaxSize(), ) { - SiteMonitorScreen() + SiteMonitorTabScreen() } } } @@ -130,6 +133,23 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. const val SAVED_STATE_CURRENT_TAB_KEY = "CurrentTabKey" } + @Composable + @SuppressLint("UnusedMaterialScaffoldPaddingParameter") + fun SiteMonitorTabScreen(modifier: Modifier = Modifier) { + Scaffold( + topBar = { + MainTopAppBar( + title = stringResource(id = R.string.site_monitoring), + navigationIcon = NavigationIcons.BackIcon, + onNavigationIconClick = onBackPressedDispatcher::onBackPressed, + ) + }, + content = { + SiteMonitorScreen(modifier = modifier) + } + ) + } + @Composable @SuppressLint("UnusedMaterialScaffoldPaddingParameter") fun SiteMonitorScreen(modifier: Modifier = Modifier) { From 554b42dcb8164993b09bba7caa80a7e389d65990 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 13:02:50 +0530 Subject: [PATCH 27/53] + Adds: the logic to handle initial tab logic --- .../sitemonitor/SiteMonitorParentActivity.kt | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index 399905aad493..15a1cea8727c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -103,13 +103,14 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. currentSelectItemId = savedInstanceState.getInt(SAVED_STATE_CURRENT_TAB_KEY) } else { siteMonitorParentViewModel.start(getSite()) + currentSelectItemId = getInitialTab() } setContent { AppTheme { Surface( modifier = Modifier.fillMaxSize(), ) { - SiteMonitorScreen() + SiteMonitorScreen(initialTab = currentSelectItemId) } } } @@ -125,9 +126,14 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. return requireNotNull(intent.getSerializableExtraCompat(WordPress.SITE)) as SiteModel } - private fun getInitialTab(): SiteMonitorType { - return intent?.getSerializableExtraCompat(ARG_SITE_MONITOR_TYPE_KEY) as SiteMonitorType? + private fun getInitialTab(): Int { + val tab = intent?.getSerializableExtraCompat(ARG_SITE_MONITOR_TYPE_KEY) as SiteMonitorType? ?: SiteMonitorType.METRICS + return when (tab) { + SiteMonitorType.METRICS -> 0 + SiteMonitorType.PHP_LOGS -> 1 + SiteMonitorType.WEB_SERVER_LOGS -> 2 + } } companion object { @@ -138,7 +144,7 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. @Composable @SuppressLint("UnusedMaterialScaffoldPaddingParameter") - fun SiteMonitorTabScreen(modifier: Modifier = Modifier) { + fun SiteMonitorScreen(initialTab: Int, modifier: Modifier = Modifier) { Scaffold( topBar = { MainTopAppBar( @@ -148,15 +154,15 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. ) }, content = { - SiteMonitorScreen(modifier = modifier) + SiteMonitorTab(initialTab, modifier = modifier) } ) } @Composable @SuppressLint("UnusedMaterialScaffoldPaddingParameter") - fun SiteMonitorScreen(modifier: Modifier = Modifier) { - var tabIndex by remember { mutableStateOf(0) } + fun SiteMonitorTab(initialTab: Int, modifier: Modifier = Modifier) { + var tabIndex by remember { mutableStateOf(initialTab) } val tabs = listOf( R.string.site_monitoring_tab_title_metrics, @@ -173,7 +179,9 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. tabs.forEachIndexed { index, title -> Tab(text = { Text(stringResource(id = title)) }, selected = tabIndex == index, - onClick = { tabIndex = index } + onClick = { + tabIndex = index + } ) } } From 54442404fc1d96da673ccef60c8e9f854fec2c3f Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 13:03:41 +0530 Subject: [PATCH 28/53] * Fixes: the incorrect passing of modifier and formatting --- .../sitemonitor/SiteMonitorParentActivity.kt | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index 15a1cea8727c..ad02e584aa8b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -60,15 +60,15 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. private val siteMonitorParentViewModel: SiteMonitorParentViewModel by viewModels() private val metricsWebView by lazy { - commonWebView(SiteMonitorType.METRICS) + commonWebView(SiteMonitorType.METRICS) } private val phpLogsWebView by lazy { - commonWebView(SiteMonitorType.PHP_LOGS) + commonWebView(SiteMonitorType.PHP_LOGS) } private val webServerLogsWebView by lazy { - commonWebView(SiteMonitorType.WEB_SERVER_LOGS) + commonWebView(SiteMonitorType.WEB_SERVER_LOGS) } private fun commonWebView( @@ -85,7 +85,7 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. webViewClient = SiteMonitorWebViewClient(this@SiteMonitorParentActivity, siteMonitorType) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // not sure about this one, double check if this works as expected - settings.isAlgorithmicDarkeningAllowed =true + settings.isAlgorithmicDarkeningAllowed = true } } @@ -240,7 +240,11 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. @SuppressLint("SetJavaScriptEnabled") @Composable - private fun SiteMonitorWebView(uiState: SiteMonitorUiState, tabType: SiteMonitorType, modifier: Modifier) { + private fun SiteMonitorWebView( + uiState: SiteMonitorUiState, + tabType: SiteMonitorType, + modifier: Modifier = Modifier + ) { // retrieve the webview from the actvity var webView = when (tabType) { SiteMonitorType.METRICS -> metricsWebView @@ -257,13 +261,13 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. contentAlignment = Alignment.Center ) { if (uiState is SiteMonitorUiState.Prepared) { - LoadingState(modifier) + LoadingState() } else { webView.let { theWebView -> AndroidView( factory = { theWebView }, update = { webView = it }, - modifier = modifier.fillMaxSize() + modifier = Modifier.fillMaxWidth() ) } } From 32877e77c1f8a088965fe0646f11df70d0c291ae Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 13:04:58 +0530 Subject: [PATCH 29/53] * Fixes: Incorrect passing of modifier instance --- .../android/ui/sitemonitor/SiteMonitorParentActivity.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index ad02e584aa8b..4659db0bd29a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -186,15 +186,15 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. } } when (tabIndex) { - 0 -> SiteMonitorTabContent(SiteMonitorType.METRICS, modifier) - 1 -> SiteMonitorTabContent(SiteMonitorType.PHP_LOGS, modifier) - 2 -> SiteMonitorTabContent(SiteMonitorType.WEB_SERVER_LOGS, modifier) + 0 -> SiteMonitorTabContent(SiteMonitorType.METRICS) + 1 -> SiteMonitorTabContent(SiteMonitorType.PHP_LOGS) + 2 -> SiteMonitorTabContent(SiteMonitorType.WEB_SERVER_LOGS) } } } @Composable - private fun SiteMonitorTabContent(tabType: SiteMonitorType, modifier: Modifier) { + private fun SiteMonitorTabContent(tabType: SiteMonitorType, modifier: Modifier = Modifier) { val uiState by remember(key1 = tabType) { siteMonitorParentViewModel.getUiState(tabType) } From d532763873f3d4ebef2d3af8d82689570ef538aa Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 13:19:07 +0530 Subject: [PATCH 30/53] * Fixes: Incorrect tab tracking and activity tracking --- .../android/ui/sitemonitor/SiteMonitorParentActivity.kt | 3 +-- .../android/ui/sitemonitor/SiteMonitorTabViewModel.kt | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index 4659db0bd29a..d52f5d0e1608 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -93,8 +93,6 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - siteMonitorUtils.trackActivityLaunched() - if (savedInstanceState != null) { savedStateSparseArray = savedInstanceState.getSparseParcelableArray( SAVED_STATE_CONTAINER_KEY @@ -180,6 +178,7 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. Tab(text = { Text(stringResource(id = title)) }, selected = tabIndex == index, onClick = { + siteMonitorUtils.trackTabLoaded(SiteMonitorType.entries[index]) tabIndex = index } ) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt index 90a47486ed93..8e4e681efcf1 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt @@ -105,7 +105,6 @@ class SiteMonitorTabViewModelSlice @Inject constructor( } fun onUrlLoaded(url: String) { - siteMonitorUtils.trackTabLoaded(siteMonitorType) if (uiState.value is SiteMonitorUiState.Prepared){ postUiState(SiteMonitorUiState .Loaded((_uiState.value as SiteMonitorUiState.Prepared).model.copy(url = url))) From 89f98957bdabf9de635a1a361034b53acebf374d Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 14:23:06 +0530 Subject: [PATCH 31/53] - Removes: Redundant logs from SiteMonitorWebViewClient --- .../android/ui/sitemonitor/SiteMonitorWebViewClient.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClient.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClient.kt index 9938522b782d..af0717e8481b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClient.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClient.kt @@ -1,7 +1,6 @@ package org.wordpress.android.ui.sitemonitor import android.graphics.Bitmap -import android.util.Log import android.webkit.WebResourceError import android.webkit.WebResourceRequest import android.webkit.WebView @@ -29,7 +28,6 @@ class SiteMonitorWebViewClient( } override fun onPageFinished(view: WebView, url: String?) { - Log.e("Site Monitor Webview client", "onPageFinished: $url") super.onPageFinished(view, url) if (!errorReceived) { url?.let { listener.onWebViewPageLoaded(it, tabType) } From 7bf963ae8ec51e0974e63c0e8c4db0a941d8d8b2 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 14:35:54 +0530 Subject: [PATCH 32/53] =?UTF-8?q?=E2=86=92=20Moves:=20Site=20Monitor=20Tab?= =?UTF-8?q?=20header=20logic=20to=20activity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sitemonitor/SiteMonitorParentActivity.kt | 44 ++++++++----- .../ui/sitemonitor/SiteMonitorTabHeader.kt | 61 ------------------- 2 files changed, 30 insertions(+), 75 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabHeader.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index d52f5d0e1608..ebab29ae5870 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -20,10 +20,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material.Button import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold -import androidx.compose.material.TabRow import androidx.compose.material.Text import androidx.compose.material3.Surface import androidx.compose.material3.Tab +import androidx.compose.material3.TabRowDefaults +import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -33,6 +34,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.fragment.app.Fragment @@ -152,35 +154,48 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. ) }, content = { - SiteMonitorTab(initialTab, modifier = modifier) + SiteMonitorHeader(initialTab, modifier = modifier) } ) } @Composable @SuppressLint("UnusedMaterialScaffoldPaddingParameter") - fun SiteMonitorTab(initialTab: Int, modifier: Modifier = Modifier) { + fun SiteMonitorHeader(initialTab: Int, modifier: Modifier = Modifier) { var tabIndex by remember { mutableStateOf(initialTab) } - val tabs = listOf( - R.string.site_monitoring_tab_title_metrics, - R.string.site_monitoring_tab_title_php_logs, - R.string.site_monitoring_tab_title_web_server_logs - ) + val tabs = SiteMonitorTabItem.entries Column(modifier = modifier.fillMaxWidth()) { - TabRow( + androidx.compose.material3.TabRow( selectedTabIndex = tabIndex, - backgroundColor = MaterialTheme.colors.surface, + containerColor = MaterialTheme.colors.surface, contentColor = MaterialTheme.colors.onSurface, + indicator = { tabPositions -> + // Customizing the indicator color and style + TabRowDefaults.Indicator( + Modifier.tabIndicatorOffset(tabPositions[tabIndex]), + color = MaterialTheme.colors.onSurface, + height = 2.0.dp + ) + } ) { - tabs.forEachIndexed { index, title -> - Tab(text = { Text(stringResource(id = title)) }, + tabs.forEachIndexed { index, item -> + Tab( + text = { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + androidx.compose.material3.Text( + text = stringResource(item.title), + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + }, selected = tabIndex == index, onClick = { - siteMonitorUtils.trackTabLoaded(SiteMonitorType.entries[index]) + siteMonitorUtils.trackTabLoaded(tabs[index].siteMonitorType) tabIndex = index - } + }, ) } } @@ -201,6 +216,7 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. is SiteMonitorUiState.Preparing -> LoadingState(modifier) is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitorWebView(uiState, tabType, modifier) + is SiteMonitorUiState.Error -> SiteMonitorError(uiState as SiteMonitorUiState.Error, modifier) } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabHeader.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabHeader.kt deleted file mode 100644 index 7a15059a31fc..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabHeader.kt +++ /dev/null @@ -1,61 +0,0 @@ -package org.wordpress.android.ui.sitemonitor - -import androidx.compose.foundation.layout.Column -import androidx.compose.material.MaterialTheme -import androidx.compose.material3.Tab -import androidx.compose.material3.TabRow -import androidx.compose.material3.TabRowDefaults -import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.dp - -@Composable -fun SiteMonitorTabHeader(navController: (String) -> Unit) { - var selectedTabIndex by rememberSaveable { mutableIntStateOf(0) } - val tabs = listOf( - SiteMonitorTabItem.Metrics, - SiteMonitorTabItem.PHPLogs, - SiteMonitorTabItem.WebServerLogs - ) - TabRow( - selectedTabIndex = selectedTabIndex, - containerColor = MaterialTheme.colors.surface, - contentColor = MaterialTheme.colors.onSurface, - indicator = { tabPositions -> - // Customizing the indicator color and style - TabRowDefaults.Indicator( - Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex]), - color = MaterialTheme.colors.onSurface, - height = 2.0.dp - ) - } - ) { - tabs.forEachIndexed { index, item -> - Tab( - text = { - Column (horizontalAlignment = Alignment.CenterHorizontally) { - Text( - text = stringResource(item.title), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - }, - selected = selectedTabIndex == index, - onClick = { - selectedTabIndex = index - navController(item.route) - }, - ) - } - } -} From dc1a6ba99f50c6634ed62fe80aad09275a311de5 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 14:39:03 +0530 Subject: [PATCH 33/53] - Removes: Site Monitor Fragment and Fragment container --- .../SiteMonitorFragmentContainer.kt | 76 ------- .../sitemonitor/SiteMonitorParentActivity.kt | 10 + .../ui/sitemonitor/SiteMonitorTabFragment.kt | 199 ------------------ 3 files changed, 10 insertions(+), 275 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorFragmentContainer.kt delete mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabFragment.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorFragmentContainer.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorFragmentContainer.kt deleted file mode 100644 index eb5eea65c8a1..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorFragmentContainer.kt +++ /dev/null @@ -1,76 +0,0 @@ -package org.wordpress.android.ui.sitemonitor - -import android.content.Context -import android.view.View -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalView -import androidx.compose.ui.viewinterop.AndroidView -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentActivity -import androidx.fragment.app.FragmentContainerView -import androidx.fragment.app.FragmentTransaction -import androidx.fragment.app.commit -import androidx.fragment.app.findFragment - -@Suppress("SwallowedException") -@Composable -fun SiteMonitorFragmentContainer( - modifier: Modifier = Modifier, - commit: FragmentTransaction.(containerId: Int) -> Unit -) { - val currentLocalView = LocalView.current - // Using the current view, check if a parent fragment exists. - // This will help ensure that the fragment are nested correctly. - // This assists in saving/restoring the fragments to their proper state - val parentFragment = remember(currentLocalView) { - try { - currentLocalView.findFragment() - } catch (e: IllegalStateException) { - null - } - } - val viewId by rememberSaveable { mutableIntStateOf(View.generateViewId()) } - val container = remember { mutableStateOf(null) } - val viewSection: (Context) -> View = remember(currentLocalView) { - { context -> - FragmentContainerView(context) - .apply { id = viewId } - .also { - val fragmentManager = parentFragment?.childFragmentManager - ?: (context as? FragmentActivity)?.supportFragmentManager - fragmentManager?.commit { commit(it.id) } - container.value = it - } - } - } - AndroidView( - modifier = modifier, - factory = viewSection, - update = {} - ) - - // Be sure to clean up the fragments when the FragmentContainer is disposed - val localContext = LocalContext.current - DisposableEffect(currentLocalView, localContext, container) { - onDispose { - val fragmentManager = parentFragment?.childFragmentManager - ?: (localContext as? FragmentActivity)?.supportFragmentManager - // Use the FragmentContainerView to find the inflated fragment - val existingFragment = fragmentManager?.findFragmentById(container.value?.id ?: 0) - if (existingFragment != null && !fragmentManager.isStateSaved) { - // A composable has been removed from the hierarchy if the state isn't saved - fragmentManager.commit { - remove(existingFragment) - } - } - } - } -} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index ebab29ae5870..4307590192b4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -21,6 +21,7 @@ import androidx.compose.material.Button import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold import androidx.compose.material.Text +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Surface import androidx.compose.material3.Tab import androidx.compose.material3.TabRowDefaults @@ -220,6 +221,15 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. is SiteMonitorUiState.Error -> SiteMonitorError(uiState as SiteMonitorUiState.Error, modifier) } } + @Composable + fun LoadingState(modifier: Modifier = Modifier) { + Box( + contentAlignment = Alignment.Center, + modifier = modifier.fillMaxSize() + ) { + CircularProgressIndicator() + } + } @Composable fun SiteMonitorError(error: SiteMonitorUiState.Error, modifier: Modifier = Modifier) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabFragment.kt deleted file mode 100644 index 841612550ae8..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabFragment.kt +++ /dev/null @@ -1,199 +0,0 @@ -package org.wordpress.android.ui.sitemonitor - -import android.annotation.SuppressLint -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.webkit.WebView -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material.Button -import androidx.compose.material3.CircularProgressIndicator -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.platform.ComposeView -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.viewinterop.AndroidView -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import dagger.hilt.android.AndroidEntryPoint -import org.wordpress.android.WordPress -import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.ui.WPWebViewActivity -import org.wordpress.android.ui.compose.utils.uiStringText - -@AndroidEntryPoint -class SiteMonitorTabFragment : Fragment(), SiteMonitorWebViewClient.SiteMonitorWebViewClientListener { - val tabType by lazy { getSiteMonitorType() } - - private val siteMonitorWebViewClient = SiteMonitorWebViewClient(this@SiteMonitorTabFragment, SiteMonitorType.PHP_LOGS) - - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View = ComposeView(requireContext()).apply { - setContent { - SiteMonitorTabContent() - } - } - - override fun onResume() { - super.onResume() - } - - private val viewModel: SiteMonitorParentViewModel by activityViewModels() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - } - - @Suppress("DEPRECATION") - private fun getSiteMonitorType(): SiteMonitorType { - return requireNotNull(arguments?.getSerializable(KEY_SITE_MONITOR_TYPE)) as SiteMonitorType - } - - override fun onWebViewPageLoaded(url: String, tabType: SiteMonitorType) = - viewModel.onUrlLoaded(tabType, url) - - override fun onWebViewReceivedError(url: String, tabType: SiteMonitorType) = - viewModel.onWebViewError(tabType) - - companion object { - const val KEY_URL_TEMPLATE = "KEY_URL" - const val KEY_SITE_MONITOR_TYPE = "KEY_SITE_MONITOR_TYPE" - fun newInstance(url: String, type: SiteMonitorType, site: SiteModel): Fragment { - val fragment = SiteMonitorTabFragment() - val argument = Bundle() - argument.putString(KEY_URL_TEMPLATE, url) - argument.putSerializable(KEY_SITE_MONITOR_TYPE, type) - argument.putSerializable(WordPress.SITE, site) - fragment.arguments = argument - return fragment - } - } - - @Composable - private fun SiteMonitorTabContent() { - val uiState by viewModel.getUiState(tabType) - when (uiState) { - is SiteMonitorUiState.Preparing -> LoadingState() - is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitorWebView(uiState) - is SiteMonitorUiState.Error -> SiteMonitorError(uiState as SiteMonitorUiState.Error) - } - } - - @Composable - fun SiteMonitorError(error: SiteMonitorUiState.Error) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = Modifier - .padding(20.dp) - .fillMaxWidth() - .fillMaxHeight(), - ) { - androidx.compose.material.Text( - text = uiStringText(uiString = error.title), - style = androidx.compose.material.MaterialTheme.typography.h5, - textAlign = TextAlign.Center - ) - androidx.compose.material.Text( - text = uiStringText(uiString = error.description), - style = androidx.compose.material.MaterialTheme.typography.body1, - textAlign = TextAlign.Center, - modifier = Modifier.padding(top = 8.dp) - ) - if (error.button != null) { - Button( - modifier = Modifier.padding(top = 8.dp), - onClick = error.button.click - ) { - androidx.compose.material.Text(text = uiStringText(uiString = error.button.text)) - } - } - } - } - - @SuppressLint("SetJavaScriptEnabled") - @Composable - private fun SiteMonitorWebView(uiState: SiteMonitorUiState) { - Log.e("Track", "SiteMonitorWebView $uiState") - var webView: WebView? by remember { mutableStateOf(null) } - - Log.e("Track", "SiteMonitorWebView $webView") - - if (uiState is SiteMonitorUiState.Prepared) { - val model = uiState.model - LaunchedEffect(true) { - webView = WebView(requireContext()).apply { - layoutParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT - ) - scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY - settings.userAgentString = model.userAgent - settings.javaScriptEnabled = true - settings.domStorageEnabled = true - webViewClient = SiteMonitorWebViewClient(this@SiteMonitorTabFragment, SiteMonitorType.PHP_LOGS) - postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, model.addressToLoad.toByteArray()) - } - } - } else if (uiState is SiteMonitorUiState.Loaded) { - val model = uiState.model - LaunchedEffect(true) { - webView = WebView(requireContext()).apply { - layoutParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT - ) - scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY - settings.userAgentString = model.userAgent - settings.javaScriptEnabled = true - settings.domStorageEnabled = true - loadUrl(model.url) - } - } - } - - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - if (uiState is SiteMonitorUiState.Prepared) { - LoadingState() - } else { - webView?.let { theWebView -> - AndroidView( - factory = { theWebView }, - modifier = Modifier.fillMaxSize() - ) - } - } - } - } -} - -@Composable -fun LoadingState(modifier: Modifier = Modifier) { - Box( - contentAlignment = Alignment.Center, - modifier = modifier.fillMaxSize() - ) { - CircularProgressIndicator() - } -} From 8a6984acafa847575735a1ef6d40781253ae562f Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 14:39:27 +0530 Subject: [PATCH 34/53] - Removes: Redundant SiteMonitorTabNavigation.kt --- .../sitemonitor/SiteMonitorTabNavigation.kt | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabNavigation.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabNavigation.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabNavigation.kt deleted file mode 100644 index 023e651a66d5..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabNavigation.kt +++ /dev/null @@ -1,20 +0,0 @@ -package org.wordpress.android.ui.sitemonitor - -import androidx.compose.foundation.layout.Box -import androidx.compose.runtime.Composable -import androidx.compose.runtime.saveable.rememberSaveableStateHolder -import androidx.compose.ui.Modifier - -@Composable -fun SiteMonitorTabNavigation ( - currentScreen: T, - modifier: Modifier = Modifier, - content: @Composable (T) -> Unit -) { - val saveableStateHolder = rememberSaveableStateHolder() - Box(modifier) { - saveableStateHolder.SaveableStateProvider(currentScreen) { - content(currentScreen) - } - } -} From adf41776d7531d7944c5621c024b86813065d26b Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 14:46:35 +0530 Subject: [PATCH 35/53] * Reverts: the change for loaded state object as its no longer needed --- .../android/ui/sitemonitor/SiteMonitorParentActivity.kt | 2 +- .../android/ui/sitemonitor/SiteMonitorParentViewModel.kt | 8 ++++---- .../android/ui/sitemonitor/SiteMonitorTabViewModel.kt | 5 ++--- .../android/ui/sitemonitor/SiteMonitorUiState.kt | 4 +--- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index 4307590192b4..7a36e9a19334 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -307,7 +307,7 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. } override fun onWebViewPageLoaded(url: String, tabType: SiteMonitorType) = - siteMonitorParentViewModel.onUrlLoaded(tabType, url) + siteMonitorParentViewModel.onUrlLoaded(tabType) override fun onWebViewReceivedError(url: String, tabType: SiteMonitorType) = siteMonitorParentViewModel.onWebViewError(tabType) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt index b430397116d6..2e0e9ad03813 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt @@ -50,16 +50,16 @@ class SiteMonitorParentViewModel @Inject constructor( } } - fun onUrlLoaded(siteMonitorType: SiteMonitorType, url: String) { + fun onUrlLoaded(siteMonitorType: SiteMonitorType) { when (siteMonitorType) { SiteMonitorType.METRICS -> { - metricsViewModel.onUrlLoaded(url) + metricsViewModel.onUrlLoaded() } SiteMonitorType.PHP_LOGS -> { - phpLogViewModel.onUrlLoaded(url) + phpLogViewModel.onUrlLoaded() } SiteMonitorType.WEB_SERVER_LOGS -> { - webServerViewModel.onUrlLoaded(url) + webServerViewModel.onUrlLoaded() } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt index 8e4e681efcf1..fab664186e62 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt @@ -104,10 +104,9 @@ class SiteMonitorTabViewModelSlice @Inject constructor( } } - fun onUrlLoaded(url: String) { + fun onUrlLoaded() { if (uiState.value is SiteMonitorUiState.Prepared){ - postUiState(SiteMonitorUiState - .Loaded((_uiState.value as SiteMonitorUiState.Prepared).model.copy(url = url))) + postUiState(SiteMonitorUiState.Loaded) } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUiState.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUiState.kt index dfeb23933876..8b7dee5a31cc 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUiState.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUiState.kt @@ -10,9 +10,7 @@ sealed class SiteMonitorUiState { val model: SiteMonitorModel ) : SiteMonitorUiState() - data class Loaded( - val model: SiteMonitorModel - ) : SiteMonitorUiState() + object Loaded : SiteMonitorUiState() open class Error( val title: UiString, From da6711c088938ee7e4a405f49feee17bbc015096 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 15:24:13 +0530 Subject: [PATCH 36/53] * Renames: SiteMonitorTabViewModel.kt to SiteMonitorTabViewModelSlice --- ...SiteMonitorTabViewModel.kt => SiteMonitorTabViewModelSlice.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/{SiteMonitorTabViewModel.kt => SiteMonitorTabViewModelSlice.kt} (100%) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSlice.kt similarity index 100% rename from WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSlice.kt From 8ec6d7eac86c05b3f4abcc2835db6d862adf4275 Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Wed, 31 Jan 2024 11:31:26 +0100 Subject: [PATCH 37/53] Update WordPress metadata translations for 24.1 --- fastlane/metadata/android/ar/changelogs/1400.txt | 6 ------ fastlane/metadata/android/ar/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/de-DE/changelogs/1400.txt | 6 ------ fastlane/metadata/android/de-DE/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/en-US/changelogs/1400.txt | 5 ----- fastlane/metadata/android/en-US/changelogs/1405.txt | 4 ++++ fastlane/metadata/android/es-ES/changelogs/1400.txt | 6 ------ fastlane/metadata/android/es-ES/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/fr-CA/changelogs/1400.txt | 6 ------ fastlane/metadata/android/fr-CA/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/fr-FR/changelogs/1400.txt | 6 ------ fastlane/metadata/android/fr-FR/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/id/changelogs/1400.txt | 6 ------ fastlane/metadata/android/id/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/it-IT/changelogs/1400.txt | 6 ------ fastlane/metadata/android/it-IT/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/iw-IL/changelogs/1400.txt | 6 ------ fastlane/metadata/android/iw-IL/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/ja-JP/changelogs/1400.txt | 6 ------ fastlane/metadata/android/ja-JP/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/ko-KR/changelogs/1400.txt | 6 ------ fastlane/metadata/android/ko-KR/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/nl-NL/changelogs/1400.txt | 6 ------ fastlane/metadata/android/nl-NL/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/ru-RU/changelogs/1400.txt | 6 ------ fastlane/metadata/android/ru-RU/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/sv-SE/changelogs/1400.txt | 6 ------ fastlane/metadata/android/sv-SE/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/tr-TR/changelogs/1400.txt | 6 ------ fastlane/metadata/android/tr-TR/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/zh-CN/changelogs/1400.txt | 6 ------ fastlane/metadata/android/zh-CN/changelogs/1405.txt | 5 +++++ fastlane/metadata/android/zh-TW/changelogs/1400.txt | 6 ------ fastlane/metadata/android/zh-TW/changelogs/1405.txt | 5 +++++ 34 files changed, 84 insertions(+), 101 deletions(-) delete mode 100644 fastlane/metadata/android/ar/changelogs/1400.txt create mode 100644 fastlane/metadata/android/ar/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/de-DE/changelogs/1400.txt create mode 100644 fastlane/metadata/android/de-DE/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/en-US/changelogs/1400.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/es-ES/changelogs/1400.txt create mode 100644 fastlane/metadata/android/es-ES/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/fr-CA/changelogs/1400.txt create mode 100644 fastlane/metadata/android/fr-CA/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/fr-FR/changelogs/1400.txt create mode 100644 fastlane/metadata/android/fr-FR/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/id/changelogs/1400.txt create mode 100644 fastlane/metadata/android/id/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/it-IT/changelogs/1400.txt create mode 100644 fastlane/metadata/android/it-IT/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/iw-IL/changelogs/1400.txt create mode 100644 fastlane/metadata/android/iw-IL/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/ja-JP/changelogs/1400.txt create mode 100644 fastlane/metadata/android/ja-JP/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/ko-KR/changelogs/1400.txt create mode 100644 fastlane/metadata/android/ko-KR/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/nl-NL/changelogs/1400.txt create mode 100644 fastlane/metadata/android/nl-NL/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/ru-RU/changelogs/1400.txt create mode 100644 fastlane/metadata/android/ru-RU/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/sv-SE/changelogs/1400.txt create mode 100644 fastlane/metadata/android/sv-SE/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/tr-TR/changelogs/1400.txt create mode 100644 fastlane/metadata/android/tr-TR/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/zh-CN/changelogs/1400.txt create mode 100644 fastlane/metadata/android/zh-CN/changelogs/1405.txt delete mode 100644 fastlane/metadata/android/zh-TW/changelogs/1400.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/1405.txt diff --git a/fastlane/metadata/android/ar/changelogs/1400.txt b/fastlane/metadata/android/ar/changelogs/1400.txt deleted file mode 100644 index 17b633c518cd..000000000000 --- a/fastlane/metadata/android/ar/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -تحديثات محرر المكوّن: -- تظل لوحة مفاتيح الجهاز موجودة عند تحرير مكوّنات النص -- عمليات التمرير التلقائية في الشاشة إلى المكوّنات المدرجة حديثًا -- إلغاء تحديد المكوّنات عن طريق الضغط على زر الرجوع في جهازك -- مشاركة أنواع الوسائط المختلفة على التطبيق مرة واحدة من دون تعطيل diff --git a/fastlane/metadata/android/ar/changelogs/1405.txt b/fastlane/metadata/android/ar/changelogs/1405.txt new file mode 100644 index 000000000000..ebfc445a886d --- /dev/null +++ b/fastlane/metadata/android/ar/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- تلقَّ تنبيهات عندما تعمل من دون اتصال بالإنترنت. +- تتوقف عمليات رفع مكوّنات الصور مؤقتًا عندما تفقد الاتصال بالإنترنت ويتم استئنافها عند إعادة الاتصال. +- حدد تدرجًا مخصصًا في المحرر وشاهد مؤشر اللون. +- يكون سهما "إلى الأمام" و"إلى الخلف" صحيحين للقراء من اليمين إلى اليسار. diff --git a/fastlane/metadata/android/de-DE/changelogs/1400.txt b/fastlane/metadata/android/de-DE/changelogs/1400.txt deleted file mode 100644 index 7a22c1f07bcf..000000000000 --- a/fastlane/metadata/android/de-DE/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -Block-Editor-Aktualisierungen: -- Gerätetastatur bleibt beim Bearbeiten von Textblöcken erhalten -- Die Ansicht scrollt automatisch zu neu eingefügten Blöcken -- Hebe die Auswahl von Blöcken auf, indem du den Zurück-Button deines Geräts drückst -- Teile verschiedene Medientypen gleichzeitig in der App, ohne Abstürze diff --git a/fastlane/metadata/android/de-DE/changelogs/1405.txt b/fastlane/metadata/android/de-DE/changelogs/1405.txt new file mode 100644 index 000000000000..b15fbce878ef --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- Du wirst benachrichtigt, wenn du offline arbeitest. +- Uploads auf Bildblöcke werden pausiert, wenn deine Internetverbindung unterbrochen ist, und fortgesetzt, sobald die Verbindung wiederhergestellt ist. +- Du kannst im Editor einen individuellen Verlauf auswählen und erhältst einen Farbhinweis. +- Die Pfeile für vor und zurück sind bei Rechts-nach-Links-Sprachen richtig. diff --git a/fastlane/metadata/android/en-US/changelogs/1400.txt b/fastlane/metadata/android/en-US/changelogs/1400.txt deleted file mode 100644 index 33452ef2e9ee..000000000000 --- a/fastlane/metadata/android/en-US/changelogs/1400.txt +++ /dev/null @@ -1,5 +0,0 @@ -Block Editor updates: -- Device keyboard remains when editing text blocks -- Screen auto-scrolls to newly inserted blocks -- Unselect blocks by pressing your device’s back button -- Share different media types to the app at once without crashing diff --git a/fastlane/metadata/android/en-US/changelogs/1405.txt b/fastlane/metadata/android/en-US/changelogs/1405.txt new file mode 100644 index 000000000000..ab3a2cba51aa --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/1405.txt @@ -0,0 +1,4 @@ +- Get notified when you’re working offline. +- Image block uploads pause when you lose internet and resume when you reconnect. +- Select a custom gradient in the editor and see a color indicator. +- “Forward” and “back” arrows are correct for right-to-left readers. diff --git a/fastlane/metadata/android/es-ES/changelogs/1400.txt b/fastlane/metadata/android/es-ES/changelogs/1400.txt deleted file mode 100644 index 9b98113ead1d..000000000000 --- a/fastlane/metadata/android/es-ES/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -Actualizaciones del Editor de bloques: -- El teclado del dispositivo se mantiene al editar bloques de texto. -- La pantalla se desplaza automáticamente a los bloques recién insertados. -- Deselecciona los bloques pulsando el botón Atrás de tu dispositivo. -- Comparte diferentes tipos de medios en la aplicación a la vez sin que se bloquee. diff --git a/fastlane/metadata/android/es-ES/changelogs/1405.txt b/fastlane/metadata/android/es-ES/changelogs/1405.txt new file mode 100644 index 000000000000..9531126af905 --- /dev/null +++ b/fastlane/metadata/android/es-ES/changelogs/1405.txt @@ -0,0 +1,5 @@ +2.4.1: +- Recibe avisos cuando estés trabajando desconectado. +- Las subidas al bloque de imagen que se pausan cuando pierdes la conexión a Internet y se reanudan cuando vuelves a conectar. +- Selecciona un gradiente personalizado en el editor y verás un indicador de color. +- Las flechas de «adelante» y «atrás» ahora están correctamente para lectores de derecha a izquierda. diff --git a/fastlane/metadata/android/fr-CA/changelogs/1400.txt b/fastlane/metadata/android/fr-CA/changelogs/1400.txt deleted file mode 100644 index 87890bb49277..000000000000 --- a/fastlane/metadata/android/fr-CA/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0 : -Mises à jour de l'éditeur de blocs : -- Le clavier de l’appareil reste visible lors de l’édition de blocs Paragraphe -- L’écran défile automatiquement jusqu’aux blocs qui viennent d’être insérés -- Désélectionner des blocs en appuyant sur le bouton Retour de votre appareil -- Partager simultanément divers types de médias vers l’application sans incident diff --git a/fastlane/metadata/android/fr-CA/changelogs/1405.txt b/fastlane/metadata/android/fr-CA/changelogs/1405.txt new file mode 100644 index 000000000000..0a7d474c1667 --- /dev/null +++ b/fastlane/metadata/android/fr-CA/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1 : +- Recevez une notification lorsque vous travaillez hors ligne. +- Les mises en ligne de blocs Image sont suspendues en cas de perte de votre connexion Internet et reprennent dès reconnexion. +- Sélectionnez un dégradé personnalisé dans l’éditeur, un indicateur de couleur apparaît. +- Les flèches s’affichent dans le bon sens pour les lecteurs de langues RTL. diff --git a/fastlane/metadata/android/fr-FR/changelogs/1400.txt b/fastlane/metadata/android/fr-FR/changelogs/1400.txt deleted file mode 100644 index 87890bb49277..000000000000 --- a/fastlane/metadata/android/fr-FR/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0 : -Mises à jour de l'éditeur de blocs : -- Le clavier de l’appareil reste visible lors de l’édition de blocs Paragraphe -- L’écran défile automatiquement jusqu’aux blocs qui viennent d’être insérés -- Désélectionner des blocs en appuyant sur le bouton Retour de votre appareil -- Partager simultanément divers types de médias vers l’application sans incident diff --git a/fastlane/metadata/android/fr-FR/changelogs/1405.txt b/fastlane/metadata/android/fr-FR/changelogs/1405.txt new file mode 100644 index 000000000000..0a7d474c1667 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1 : +- Recevez une notification lorsque vous travaillez hors ligne. +- Les mises en ligne de blocs Image sont suspendues en cas de perte de votre connexion Internet et reprennent dès reconnexion. +- Sélectionnez un dégradé personnalisé dans l’éditeur, un indicateur de couleur apparaît. +- Les flèches s’affichent dans le bon sens pour les lecteurs de langues RTL. diff --git a/fastlane/metadata/android/id/changelogs/1400.txt b/fastlane/metadata/android/id/changelogs/1400.txt deleted file mode 100644 index ef674133b1d8..000000000000 --- a/fastlane/metadata/android/id/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -Pembaruan Editor Blok: -- Keyboard perangkat tetap terlihat ketika menyunting blok teks -- Layar bergulir otomatis ke blok yang baru disisipkan -- Batalkan pemilihan blok dengan menekan tombol kembali pada perangkat -- Bagikan berbagai jenis media ke aplikasi sekaligus tanpa crash diff --git a/fastlane/metadata/android/id/changelogs/1405.txt b/fastlane/metadata/android/id/changelogs/1405.txt new file mode 100644 index 000000000000..a68b18255349 --- /dev/null +++ b/fastlane/metadata/android/id/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- Dapatkan pemberitahuan ketika Anda sedang offline. +- Pengunggahan ke blok gambar dijeda saat internet terputus dan dilanjutkan saat internet tersambung kembali. +- Pilih gradien kustom di editor dan lihat indikator warna. +- Panah “maju” dan “mundur” sudah sesuai untuk pembaca tulisan dari kanan ke kiri. diff --git a/fastlane/metadata/android/it-IT/changelogs/1400.txt b/fastlane/metadata/android/it-IT/changelogs/1400.txt deleted file mode 100644 index 5f7eb1bf587e..000000000000 --- a/fastlane/metadata/android/it-IT/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -Aggiornamenti all'editor dei blocchi: -- La tastiera del dispositivo rimane attiva durante la modifica dei blocchi di testo -- La schermata scorre automaticamente sui blocchi appena inseriti -- Deseleziona i blocchi premendo il tasto indietro del tuo dispositivo -- Condividi diversi tipi di media nell'app in una volta sola senza che si verifichino arresti anomali diff --git a/fastlane/metadata/android/it-IT/changelogs/1405.txt b/fastlane/metadata/android/it-IT/changelogs/1405.txt new file mode 100644 index 000000000000..aa03b6d9095f --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- Ricevi notifiche mentre lavori offline. +- I caricamenti del blocco immagine vengono messi in pausa quando perdi la connessione internet e ripresi quando ti riconnetti. +- Seleziona un gradiente personalizzato nell'editor e vedi un indicatore di colore. +- Sono state sistemate le frecce avanti/indietro per chi legge da destra verso sinistra. diff --git a/fastlane/metadata/android/iw-IL/changelogs/1400.txt b/fastlane/metadata/android/iw-IL/changelogs/1400.txt deleted file mode 100644 index f1804b5d0bbc..000000000000 --- a/fastlane/metadata/android/iw-IL/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -עדכונים בעורך הבלוקים: -- המקלדת של המכשיר נשארת במקומה במהלך עריכת בלוקים של טקסט -- המסך גולל באופן אוטומטי לבלוקים החדשים שנוספו -- לבטל את הבחירה בבלוקים על ידי לחיצה על כפתור החזרה במכשיר -- לשתף במקביל סוגי מדיה שונים באפליקציה, ללא קריסות diff --git a/fastlane/metadata/android/iw-IL/changelogs/1405.txt b/fastlane/metadata/android/iw-IL/changelogs/1405.txt new file mode 100644 index 000000000000..aff27d0f1f43 --- /dev/null +++ b/fastlane/metadata/android/iw-IL/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- לקבל הודעה כאשר העבודה מתבצעת באופן לא מקוון. +- העלאות של הבלוק 'תמונה' מושהות אם החיבור לאינטרנט אובד וממשיכות שוב לאחר ההתחברות מחדש. +- ניתן לבחור מעבר צבע מותאם אישית בעורך ולראות סמן צבע. +- החצים 'קדימה' ו'חזרה' מוצגים בצורה נכונה לקוראי שפות עם כיווניות מימין לשמאל. diff --git a/fastlane/metadata/android/ja-JP/changelogs/1400.txt b/fastlane/metadata/android/ja-JP/changelogs/1400.txt deleted file mode 100644 index 4e41d3e19d03..000000000000 --- a/fastlane/metadata/android/ja-JP/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -ブロックエディターの更新: -- テキストブロックの編集時にデバイスのキーボードがそのままになります -- 新しく挿入されたブロックまで画面が自動スクロールされます -- 端末の戻るボタンを押すとブロックの選択が解除されます -- クラッシュすることなくさまざまな種類のメディアをアプリに一度に共有できます diff --git a/fastlane/metadata/android/ja-JP/changelogs/1405.txt b/fastlane/metadata/android/ja-JP/changelogs/1405.txt new file mode 100644 index 000000000000..c522eb94b342 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- オフラインで作業しているときに通知を受け取ります。 +- 画像ブロックのアップロードは、インターネットが切断されると一時停止され、再度接続すると再開します。 +- エディターでカスタムグラデーションを選択すると、カラーインジケーターが表示されます。 +- 右から左方向に読むリーダーの「左」と「右」向きの矢印が修正されています。 diff --git a/fastlane/metadata/android/ko-KR/changelogs/1400.txt b/fastlane/metadata/android/ko-KR/changelogs/1400.txt deleted file mode 100644 index fa1618094eee..000000000000 --- a/fastlane/metadata/android/ko-KR/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -블록 편집기 업데이트: -- 텍스트 블록 편집 시 기기 키보드 유지 -- 새로 삽입한 블록으로 화면 자동 스크롤 -- 기기의 뒤로 버튼을 눌러 블록 선택 취소 -- 충돌 없이 동시에 앱과 다양한 미디어 유형 공유 diff --git a/fastlane/metadata/android/ko-KR/changelogs/1405.txt b/fastlane/metadata/android/ko-KR/changelogs/1405.txt new file mode 100644 index 000000000000..fa1b471eda61 --- /dev/null +++ b/fastlane/metadata/android/ko-KR/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- 오프라인으로 작업할 때 알림을 받으세요. +- 인터넷 연결이 끊어지면 이미지 블록 업로드도 일시 중지되었다가 다시 연결되면 재개됩니다. +- 편집기에서 사용자 정의 그레이디언트를 선택하고 색 표시기를 확인하세요. +- 오른쪽에서 왼쪽으로 읽는 독자를 위해 "앞으로" 및 "뒤로" 화살표를 수정했습니다. diff --git a/fastlane/metadata/android/nl-NL/changelogs/1400.txt b/fastlane/metadata/android/nl-NL/changelogs/1400.txt deleted file mode 100644 index 299f76e973a5..000000000000 --- a/fastlane/metadata/android/nl-NL/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -Updates van de blokeditor: -- Toetsenbord van apparaat blijft in beeld wanneer tekstblokken bewerkt worden -- Scherm scrolt automatisch naar nieuw ingevoegde blokken -- Deselecteer blokken door op de terugknop op je apparaat te klikken -- Deel tegelijkertijd verschillende typen media met de app zonder crashen diff --git a/fastlane/metadata/android/nl-NL/changelogs/1405.txt b/fastlane/metadata/android/nl-NL/changelogs/1405.txt new file mode 100644 index 000000000000..931eff17193f --- /dev/null +++ b/fastlane/metadata/android/nl-NL/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- Krijg een melding wanneer je offline werkt. +- Uploads naar het afbeeldingblok pauzeren wanneer je geen verbinding meer hebt met het internet en hervatten wanneer je weer verbinding hebt. +- Selecteer een aangepast kleurverloop in de editor en zie een kleurenindicator. +- De pijlen verder/terug kloppen voor lezers die van rechts naar links lezen. diff --git a/fastlane/metadata/android/ru-RU/changelogs/1400.txt b/fastlane/metadata/android/ru-RU/changelogs/1400.txt deleted file mode 100644 index 1f61f1d63500..000000000000 --- a/fastlane/metadata/android/ru-RU/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -Обновления редактора блоков -- При редактировании текстовых блоков клавиатура устройства не исчезает. -- Экран автоматически прокручивается к новым добавленным блокам. -- Отмена выбора блоков нажатием кнопки «Назад» на устройстве. -- Возможность одновременной публикации медиафайлов различных типов, не приводящей к сбоям в приложении. diff --git a/fastlane/metadata/android/ru-RU/changelogs/1405.txt b/fastlane/metadata/android/ru-RU/changelogs/1405.txt new file mode 100644 index 000000000000..6b63dc27bf79 --- /dev/null +++ b/fastlane/metadata/android/ru-RU/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- Получайте уведомления о том, что связь прервалась. +- Загрузка блока изображений приостанавливается при прерывании связи и возобновляется после восстановления. +- Выберите пользовательский градиент в редакторе и сверяйтесь с индикатором цвета. +- Исправлены стрелки вперёд/назад для языков с письмом справа налево. diff --git a/fastlane/metadata/android/sv-SE/changelogs/1400.txt b/fastlane/metadata/android/sv-SE/changelogs/1400.txt deleted file mode 100644 index cf3f7d646691..000000000000 --- a/fastlane/metadata/android/sv-SE/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -Blockredigeraruppdateringar: -- Enhetstangentbordet förblir kvar vid redigering av textblock -- Skärmen bläddrar automatiskt till nyinfogade block -- Avmarkera block genom att trycka på din enhets tillbakaknapp -- Dela olika mediatyper till appen med en gång utan någon krasch diff --git a/fastlane/metadata/android/sv-SE/changelogs/1405.txt b/fastlane/metadata/android/sv-SE/changelogs/1405.txt new file mode 100644 index 000000000000..495622d8efc5 --- /dev/null +++ b/fastlane/metadata/android/sv-SE/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- Få notiser när du arbetar offline. +- Bildblocksuppladdningar pausas när din internetanslutning försvinner och återupptas när du återansluter. +- Välj en anpassad gradient i redigeraren och en färgindikator. +- Framåt- och bakåtpilarna är korrekta för höger-till-vänster-läsare. diff --git a/fastlane/metadata/android/tr-TR/changelogs/1400.txt b/fastlane/metadata/android/tr-TR/changelogs/1400.txt deleted file mode 100644 index 03f27902fc75..000000000000 --- a/fastlane/metadata/android/tr-TR/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -Blok Düzenleyici güncellemeleri: -- Metin blokları eklerken cihaz klavyesi kalır -- Ekran yeni eklenen bloklara otomatik olarak kaydırır -- Cihazınızın geri düğmesine basarak blokların seçimini kaldırın -- Tek seferde uygulamayla farklı ortam türleri paylaştığınızda uygulama çökmeyecek diff --git a/fastlane/metadata/android/tr-TR/changelogs/1405.txt b/fastlane/metadata/android/tr-TR/changelogs/1405.txt new file mode 100644 index 000000000000..cc0850ec0231 --- /dev/null +++ b/fastlane/metadata/android/tr-TR/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- Çevrimdışı çalışırken bildirim alın. +- İnternet bağlantınız kesildiğinde görsel bloku yüklemeleri durur ve yeniden bağlandığınızda devam eder. +- Düzenleyicide özel bir gradyan seçin ve renk göstergesini görün. +- "İleri" ve "geri" okları, sağdan sola okuyucular için doğrudur. diff --git a/fastlane/metadata/android/zh-CN/changelogs/1400.txt b/fastlane/metadata/android/zh-CN/changelogs/1400.txt deleted file mode 100644 index 8cbf5d93543a..000000000000 --- a/fastlane/metadata/android/zh-CN/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -更新了区块编辑器: -- 编辑文本区块时,设备键盘不会消失 -- 界面会自动滚动至新插入的区块 -- 按下设备的返回按钮即可取消选择区块 -- 将不同类型的媒体同时分享到应用程序中时不会出现崩溃 diff --git a/fastlane/metadata/android/zh-CN/changelogs/1405.txt b/fastlane/metadata/android/zh-CN/changelogs/1405.txt new file mode 100644 index 000000000000..e832f3152585 --- /dev/null +++ b/fastlane/metadata/android/zh-CN/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- 在离线工作时获得通知。 +- 互联网断开时,图像区块将暂停上传,重新连接后即会恢复。 +- 在编辑器中选择自定义渐变,就能看到颜色指示器。 +- “前进”和“后退”箭头已纠正,适用于从右向左的阅读器。 diff --git a/fastlane/metadata/android/zh-TW/changelogs/1400.txt b/fastlane/metadata/android/zh-TW/changelogs/1400.txt deleted file mode 100644 index 6b7ab61e4a9a..000000000000 --- a/fastlane/metadata/android/zh-TW/changelogs/1400.txt +++ /dev/null @@ -1,6 +0,0 @@ -24.0: -* 區塊編輯器更新: -- 當你在編輯文字方塊時,系統仍會顯示裝置鍵盤 -- 畫面會自動捲動至新插入的區塊 -- 按下裝置的「返回」按鈕,即可將區塊取消選取 -- 可將各種不同的媒體類型一次分享至應用程式,無須擔心當機 diff --git a/fastlane/metadata/android/zh-TW/changelogs/1405.txt b/fastlane/metadata/android/zh-TW/changelogs/1405.txt new file mode 100644 index 000000000000..12e271deb010 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/1405.txt @@ -0,0 +1,5 @@ +24.1: +- 可在離線工作時收到通知。 +- 網際網路連線中斷時,系統會暫停上傳圖片區塊,恢復連線時就會繼續上傳。 +- 可在編輯器中選取自訂漸層,並查看顏色標記。 +- 為閱讀由右向左文字的讀者提供正確的「下一步」與「上一步」箭頭。 From 64151d450520d2f13d03d9a0dd3e55441330b6e1 Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Wed, 31 Jan 2024 11:34:09 +0100 Subject: [PATCH 38/53] Revert "Update WordPress metadata translations for 24.1" This reverts commit 8ec6d7eac86c05b3f4abcc2835db6d862adf4275. --- fastlane/metadata/android/ar/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/ar/changelogs/1405.txt | 5 ----- fastlane/metadata/android/de-DE/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/de-DE/changelogs/1405.txt | 5 ----- fastlane/metadata/android/en-US/changelogs/1400.txt | 5 +++++ fastlane/metadata/android/en-US/changelogs/1405.txt | 4 ---- fastlane/metadata/android/es-ES/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/es-ES/changelogs/1405.txt | 5 ----- fastlane/metadata/android/fr-CA/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/fr-CA/changelogs/1405.txt | 5 ----- fastlane/metadata/android/fr-FR/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/fr-FR/changelogs/1405.txt | 5 ----- fastlane/metadata/android/id/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/id/changelogs/1405.txt | 5 ----- fastlane/metadata/android/it-IT/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/it-IT/changelogs/1405.txt | 5 ----- fastlane/metadata/android/iw-IL/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/iw-IL/changelogs/1405.txt | 5 ----- fastlane/metadata/android/ja-JP/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/ja-JP/changelogs/1405.txt | 5 ----- fastlane/metadata/android/ko-KR/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/ko-KR/changelogs/1405.txt | 5 ----- fastlane/metadata/android/nl-NL/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/nl-NL/changelogs/1405.txt | 5 ----- fastlane/metadata/android/ru-RU/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/ru-RU/changelogs/1405.txt | 5 ----- fastlane/metadata/android/sv-SE/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/sv-SE/changelogs/1405.txt | 5 ----- fastlane/metadata/android/tr-TR/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/tr-TR/changelogs/1405.txt | 5 ----- fastlane/metadata/android/zh-CN/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/zh-CN/changelogs/1405.txt | 5 ----- fastlane/metadata/android/zh-TW/changelogs/1400.txt | 6 ++++++ fastlane/metadata/android/zh-TW/changelogs/1405.txt | 5 ----- 34 files changed, 101 insertions(+), 84 deletions(-) create mode 100644 fastlane/metadata/android/ar/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/ar/changelogs/1405.txt create mode 100644 fastlane/metadata/android/de-DE/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/de-DE/changelogs/1405.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/en-US/changelogs/1405.txt create mode 100644 fastlane/metadata/android/es-ES/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/es-ES/changelogs/1405.txt create mode 100644 fastlane/metadata/android/fr-CA/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/fr-CA/changelogs/1405.txt create mode 100644 fastlane/metadata/android/fr-FR/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/fr-FR/changelogs/1405.txt create mode 100644 fastlane/metadata/android/id/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/id/changelogs/1405.txt create mode 100644 fastlane/metadata/android/it-IT/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/it-IT/changelogs/1405.txt create mode 100644 fastlane/metadata/android/iw-IL/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/iw-IL/changelogs/1405.txt create mode 100644 fastlane/metadata/android/ja-JP/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/ja-JP/changelogs/1405.txt create mode 100644 fastlane/metadata/android/ko-KR/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/ko-KR/changelogs/1405.txt create mode 100644 fastlane/metadata/android/nl-NL/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/nl-NL/changelogs/1405.txt create mode 100644 fastlane/metadata/android/ru-RU/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/ru-RU/changelogs/1405.txt create mode 100644 fastlane/metadata/android/sv-SE/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/sv-SE/changelogs/1405.txt create mode 100644 fastlane/metadata/android/tr-TR/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/tr-TR/changelogs/1405.txt create mode 100644 fastlane/metadata/android/zh-CN/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/zh-CN/changelogs/1405.txt create mode 100644 fastlane/metadata/android/zh-TW/changelogs/1400.txt delete mode 100644 fastlane/metadata/android/zh-TW/changelogs/1405.txt diff --git a/fastlane/metadata/android/ar/changelogs/1400.txt b/fastlane/metadata/android/ar/changelogs/1400.txt new file mode 100644 index 000000000000..17b633c518cd --- /dev/null +++ b/fastlane/metadata/android/ar/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +تحديثات محرر المكوّن: +- تظل لوحة مفاتيح الجهاز موجودة عند تحرير مكوّنات النص +- عمليات التمرير التلقائية في الشاشة إلى المكوّنات المدرجة حديثًا +- إلغاء تحديد المكوّنات عن طريق الضغط على زر الرجوع في جهازك +- مشاركة أنواع الوسائط المختلفة على التطبيق مرة واحدة من دون تعطيل diff --git a/fastlane/metadata/android/ar/changelogs/1405.txt b/fastlane/metadata/android/ar/changelogs/1405.txt deleted file mode 100644 index ebfc445a886d..000000000000 --- a/fastlane/metadata/android/ar/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- تلقَّ تنبيهات عندما تعمل من دون اتصال بالإنترنت. -- تتوقف عمليات رفع مكوّنات الصور مؤقتًا عندما تفقد الاتصال بالإنترنت ويتم استئنافها عند إعادة الاتصال. -- حدد تدرجًا مخصصًا في المحرر وشاهد مؤشر اللون. -- يكون سهما "إلى الأمام" و"إلى الخلف" صحيحين للقراء من اليمين إلى اليسار. diff --git a/fastlane/metadata/android/de-DE/changelogs/1400.txt b/fastlane/metadata/android/de-DE/changelogs/1400.txt new file mode 100644 index 000000000000..7a22c1f07bcf --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +Block-Editor-Aktualisierungen: +- Gerätetastatur bleibt beim Bearbeiten von Textblöcken erhalten +- Die Ansicht scrollt automatisch zu neu eingefügten Blöcken +- Hebe die Auswahl von Blöcken auf, indem du den Zurück-Button deines Geräts drückst +- Teile verschiedene Medientypen gleichzeitig in der App, ohne Abstürze diff --git a/fastlane/metadata/android/de-DE/changelogs/1405.txt b/fastlane/metadata/android/de-DE/changelogs/1405.txt deleted file mode 100644 index b15fbce878ef..000000000000 --- a/fastlane/metadata/android/de-DE/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- Du wirst benachrichtigt, wenn du offline arbeitest. -- Uploads auf Bildblöcke werden pausiert, wenn deine Internetverbindung unterbrochen ist, und fortgesetzt, sobald die Verbindung wiederhergestellt ist. -- Du kannst im Editor einen individuellen Verlauf auswählen und erhältst einen Farbhinweis. -- Die Pfeile für vor und zurück sind bei Rechts-nach-Links-Sprachen richtig. diff --git a/fastlane/metadata/android/en-US/changelogs/1400.txt b/fastlane/metadata/android/en-US/changelogs/1400.txt new file mode 100644 index 000000000000..33452ef2e9ee --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/1400.txt @@ -0,0 +1,5 @@ +Block Editor updates: +- Device keyboard remains when editing text blocks +- Screen auto-scrolls to newly inserted blocks +- Unselect blocks by pressing your device’s back button +- Share different media types to the app at once without crashing diff --git a/fastlane/metadata/android/en-US/changelogs/1405.txt b/fastlane/metadata/android/en-US/changelogs/1405.txt deleted file mode 100644 index ab3a2cba51aa..000000000000 --- a/fastlane/metadata/android/en-US/changelogs/1405.txt +++ /dev/null @@ -1,4 +0,0 @@ -- Get notified when you’re working offline. -- Image block uploads pause when you lose internet and resume when you reconnect. -- Select a custom gradient in the editor and see a color indicator. -- “Forward” and “back” arrows are correct for right-to-left readers. diff --git a/fastlane/metadata/android/es-ES/changelogs/1400.txt b/fastlane/metadata/android/es-ES/changelogs/1400.txt new file mode 100644 index 000000000000..9b98113ead1d --- /dev/null +++ b/fastlane/metadata/android/es-ES/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +Actualizaciones del Editor de bloques: +- El teclado del dispositivo se mantiene al editar bloques de texto. +- La pantalla se desplaza automáticamente a los bloques recién insertados. +- Deselecciona los bloques pulsando el botón Atrás de tu dispositivo. +- Comparte diferentes tipos de medios en la aplicación a la vez sin que se bloquee. diff --git a/fastlane/metadata/android/es-ES/changelogs/1405.txt b/fastlane/metadata/android/es-ES/changelogs/1405.txt deleted file mode 100644 index 9531126af905..000000000000 --- a/fastlane/metadata/android/es-ES/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -2.4.1: -- Recibe avisos cuando estés trabajando desconectado. -- Las subidas al bloque de imagen que se pausan cuando pierdes la conexión a Internet y se reanudan cuando vuelves a conectar. -- Selecciona un gradiente personalizado en el editor y verás un indicador de color. -- Las flechas de «adelante» y «atrás» ahora están correctamente para lectores de derecha a izquierda. diff --git a/fastlane/metadata/android/fr-CA/changelogs/1400.txt b/fastlane/metadata/android/fr-CA/changelogs/1400.txt new file mode 100644 index 000000000000..87890bb49277 --- /dev/null +++ b/fastlane/metadata/android/fr-CA/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0 : +Mises à jour de l'éditeur de blocs : +- Le clavier de l’appareil reste visible lors de l’édition de blocs Paragraphe +- L’écran défile automatiquement jusqu’aux blocs qui viennent d’être insérés +- Désélectionner des blocs en appuyant sur le bouton Retour de votre appareil +- Partager simultanément divers types de médias vers l’application sans incident diff --git a/fastlane/metadata/android/fr-CA/changelogs/1405.txt b/fastlane/metadata/android/fr-CA/changelogs/1405.txt deleted file mode 100644 index 0a7d474c1667..000000000000 --- a/fastlane/metadata/android/fr-CA/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1 : -- Recevez une notification lorsque vous travaillez hors ligne. -- Les mises en ligne de blocs Image sont suspendues en cas de perte de votre connexion Internet et reprennent dès reconnexion. -- Sélectionnez un dégradé personnalisé dans l’éditeur, un indicateur de couleur apparaît. -- Les flèches s’affichent dans le bon sens pour les lecteurs de langues RTL. diff --git a/fastlane/metadata/android/fr-FR/changelogs/1400.txt b/fastlane/metadata/android/fr-FR/changelogs/1400.txt new file mode 100644 index 000000000000..87890bb49277 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0 : +Mises à jour de l'éditeur de blocs : +- Le clavier de l’appareil reste visible lors de l’édition de blocs Paragraphe +- L’écran défile automatiquement jusqu’aux blocs qui viennent d’être insérés +- Désélectionner des blocs en appuyant sur le bouton Retour de votre appareil +- Partager simultanément divers types de médias vers l’application sans incident diff --git a/fastlane/metadata/android/fr-FR/changelogs/1405.txt b/fastlane/metadata/android/fr-FR/changelogs/1405.txt deleted file mode 100644 index 0a7d474c1667..000000000000 --- a/fastlane/metadata/android/fr-FR/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1 : -- Recevez une notification lorsque vous travaillez hors ligne. -- Les mises en ligne de blocs Image sont suspendues en cas de perte de votre connexion Internet et reprennent dès reconnexion. -- Sélectionnez un dégradé personnalisé dans l’éditeur, un indicateur de couleur apparaît. -- Les flèches s’affichent dans le bon sens pour les lecteurs de langues RTL. diff --git a/fastlane/metadata/android/id/changelogs/1400.txt b/fastlane/metadata/android/id/changelogs/1400.txt new file mode 100644 index 000000000000..ef674133b1d8 --- /dev/null +++ b/fastlane/metadata/android/id/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +Pembaruan Editor Blok: +- Keyboard perangkat tetap terlihat ketika menyunting blok teks +- Layar bergulir otomatis ke blok yang baru disisipkan +- Batalkan pemilihan blok dengan menekan tombol kembali pada perangkat +- Bagikan berbagai jenis media ke aplikasi sekaligus tanpa crash diff --git a/fastlane/metadata/android/id/changelogs/1405.txt b/fastlane/metadata/android/id/changelogs/1405.txt deleted file mode 100644 index a68b18255349..000000000000 --- a/fastlane/metadata/android/id/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- Dapatkan pemberitahuan ketika Anda sedang offline. -- Pengunggahan ke blok gambar dijeda saat internet terputus dan dilanjutkan saat internet tersambung kembali. -- Pilih gradien kustom di editor dan lihat indikator warna. -- Panah “maju” dan “mundur” sudah sesuai untuk pembaca tulisan dari kanan ke kiri. diff --git a/fastlane/metadata/android/it-IT/changelogs/1400.txt b/fastlane/metadata/android/it-IT/changelogs/1400.txt new file mode 100644 index 000000000000..5f7eb1bf587e --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +Aggiornamenti all'editor dei blocchi: +- La tastiera del dispositivo rimane attiva durante la modifica dei blocchi di testo +- La schermata scorre automaticamente sui blocchi appena inseriti +- Deseleziona i blocchi premendo il tasto indietro del tuo dispositivo +- Condividi diversi tipi di media nell'app in una volta sola senza che si verifichino arresti anomali diff --git a/fastlane/metadata/android/it-IT/changelogs/1405.txt b/fastlane/metadata/android/it-IT/changelogs/1405.txt deleted file mode 100644 index aa03b6d9095f..000000000000 --- a/fastlane/metadata/android/it-IT/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- Ricevi notifiche mentre lavori offline. -- I caricamenti del blocco immagine vengono messi in pausa quando perdi la connessione internet e ripresi quando ti riconnetti. -- Seleziona un gradiente personalizzato nell'editor e vedi un indicatore di colore. -- Sono state sistemate le frecce avanti/indietro per chi legge da destra verso sinistra. diff --git a/fastlane/metadata/android/iw-IL/changelogs/1400.txt b/fastlane/metadata/android/iw-IL/changelogs/1400.txt new file mode 100644 index 000000000000..f1804b5d0bbc --- /dev/null +++ b/fastlane/metadata/android/iw-IL/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +עדכונים בעורך הבלוקים: +- המקלדת של המכשיר נשארת במקומה במהלך עריכת בלוקים של טקסט +- המסך גולל באופן אוטומטי לבלוקים החדשים שנוספו +- לבטל את הבחירה בבלוקים על ידי לחיצה על כפתור החזרה במכשיר +- לשתף במקביל סוגי מדיה שונים באפליקציה, ללא קריסות diff --git a/fastlane/metadata/android/iw-IL/changelogs/1405.txt b/fastlane/metadata/android/iw-IL/changelogs/1405.txt deleted file mode 100644 index aff27d0f1f43..000000000000 --- a/fastlane/metadata/android/iw-IL/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- לקבל הודעה כאשר העבודה מתבצעת באופן לא מקוון. -- העלאות של הבלוק 'תמונה' מושהות אם החיבור לאינטרנט אובד וממשיכות שוב לאחר ההתחברות מחדש. -- ניתן לבחור מעבר צבע מותאם אישית בעורך ולראות סמן צבע. -- החצים 'קדימה' ו'חזרה' מוצגים בצורה נכונה לקוראי שפות עם כיווניות מימין לשמאל. diff --git a/fastlane/metadata/android/ja-JP/changelogs/1400.txt b/fastlane/metadata/android/ja-JP/changelogs/1400.txt new file mode 100644 index 000000000000..4e41d3e19d03 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +ブロックエディターの更新: +- テキストブロックの編集時にデバイスのキーボードがそのままになります +- 新しく挿入されたブロックまで画面が自動スクロールされます +- 端末の戻るボタンを押すとブロックの選択が解除されます +- クラッシュすることなくさまざまな種類のメディアをアプリに一度に共有できます diff --git a/fastlane/metadata/android/ja-JP/changelogs/1405.txt b/fastlane/metadata/android/ja-JP/changelogs/1405.txt deleted file mode 100644 index c522eb94b342..000000000000 --- a/fastlane/metadata/android/ja-JP/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- オフラインで作業しているときに通知を受け取ります。 -- 画像ブロックのアップロードは、インターネットが切断されると一時停止され、再度接続すると再開します。 -- エディターでカスタムグラデーションを選択すると、カラーインジケーターが表示されます。 -- 右から左方向に読むリーダーの「左」と「右」向きの矢印が修正されています。 diff --git a/fastlane/metadata/android/ko-KR/changelogs/1400.txt b/fastlane/metadata/android/ko-KR/changelogs/1400.txt new file mode 100644 index 000000000000..fa1618094eee --- /dev/null +++ b/fastlane/metadata/android/ko-KR/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +블록 편집기 업데이트: +- 텍스트 블록 편집 시 기기 키보드 유지 +- 새로 삽입한 블록으로 화면 자동 스크롤 +- 기기의 뒤로 버튼을 눌러 블록 선택 취소 +- 충돌 없이 동시에 앱과 다양한 미디어 유형 공유 diff --git a/fastlane/metadata/android/ko-KR/changelogs/1405.txt b/fastlane/metadata/android/ko-KR/changelogs/1405.txt deleted file mode 100644 index fa1b471eda61..000000000000 --- a/fastlane/metadata/android/ko-KR/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- 오프라인으로 작업할 때 알림을 받으세요. -- 인터넷 연결이 끊어지면 이미지 블록 업로드도 일시 중지되었다가 다시 연결되면 재개됩니다. -- 편집기에서 사용자 정의 그레이디언트를 선택하고 색 표시기를 확인하세요. -- 오른쪽에서 왼쪽으로 읽는 독자를 위해 "앞으로" 및 "뒤로" 화살표를 수정했습니다. diff --git a/fastlane/metadata/android/nl-NL/changelogs/1400.txt b/fastlane/metadata/android/nl-NL/changelogs/1400.txt new file mode 100644 index 000000000000..299f76e973a5 --- /dev/null +++ b/fastlane/metadata/android/nl-NL/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +Updates van de blokeditor: +- Toetsenbord van apparaat blijft in beeld wanneer tekstblokken bewerkt worden +- Scherm scrolt automatisch naar nieuw ingevoegde blokken +- Deselecteer blokken door op de terugknop op je apparaat te klikken +- Deel tegelijkertijd verschillende typen media met de app zonder crashen diff --git a/fastlane/metadata/android/nl-NL/changelogs/1405.txt b/fastlane/metadata/android/nl-NL/changelogs/1405.txt deleted file mode 100644 index 931eff17193f..000000000000 --- a/fastlane/metadata/android/nl-NL/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- Krijg een melding wanneer je offline werkt. -- Uploads naar het afbeeldingblok pauzeren wanneer je geen verbinding meer hebt met het internet en hervatten wanneer je weer verbinding hebt. -- Selecteer een aangepast kleurverloop in de editor en zie een kleurenindicator. -- De pijlen verder/terug kloppen voor lezers die van rechts naar links lezen. diff --git a/fastlane/metadata/android/ru-RU/changelogs/1400.txt b/fastlane/metadata/android/ru-RU/changelogs/1400.txt new file mode 100644 index 000000000000..1f61f1d63500 --- /dev/null +++ b/fastlane/metadata/android/ru-RU/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +Обновления редактора блоков +- При редактировании текстовых блоков клавиатура устройства не исчезает. +- Экран автоматически прокручивается к новым добавленным блокам. +- Отмена выбора блоков нажатием кнопки «Назад» на устройстве. +- Возможность одновременной публикации медиафайлов различных типов, не приводящей к сбоям в приложении. diff --git a/fastlane/metadata/android/ru-RU/changelogs/1405.txt b/fastlane/metadata/android/ru-RU/changelogs/1405.txt deleted file mode 100644 index 6b63dc27bf79..000000000000 --- a/fastlane/metadata/android/ru-RU/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- Получайте уведомления о том, что связь прервалась. -- Загрузка блока изображений приостанавливается при прерывании связи и возобновляется после восстановления. -- Выберите пользовательский градиент в редакторе и сверяйтесь с индикатором цвета. -- Исправлены стрелки вперёд/назад для языков с письмом справа налево. diff --git a/fastlane/metadata/android/sv-SE/changelogs/1400.txt b/fastlane/metadata/android/sv-SE/changelogs/1400.txt new file mode 100644 index 000000000000..cf3f7d646691 --- /dev/null +++ b/fastlane/metadata/android/sv-SE/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +Blockredigeraruppdateringar: +- Enhetstangentbordet förblir kvar vid redigering av textblock +- Skärmen bläddrar automatiskt till nyinfogade block +- Avmarkera block genom att trycka på din enhets tillbakaknapp +- Dela olika mediatyper till appen med en gång utan någon krasch diff --git a/fastlane/metadata/android/sv-SE/changelogs/1405.txt b/fastlane/metadata/android/sv-SE/changelogs/1405.txt deleted file mode 100644 index 495622d8efc5..000000000000 --- a/fastlane/metadata/android/sv-SE/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- Få notiser när du arbetar offline. -- Bildblocksuppladdningar pausas när din internetanslutning försvinner och återupptas när du återansluter. -- Välj en anpassad gradient i redigeraren och en färgindikator. -- Framåt- och bakåtpilarna är korrekta för höger-till-vänster-läsare. diff --git a/fastlane/metadata/android/tr-TR/changelogs/1400.txt b/fastlane/metadata/android/tr-TR/changelogs/1400.txt new file mode 100644 index 000000000000..03f27902fc75 --- /dev/null +++ b/fastlane/metadata/android/tr-TR/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +Blok Düzenleyici güncellemeleri: +- Metin blokları eklerken cihaz klavyesi kalır +- Ekran yeni eklenen bloklara otomatik olarak kaydırır +- Cihazınızın geri düğmesine basarak blokların seçimini kaldırın +- Tek seferde uygulamayla farklı ortam türleri paylaştığınızda uygulama çökmeyecek diff --git a/fastlane/metadata/android/tr-TR/changelogs/1405.txt b/fastlane/metadata/android/tr-TR/changelogs/1405.txt deleted file mode 100644 index cc0850ec0231..000000000000 --- a/fastlane/metadata/android/tr-TR/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- Çevrimdışı çalışırken bildirim alın. -- İnternet bağlantınız kesildiğinde görsel bloku yüklemeleri durur ve yeniden bağlandığınızda devam eder. -- Düzenleyicide özel bir gradyan seçin ve renk göstergesini görün. -- "İleri" ve "geri" okları, sağdan sola okuyucular için doğrudur. diff --git a/fastlane/metadata/android/zh-CN/changelogs/1400.txt b/fastlane/metadata/android/zh-CN/changelogs/1400.txt new file mode 100644 index 000000000000..8cbf5d93543a --- /dev/null +++ b/fastlane/metadata/android/zh-CN/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +更新了区块编辑器: +- 编辑文本区块时,设备键盘不会消失 +- 界面会自动滚动至新插入的区块 +- 按下设备的返回按钮即可取消选择区块 +- 将不同类型的媒体同时分享到应用程序中时不会出现崩溃 diff --git a/fastlane/metadata/android/zh-CN/changelogs/1405.txt b/fastlane/metadata/android/zh-CN/changelogs/1405.txt deleted file mode 100644 index e832f3152585..000000000000 --- a/fastlane/metadata/android/zh-CN/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- 在离线工作时获得通知。 -- 互联网断开时,图像区块将暂停上传,重新连接后即会恢复。 -- 在编辑器中选择自定义渐变,就能看到颜色指示器。 -- “前进”和“后退”箭头已纠正,适用于从右向左的阅读器。 diff --git a/fastlane/metadata/android/zh-TW/changelogs/1400.txt b/fastlane/metadata/android/zh-TW/changelogs/1400.txt new file mode 100644 index 000000000000..6b7ab61e4a9a --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/1400.txt @@ -0,0 +1,6 @@ +24.0: +* 區塊編輯器更新: +- 當你在編輯文字方塊時,系統仍會顯示裝置鍵盤 +- 畫面會自動捲動至新插入的區塊 +- 按下裝置的「返回」按鈕,即可將區塊取消選取 +- 可將各種不同的媒體類型一次分享至應用程式,無須擔心當機 diff --git a/fastlane/metadata/android/zh-TW/changelogs/1405.txt b/fastlane/metadata/android/zh-TW/changelogs/1405.txt deleted file mode 100644 index 12e271deb010..000000000000 --- a/fastlane/metadata/android/zh-TW/changelogs/1405.txt +++ /dev/null @@ -1,5 +0,0 @@ -24.1: -- 可在離線工作時收到通知。 -- 網際網路連線中斷時,系統會暫停上傳圖片區塊,恢復連線時就會繼續上傳。 -- 可在編輯器中選取自訂漸層,並查看顏色標記。 -- 為閱讀由右向左文字的讀者提供正確的「下一步」與「上一步」箭頭。 From f6633cf9d849a39afd0328dadcb88138504cae3b Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 16:20:42 +0530 Subject: [PATCH 39/53] =?UTF-8?q?=E2=86=91=20Updates:=20the=20state=20retu?= =?UTF-8?q?rned=20from=20mutable=20to=20immutable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../android/ui/sitemonitor/SiteMonitorParentViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt index 2e0e9ad03813..98a6add7e83b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt @@ -1,6 +1,6 @@ package org.wordpress.android.ui.sitemonitor -import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher From cfb913251bf44b8d93720d977e6105f08f544064 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 16:21:06 +0530 Subject: [PATCH 40/53] * Fixes: data not loaded in orientation change --- .../ui/sitemonitor/SiteMonitorParentActivity.kt | 1 + .../ui/sitemonitor/SiteMonitorParentViewModel.kt | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index 7a36e9a19334..3538f3ac27f5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -102,6 +102,7 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. ) ?: savedStateSparseArray currentSelectItemId = savedInstanceState.getInt(SAVED_STATE_CURRENT_TAB_KEY) + siteMonitorParentViewModel.loadData() } else { siteMonitorParentViewModel.start(getSite()) currentSelectItemId = getInitialTab() diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt index 98a6add7e83b..22fa8eb98614 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt @@ -31,19 +31,25 @@ class SiteMonitorParentViewModel @Inject constructor( fun start(site: SiteModel) { this.site = site trackActivityLaunched() + loadData() + } + + fun loadData() { metricsViewModel.start(SiteMonitorType.METRICS, SiteMonitorTabItem.Metrics.urlTemplate, site) phpLogViewModel.start(SiteMonitorType.PHP_LOGS, SiteMonitorTabItem.PHPLogs.urlTemplate, site) webServerViewModel.start(SiteMonitorType.WEB_SERVER_LOGS, SiteMonitorTabItem.WebServerLogs.urlTemplate, site) } - fun getUiState(siteMonitorType: SiteMonitorType): MutableState { + fun getUiState(siteMonitorType: SiteMonitorType): State { return when (siteMonitorType) { SiteMonitorType.METRICS -> { metricsViewModel.uiState } + SiteMonitorType.PHP_LOGS -> { phpLogViewModel.uiState } + SiteMonitorType.WEB_SERVER_LOGS -> { webServerViewModel.uiState } @@ -55,9 +61,11 @@ class SiteMonitorParentViewModel @Inject constructor( SiteMonitorType.METRICS -> { metricsViewModel.onUrlLoaded() } + SiteMonitorType.PHP_LOGS -> { phpLogViewModel.onUrlLoaded() } + SiteMonitorType.WEB_SERVER_LOGS -> { webServerViewModel.onUrlLoaded() } @@ -69,9 +77,11 @@ class SiteMonitorParentViewModel @Inject constructor( SiteMonitorType.METRICS -> { metricsViewModel.onWebViewError() } + SiteMonitorType.PHP_LOGS -> { phpLogViewModel.onWebViewError() } + SiteMonitorType.WEB_SERVER_LOGS -> { webServerViewModel.onWebViewError() } From 8aa801bd0633a3cb1633d72ebdad6135601aa611 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Wed, 31 Jan 2024 08:01:06 -0500 Subject: [PATCH 41/53] Refactor: wrap the content in it's own column to prevent tab jumping --- .../ui/sitemonitor/SiteMonitorParentActivity.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index 3538f3ac27f5..fe446346c8eb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.Button import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold @@ -214,12 +215,15 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. val uiState by remember(key1 = tabType) { siteMonitorParentViewModel.getUiState(tabType) } - when (uiState) { - is SiteMonitorUiState.Preparing -> LoadingState(modifier) - is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> - SiteMonitorWebView(uiState, tabType, modifier) - - is SiteMonitorUiState.Error -> SiteMonitorError(uiState as SiteMonitorUiState.Error, modifier) + LazyColumn { + item { + when (uiState) { + is SiteMonitorUiState.Preparing -> LoadingState(modifier) + is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> + SiteMonitorWebView(uiState, tabType, modifier) + is SiteMonitorUiState.Error -> SiteMonitorError(uiState as SiteMonitorUiState.Error, modifier) + } + } } } @Composable From c53f6ff5ef33963c13812c835124a456a2985863 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Wed, 31 Jan 2024 08:41:57 -0500 Subject: [PATCH 42/53] Add unit tests for Site Monitor mapper and utils --- .../ui/sitemonitor/SiteMonitorMapperTest.kt | 58 ++++++++++++ .../ui/sitemonitor/SiteMonitorUtilsTest.kt | 92 +++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapperTest.kt create mode 100644 WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUtilsTest.kt diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapperTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapperTest.kt new file mode 100644 index 000000000000..d9b349bc2873 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapperTest.kt @@ -0,0 +1,58 @@ +package org.wordpress.android.ui.sitemonitor + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.whenever +import org.wordpress.android.BaseUnitTest + +@ExperimentalCoroutinesApi +@RunWith(MockitoJUnitRunner::class) +class SiteMonitorMapperTest : BaseUnitTest() { + @Mock + lateinit var siteMonitorUtils: SiteMonitorUtils + + private lateinit var siteMonitorMapper: SiteMonitorMapper + + @Before + fun setup() { + siteMonitorMapper = SiteMonitorMapper(siteMonitorUtils) + } + + @Test + fun `given prepared request, when mapper is called, then site monitor model is created`() { + whenever(siteMonitorUtils.getUserAgent()).thenReturn(USER_AGENT) + + val state = siteMonitorMapper.toPrepared(URL, ADDRESS_TO_LOAD, SiteMonitorType.METRICS) + + assertThat(state.model.siteMonitorType).isEqualTo(SiteMonitorType.METRICS) + assertThat(state.model.url).isEqualTo(URL) + assertThat(state.model.addressToLoad).isEqualTo(ADDRESS_TO_LOAD) + assertThat(state.model.userAgent).isEqualTo(USER_AGENT) + } + + @Test + fun `given network error, when mapper is called, then NoNetwork error is created`() { + val state = siteMonitorMapper.toNoNetworkError(mock()) + + assertThat(state).isInstanceOf(SiteMonitorUiState.NoNetworkError::class.java) + } + + @Test + fun `given generic error error, when mapper is called, then Generic error is created`() { + val state = siteMonitorMapper.toGenericError(mock()) + + assertThat(state).isInstanceOf(SiteMonitorUiState.GenericError::class.java) + } + + companion object { + const val USER_AGENT = "user_agent" + const val URL = "url" + const val ADDRESS_TO_LOAD = "address_to_load" + } +} diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUtilsTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUtilsTest.kt new file mode 100644 index 000000000000..0bf5076d32d5 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUtilsTest.kt @@ -0,0 +1,92 @@ +package org.wordpress.android.ui.sitemonitor + +import junit.framework.TestCase.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.verify +import org.wordpress.android.analytics.AnalyticsTracker +import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper + +@RunWith(MockitoJUnitRunner::class) +class SiteMonitorUtilsTest { + @Mock + lateinit var analyticsTrackerWrapper: AnalyticsTrackerWrapper + + private lateinit var siteMonitorUtils: SiteMonitorUtils + + @Before + fun setup() { + siteMonitorUtils = SiteMonitorUtils(analyticsTrackerWrapper) + } + + @Test + fun `when activity is launched, then event is tracked`() { + siteMonitorUtils.trackActivityLaunched() + + verify(analyticsTrackerWrapper).track(AnalyticsTracker.Stat.SITE_MONITORING_SCREEN_SHOWN) + } + + @Test + fun `given url matches pattern, when sanitize is requested, then url is sanitized`() { + val result = siteMonitorUtils.sanitizeSiteUrl("http://example.com") + + assertEquals("example.com", result) + } + + @Test + fun `given url is null, when sanitize is requested, then url is empty`() { + val result = siteMonitorUtils.sanitizeSiteUrl(null) + + assertEquals("", result) + } + + @Test + fun `given url does not match pattern, when sanitize is requested, then url is not sanitized`() { + val url = "gibberish" + val result = siteMonitorUtils.sanitizeSiteUrl(url) + + assertEquals(url, result) + } + + @Test + fun `when metrics tab is launched, then event is tracked`() { + siteMonitorUtils.trackTabLoaded(SiteMonitorType.METRICS) + + // Verify that the correct method was called on the analyticsTrackerWrapper + verify(analyticsTrackerWrapper).track( + AnalyticsTracker.Stat.SITE_MONITORING_TAB_SHOWN, + mapOf( + SiteMonitorUtils.TAB_TRACK_KEY to SiteMonitorType.METRICS.analyticsDescription + ) + ) + } + + @Test + fun `when php logs tab is launched, then event is tracked`() { + siteMonitorUtils.trackTabLoaded(SiteMonitorType.PHP_LOGS) + + // Verify that the correct method was called on the analyticsTrackerWrapper + verify(analyticsTrackerWrapper).track( + AnalyticsTracker.Stat.SITE_MONITORING_TAB_SHOWN, + mapOf( + SiteMonitorUtils.TAB_TRACK_KEY to SiteMonitorType.PHP_LOGS.analyticsDescription + ) + ) + } + + @Test + fun `when web server logs tab is launched, then event is tracked`() { + siteMonitorUtils.trackTabLoaded(SiteMonitorType.WEB_SERVER_LOGS) + + // Verify that the correct method was called on the analyticsTrackerWrapper + verify(analyticsTrackerWrapper).track( + AnalyticsTracker.Stat.SITE_MONITORING_TAB_SHOWN, + mapOf( + SiteMonitorUtils.TAB_TRACK_KEY to SiteMonitorType.WEB_SERVER_LOGS.analyticsDescription + ) + ) + } +} From 6a7a13d5c795f89862419e15ed903ddbdf822eef Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Wed, 31 Jan 2024 15:53:37 +0200 Subject: [PATCH 43/53] Add tracking for initial site monitor tab --- .../android/ui/sitemonitor/SiteMonitorParentActivity.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index fe446346c8eb..9f1d0bd3caef 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -28,6 +28,7 @@ import androidx.compose.material3.Tab import androidx.compose.material3.TabRowDefaults import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset 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 @@ -169,6 +170,10 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. val tabs = SiteMonitorTabItem.entries + LaunchedEffect(true) { + siteMonitorUtils.trackTabLoaded(tabs[initialTab].siteMonitorType) + } + Column(modifier = modifier.fillMaxWidth()) { androidx.compose.material3.TabRow( selectedTabIndex = tabIndex, From b697e790b10ae789175c7ae20c4b459040772478 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Wed, 31 Jan 2024 16:36:45 +0200 Subject: [PATCH 44/53] Add tracking for site monitor webview error --- .../android/ui/sitemonitor/SiteMonitorParentActivity.kt | 5 ++++- .../wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt | 8 ++++++++ .../org/wordpress/android/analytics/AnalyticsTracker.java | 1 + .../android/analytics/AnalyticsTrackerNosara.java | 2 ++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index 9f1d0bd3caef..57da7e93e2e2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -319,6 +319,9 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. override fun onWebViewPageLoaded(url: String, tabType: SiteMonitorType) = siteMonitorParentViewModel.onUrlLoaded(tabType) - override fun onWebViewReceivedError(url: String, tabType: SiteMonitorType) = + override fun onWebViewReceivedError(url: String, tabType: SiteMonitorType) { siteMonitorParentViewModel.onWebViewError(tabType) + siteMonitorUtils.trackTabLoadingError(tabType) + } + } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt index a4b25ed2a1c7..a64e92029030 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt @@ -33,6 +33,14 @@ class SiteMonitorUtils @Inject constructor( )) } + fun trackTabLoadingError(siteMonitorType: SiteMonitorType) { + analyticsTrackerWrapper.track( + AnalyticsTracker.Stat.SITE_MONITORING_TAB_LOADING_ERROR, + mapOf( + TAB_TRACK_KEY to siteMonitorType.analyticsDescription + )) + } + companion object { const val HTTP_PATTERN = "(https?://)" const val PHP_LOGS_PATTERN = "/php" diff --git a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java index 4ecc68844c66..9c93b7293a73 100644 --- a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java +++ b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java @@ -1104,6 +1104,7 @@ public enum Stat { SITE_MONITORING_SCREEN_SHOWN, OPENED_SITE_MONITORING, SITE_MONITORING_TAB_SHOWN, + SITE_MONITORING_TAB_LOADING_ERROR } private static final List TRACKERS = new ArrayList<>(); diff --git a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java index 6bc51ec5bdbf..5e5fa351b389 100644 --- a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java +++ b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java @@ -2701,6 +2701,8 @@ public static String getEventNameForStat(AnalyticsTracker.Stat stat) { return "opened_site_monitoring"; case SITE_MONITORING_TAB_SHOWN: return "site_monitoring_tab_shown"; + case SITE_MONITORING_TAB_LOADING_ERROR: + return "site_monitoring_tab_loading_error"; } return null; } From 5479d36c14fdd62380ec9891bb98d17fae5dc75a Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Wed, 31 Jan 2024 16:45:21 +0200 Subject: [PATCH 45/53] Add capitalisation for tab names --- .../ui/mysite/personalization/PersonalizationActivity.kt | 2 +- .../android/ui/sitemonitor/SiteMonitorParentActivity.kt | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/personalization/PersonalizationActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/personalization/PersonalizationActivity.kt index 94e60930694d..ac9ab5de738d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/personalization/PersonalizationActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/personalization/PersonalizationActivity.kt @@ -107,7 +107,7 @@ class PersonalizationActivity : AppCompatActivity() { contentColor = MaterialTheme.colors.onSurface, ) { tabs.forEachIndexed { index, title -> - Tab(text = { Text(stringResource(id = title)) }, + Tab(text = { Text(stringResource(id = title).uppercase()) }, selected = tabIndex == index, onClick = { tabIndex = index } ) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index 57da7e93e2e2..9fba7836ae95 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -25,6 +25,7 @@ import androidx.compose.material.Text import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Surface import androidx.compose.material3.Tab +import androidx.compose.material3.TabRow import androidx.compose.material3.TabRowDefaults import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset import androidx.compose.runtime.Composable @@ -175,7 +176,7 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. } Column(modifier = modifier.fillMaxWidth()) { - androidx.compose.material3.TabRow( + TabRow( selectedTabIndex = tabIndex, containerColor = MaterialTheme.colors.surface, contentColor = MaterialTheme.colors.onSurface, @@ -192,8 +193,8 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. Tab( text = { Column(horizontalAlignment = Alignment.CenterHorizontally) { - androidx.compose.material3.Text( - text = stringResource(item.title), + Text( + text = stringResource(item.title).uppercase(), maxLines = 1, overflow = TextOverflow.Ellipsis ) From 29fa1f5bc9fcf61ad5ac979609d4137be8a46798 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Wed, 31 Jan 2024 09:39:08 -0500 Subject: [PATCH 46/53] Add unit tests for Site Monitor web view client --- .../SiteMonitorWebViewClientTest.kt | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClientTest.kt diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClientTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClientTest.kt new file mode 100644 index 000000000000..c4f98154d6c4 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClientTest.kt @@ -0,0 +1,68 @@ +package org.wordpress.android.ui.sitemonitor + +import android.net.Uri +import android.webkit.WebResourceRequest +import android.webkit.WebView +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.any +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.wordpress.android.BaseUnitTest +import android.webkit.WebResourceError +import org.mockito.Mockito.* + +@ExperimentalCoroutinesApi +class SiteMonitorWebViewClientTest : BaseUnitTest() { + @Mock + private lateinit var mockListener: SiteMonitorWebViewClient.SiteMonitorWebViewClientListener + + @Mock + private lateinit var uri: Uri + + private lateinit var webViewClient: SiteMonitorWebViewClient + + @Before + fun setup() { + MockitoAnnotations.openMocks(this) + webViewClient = SiteMonitorWebViewClient(mockListener, SiteMonitorType.METRICS) + } + + @Test + fun `when onPageFinished, then should invoke on webview page loaded`() { + webViewClient.onPageFinished(mock(WebView::class.java), "https://example.com") + + verify(mockListener).onWebViewPageLoaded("https://example.com", SiteMonitorType.METRICS) + } + + @Test + fun `when onReceivedError, then should invoke on web view error received`() { + val mockRequest = mock(WebResourceRequest::class.java) + whenever(mockRequest.isForMainFrame).thenReturn(true) + val url = "https://some.domain" + whenever(uri.toString()).thenReturn(url) + whenever(mockRequest.url).thenReturn(uri) + + webViewClient.onPageStarted(mock(WebView::class.java), url, null) + webViewClient.onReceivedError( + mock(WebView::class.java), + mockRequest, + mock(WebResourceError::class.java) + ) + + verify(mockListener).onWebViewReceivedError(url, SiteMonitorType.METRICS) + } + + @Test + fun `when onPageFinished, then should not invoke OnReceivedError`() { + val url = "https://some.domain" + + webViewClient.onPageFinished(mock(WebView::class.java), url) + + verify(mockListener, never()).onWebViewReceivedError(anyString(), any()) + } +} + From fb3c6b9815cda5d18f97a1a9227042a936dc91c4 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Wed, 31 Jan 2024 20:32:49 +0530 Subject: [PATCH 47/53] * Updates: the _uiState to use immutable state variable --- .../android/ui/sitemonitor/SiteMonitorTabViewModelSlice.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSlice.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSlice.kt index fab664186e62..45ec9a56d76f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSlice.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSlice.kt @@ -1,6 +1,7 @@ package org.wordpress.android.ui.sitemonitor import android.text.TextUtils +import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.cancel @@ -25,7 +26,7 @@ class SiteMonitorTabViewModelSlice @Inject constructor( private lateinit var urlTemplate: String private val _uiState = mutableStateOf(SiteMonitorUiState.Preparing) - val uiState = _uiState + val uiState: State = _uiState fun initialize(scope: CoroutineScope) { this.scope = scope From 6f0c48efb8226e3caac83eb5a426b8263b194a80 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Wed, 31 Jan 2024 11:00:32 -0500 Subject: [PATCH 48/53] Refactor: replace direct access to analytics tracker with siteMonitorUtils --- .../ui/sitemonitor/SiteMonitorParentViewModel.kt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt index 22fa8eb98614..2a18f07e1fb2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt @@ -4,10 +4,8 @@ import androidx.compose.runtime.State import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher -import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.modules.BG_THREAD -import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper import org.wordpress.android.viewmodel.ScopedViewModel import javax.inject.Inject import javax.inject.Named @@ -15,7 +13,7 @@ import javax.inject.Named @HiltViewModel class SiteMonitorParentViewModel @Inject constructor( @param:Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, - private val analyticsTrackerWrapper: AnalyticsTrackerWrapper, + private val siteMonitorUtils: SiteMonitorUtils, private val metricsViewModel: SiteMonitorTabViewModelSlice, private val phpLogViewModel: SiteMonitorTabViewModelSlice, private val webServerViewModel: SiteMonitorTabViewModelSlice @@ -30,7 +28,7 @@ class SiteMonitorParentViewModel @Inject constructor( fun start(site: SiteModel) { this.site = site - trackActivityLaunched() + siteMonitorUtils.trackActivityLaunched() loadData() } @@ -88,10 +86,6 @@ class SiteMonitorParentViewModel @Inject constructor( } } - private fun trackActivityLaunched() { - analyticsTrackerWrapper.track(AnalyticsTracker.Stat.SITE_MONITORING_SCREEN_SHOWN) - } - override fun onCleared() { super.onCleared() metricsViewModel.onCleared() From 1cf5193b0ec6d96b384237d4e6a786152d7fb5c5 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Wed, 31 Jan 2024 11:00:54 -0500 Subject: [PATCH 49/53] Add unit tests for SiteMonitorParentViewModel --- .../SiteMonitorParentViewModelTest.kt | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModelTest.kt diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModelTest.kt new file mode 100644 index 000000000000..411f72a9a442 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModelTest.kt @@ -0,0 +1,170 @@ +package org.wordpress.android.ui.sitemonitor + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.kotlin.any +import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.wordpress.android.BaseUnitTest +import org.wordpress.android.fluxc.model.SiteModel + +@ExperimentalCoroutinesApi +@RunWith(MockitoJUnitRunner::class) +class SiteMonitorParentViewModelTest: BaseUnitTest(){ + @Mock + private lateinit var siteMonitorUtils: SiteMonitorUtils + @Mock + private lateinit var metricsViewModel: SiteMonitorTabViewModelSlice + @Mock + private lateinit var phpLogViewModel: SiteMonitorTabViewModelSlice + @Mock + private lateinit var webServerViewModel: SiteMonitorTabViewModelSlice + + private lateinit var viewModel: SiteMonitorParentViewModel + + @Before + fun setUp() { + viewModel = SiteMonitorParentViewModel( + testDispatcher(), + siteMonitorUtils, + metricsViewModel, + phpLogViewModel, + webServerViewModel + ) + } + + @Test + fun `when viewmodel is started, then track screen shown`() { + val site = mock() + viewModel.start(site) + + verify(siteMonitorUtils).trackActivityLaunched() + } + + @Test + fun `when viewmodel is created, then view model slices are initialized`() { + verify(metricsViewModel).initialize(any()) + verify(phpLogViewModel).initialize(any()) + verify(webServerViewModel).initialize(any()) + } + + @Test + fun `when start is invoked, then view models are started with the correct tab item`() { + val site = mock() + viewModel.start(site) + + verify(metricsViewModel).start(SiteMonitorType.METRICS, SiteMonitorTabItem.Metrics.urlTemplate, site) + verify(phpLogViewModel).start(SiteMonitorType.PHP_LOGS, SiteMonitorTabItem.PHPLogs.urlTemplate, site) + verify(webServerViewModel).start( + SiteMonitorType.WEB_SERVER_LOGS, + SiteMonitorTabItem.WebServerLogs.urlTemplate, + site + ) + } + + @Test + fun `when loadData is invoked, then view models are started with the correct tab item`() { + val site = mock() + viewModel.start(site) + + clearInvocations(metricsViewModel, phpLogViewModel, webServerViewModel) + + viewModel.loadData() + + verify(metricsViewModel).start(SiteMonitorType.METRICS, SiteMonitorTabItem.Metrics.urlTemplate, site) + verify(phpLogViewModel).start(SiteMonitorType.PHP_LOGS, SiteMonitorTabItem.PHPLogs.urlTemplate, site) + verify(webServerViewModel).start( + SiteMonitorType.WEB_SERVER_LOGS, + SiteMonitorTabItem.WebServerLogs.urlTemplate, + site + ) + } + + @Test + fun `given metrics, when getUiState is invoked, then ui state is returned`() { + whenever(metricsViewModel.uiState).thenReturn(mock()) + val site = mock() + viewModel.start(site) + + advanceUntilIdle() + + val state = viewModel.getUiState(SiteMonitorType.METRICS) + + assertThat(state).isNotNull + } + + @Test + fun `given phplogs, when getUiState is invoked, then ui state is returned`() { + whenever(phpLogViewModel.uiState).thenReturn(mock()) + val site = mock() + viewModel.start(site) + + advanceUntilIdle() + + val state = viewModel.getUiState(SiteMonitorType.PHP_LOGS) + + assertThat(state).isNotNull + } + + @Test + fun `given webserver logs, when getUiState is invoked, then ui state is returned`() { + whenever(webServerViewModel.uiState).thenReturn(mock()) + val site = mock() + viewModel.start(site) + + advanceUntilIdle() + + val state = viewModel.getUiState(SiteMonitorType.WEB_SERVER_LOGS) + + assertThat(state).isNotNull + } + + @Test + fun `given metrics, when onUrlLoaded is invoked, then metric vm slice onUrlLoaded is invoked`() { + viewModel.onUrlLoaded(SiteMonitorType.METRICS) + + verify(metricsViewModel).onUrlLoaded() + } + + @Test + fun `given php logs, when onUrlLoaded is invoked, then php logs vm slice onUrlLoaded is invoked`() { + viewModel.onUrlLoaded(SiteMonitorType.PHP_LOGS) + + verify(phpLogViewModel).onUrlLoaded() + } + + @Test + fun `given webserver logs, when onUrlLoaded is invoked, then webserver logs vm slice onUrlLoaded is invoked`() { + viewModel.onUrlLoaded(SiteMonitorType.WEB_SERVER_LOGS) + + verify(webServerViewModel).onUrlLoaded() + } + + @Test + fun `given metrics, when onWebViewError is invoked, then metric vm slice onWebViewError is invoked`() { + viewModel.onWebViewError(SiteMonitorType.METRICS) + + verify(metricsViewModel).onWebViewError() + } + + @Test + fun `given php logs, when onWebViewError is invoked, then php logs vm slice onWebViewError is invoked`() { + viewModel.onWebViewError(SiteMonitorType.PHP_LOGS) + + verify(phpLogViewModel).onWebViewError() + } + + @Test + fun `given webserver logs, when onWebViewError is invoked, then webserver vm slice onWebViewError is invoked`() { + viewModel.onWebViewError(SiteMonitorType.WEB_SERVER_LOGS) + + verify(webServerViewModel).onWebViewError() + } +} From c21915f7cb49ca34eaec75ca62139a478ce5d163 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Wed, 31 Jan 2024 11:01:10 -0500 Subject: [PATCH 50/53] Fix detekt issue --- .../android/ui/sitemonitor/SiteMonitorWebViewClientTest.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClientTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClientTest.kt index c4f98154d6c4..38b11dbd998d 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClientTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClientTest.kt @@ -13,7 +13,9 @@ import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest import android.webkit.WebResourceError -import org.mockito.Mockito.* +import org.mockito.ArgumentMatchers.anyString +import org.mockito.Mockito.mock +import org.mockito.kotlin.never @ExperimentalCoroutinesApi class SiteMonitorWebViewClientTest : BaseUnitTest() { @@ -32,7 +34,7 @@ class SiteMonitorWebViewClientTest : BaseUnitTest() { } @Test - fun `when onPageFinished, then should invoke on webview page loaded`() { + fun `when onPageFinished, then should invoke on web view page loaded`() { webViewClient.onPageFinished(mock(WebView::class.java), "https://example.com") verify(mockListener).onWebViewPageLoaded("https://example.com", SiteMonitorType.METRICS) From e8da1d82ad1c4d47880b26a56e778962e3f9c7b0 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Wed, 31 Jan 2024 12:15:56 -0500 Subject: [PATCH 51/53] Add unit tests for SiteMonitorTabViewModelSlice --- .../SiteMonitorTabViewModelSliceTest.kt | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSliceTest.kt diff --git a/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSliceTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSliceTest.kt new file mode 100644 index 000000000000..3fe113c67fb7 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSliceTest.kt @@ -0,0 +1,127 @@ +package org.wordpress.android.ui.sitemonitor + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever +import org.wordpress.android.BaseUnitTest +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.store.AccountStore +import org.wordpress.android.fluxc.store.SiteStore +import org.wordpress.android.util.NetworkUtilsWrapper + +@ExperimentalCoroutinesApi +class SiteMonitorTabViewModelSliceTest : BaseUnitTest() { + @Mock + private lateinit var networkUtilsWrapper: NetworkUtilsWrapper + @Mock + private lateinit var accountStore: AccountStore + @Mock + private lateinit var mapper: SiteMonitorMapper + @Mock + private lateinit var siteMonitorUtils: SiteMonitorUtils + @Mock + private lateinit var siteStore: SiteStore + + private lateinit var viewModel: SiteMonitorTabViewModelSlice + + val site = mock() + + @Before + fun setUp() = test { + viewModel = SiteMonitorTabViewModelSlice( + networkUtilsWrapper, + accountStore, + mapper, + siteMonitorUtils, + siteStore + ) + + whenever(accountStore.account).thenReturn(mock()) + whenever(accountStore.account.userName).thenReturn(USER_NAME) + whenever(accountStore.accessToken).thenReturn(ACCESS_TOKEN) + + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true) + whenever(mapper.toGenericError(any())).thenReturn(mock()) + whenever(mapper.toNoNetworkError(any())).thenReturn(mock()) + whenever(mapper.toPrepared(any(), any(), any())).thenReturn(mock()) + + whenever(site.url).thenReturn(URL) + whenever(siteMonitorUtils.sanitizeSiteUrl(any())).thenReturn(URL) + whenever(siteMonitorUtils.getAuthenticationPostData(any(), any(), any(), any(), any())).thenReturn(URL) + + viewModel.initialize(testScope()) + } + + @Test + fun `when slice is instantiated, then uiState is in preparing`() { + assertThat(viewModel.uiState.value).isEqualTo(SiteMonitorUiState.Preparing) + } + + @Test + fun `given loadView(), when slice is started, then uiState is in prepared`() = test { + viewModel.start(SiteMonitorType.METRICS, SiteMonitorTabItem.Metrics.urlTemplate, site) + + assertThat(viewModel.uiState.value).isInstanceOf(SiteMonitorUiState.Prepared::class.java) + } + + @Test + fun `given null username, when slice is started, then uiState is in toGenericError`() { + whenever(accountStore.account.userName).thenReturn(null) + + viewModel.start(SiteMonitorType.METRICS, SiteMonitorTabItem.Metrics.urlTemplate, site) + + assertThat(viewModel.uiState.value).isInstanceOf(SiteMonitorUiState.GenericError::class.java) + } + + @Test + fun `given null accessToken, when slice is started, then uiState is in toGenericError`() { + whenever(accountStore.accessToken).thenReturn(null) + + viewModel.start(SiteMonitorType.METRICS, SiteMonitorTabItem.Metrics.urlTemplate, site) + + assertThat(viewModel.uiState.value).isInstanceOf(SiteMonitorUiState.GenericError::class.java) + } + + @Test + fun `given no network, when slice is started, then uiState is in error`() { + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(false) + + viewModel.start(SiteMonitorType.METRICS, SiteMonitorTabItem.Metrics.urlTemplate, site) + + assertThat(viewModel.uiState.value).isInstanceOf(SiteMonitorUiState.NoNetworkError::class.java) + } + + @Test + fun `given prepared state, when url is loaded, then uiState loaded is posted`() = test { + viewModel.start(SiteMonitorType.METRICS, SiteMonitorTabItem.Metrics.urlTemplate, site) + advanceUntilIdle() + viewModel.onUrlLoaded() + + assertThat(viewModel.uiState.value).isInstanceOf(SiteMonitorUiState.Loaded::class.java) + } + + @Test + fun `given preparing state, when url is loaded, then uiState loaded is not posted`() = test { + viewModel.onUrlLoaded() + + assertThat(viewModel.uiState.value).isInstanceOf(SiteMonitorUiState.Preparing::class.java) + } + + @Test + fun `when web view error, then error state is posted`() = test { + viewModel.onWebViewError() + + assertThat(viewModel.uiState.value).isInstanceOf(SiteMonitorUiState.GenericError::class.java) + } + + companion object { + const val USER_NAME = "user_name" + const val ACCESS_TOKEN = "access_token" + const val URL = "test.wordpress.com" + } +} From 82d7b927c466cb4babe24dac1c50370b2c9184f3 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Wed, 31 Jan 2024 13:21:45 -0500 Subject: [PATCH 52/53] Fix checkstyle empty line --- .../android/ui/sitemonitor/SiteMonitorParentActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt index 9fba7836ae95..c1773d48c83e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentActivity.kt @@ -324,5 +324,4 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. siteMonitorParentViewModel.onWebViewError(tabType) siteMonitorUtils.trackTabLoadingError(tabType) } - } From ecc32a8991a01b685104d29c8f4ce14dfc62e890 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Wed, 31 Jan 2024 13:29:54 -0500 Subject: [PATCH 53/53] Add release notes for Site Monitoring feature --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 2bb795886d6d..e2e517ec71ba 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -3,6 +3,7 @@ 24.2 ----- * [**] Fix editor crash occurring on large posts [https://github.com/wordpress-mobile/WordPress-Android/pull/20046] +* [*] [Jetpack-only] Site Monitoring: Add Metrics, PHP Logs, and Web Server Logs under Site Monitoring [https://github.com/wordpress-mobile/WordPress-Android/issues/20067] 24.1 -----