From d82215b6dcd7748e658f31e5cb26076fb571fa49 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Wed, 17 Jan 2024 10:14:35 +0100 Subject: [PATCH 001/176] 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 002/176] 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 f4983b0be0ca29cb36ce2eba20c2d117c6915f9b Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Tue, 23 Jan 2024 16:41:20 +0100 Subject: [PATCH 003/176] Disable Story block --- .../java/org/wordpress/android/ui/posts/EditPostActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index a6884db857a2..5a4637715143 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -2513,7 +2513,7 @@ private GutenbergPropsBuilder getGutenbergPropsBuilder() { SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_INSTAGRAM_EMBED_JETPACK_VERSION), SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_LOOM_EMBED_JETPACK_VERSION), SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_SMARTFRAME_EMBED_JETPACK_VERSION), - SiteUtils.supportsStoriesFeature(mSite, mJetpackFeatureRemovalPhaseHelper), + false, mSite.isUsingWpComRestApi(), enableXPosts, isUnsupportedBlockEditorEnabled, From 651aef792784da0b90344698feb92cf3f25ba3fe Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Tue, 23 Jan 2024 18:30:06 +0100 Subject: [PATCH 004/176] Update Gutenberg Mobile reference --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0d1aa95ca11a..1b836d9383cc 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' + gutenbergMobileVersion = '6568-2d7cfb9b0308cebdd0f970ff8023d89e660dfb55' wordPressAztecVersion = 'v1.9.0' wordPressFluxCVersion = '2.61.0' wordPressLoginVersion = '1.10.0' From dc2b0e876cd16e9dd41d78b64588282ee817c141 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Tue, 23 Jan 2024 18:30:39 +0100 Subject: [PATCH 005/176] Remove initial prop to control Story block --- .../java/org/wordpress/android/ui/posts/EditPostActivity.java | 2 -- .../wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt | 2 -- 2 files changed, 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index 5a4637715143..b9fbbf75af0f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -2490,7 +2490,6 @@ private GutenbergPropsBuilder getGutenbergPropsBuilder() { false, false, false, - false, true, false, !isFreeWPCom, @@ -2513,7 +2512,6 @@ private GutenbergPropsBuilder getGutenbergPropsBuilder() { SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_INSTAGRAM_EMBED_JETPACK_VERSION), SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_LOOM_EMBED_JETPACK_VERSION), SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_SMARTFRAME_EMBED_JETPACK_VERSION), - false, mSite.isUsingWpComRestApi(), enableXPosts, isUnsupportedBlockEditorEnabled, diff --git a/libs/editor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt b/libs/editor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt index c4117e0251f9..53ad2c0c9aae 100644 --- a/libs/editor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt +++ b/libs/editor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt @@ -18,7 +18,6 @@ data class GutenbergPropsBuilder( private val enableInstagramEmbed: Boolean, private val enableLoomEmbed: Boolean, private val enableSmartframeEmbed: Boolean, - private val enableMediaFilesCollectionBlocks: Boolean, private val enableMentions: Boolean, private val enableXPosts: Boolean, private val enableUnsupportedBlockEditor: Boolean, @@ -43,7 +42,6 @@ data class GutenbergPropsBuilder( enableInstagramEmbed = enableInstagramEmbed, enableLoomEmbed = enableLoomEmbed, enableSmartframeEmbed = enableSmartframeEmbed, - enableMediaFilesCollectionBlocks = enableMediaFilesCollectionBlocks, enableMentions = enableMentions, enableXPosts = enableXPosts, enableUnsupportedBlockEditor = enableUnsupportedBlockEditor, From e9c08839ab30731fb1f213b21495109ff6b6f3a0 Mon Sep 17 00:00:00 2001 From: Aditi Bhatia Date: Tue, 23 Jan 2024 14:07:34 -0800 Subject: [PATCH 006/176] Add dependencies --- WordPress/build.gradle | 1 + build.gradle | 1 + 2 files changed, 2 insertions(+) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 93370a88f9e6..ea2067a68e20 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -348,6 +348,7 @@ kapt { dependencies { implementation 'androidx.webkit:webkit:1.7.0' + implementation "androidx.navigation:navigation-compose:$androidxComposeNavigationVersion" compileOnly project(path: ':libs:annotations') kapt project(':libs:processors') implementation (project(path:':libs:networking')) { diff --git a/build.gradle b/build.gradle index 0d1aa95ca11a..574ad5e5a2ad 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ ext { androidxArchCoreVersion = '2.2.0' androidxComposeBomVersion = '2023.10.00' androidxComposeCompilerVersion = '1.5.3' + androidxComposeNavigationVersion = '2.7.6' androidxCardviewVersion = '1.0.0' androidxConstraintlayoutVersion = '2.1.4' androidxConstraintlayoutComposeVersion = '1.0.1' From 723f87763141760b6058593ec03b30f7106f7532 Mon Sep 17 00:00:00 2001 From: Aditi Bhatia Date: Tue, 23 Jan 2024 14:07:52 -0800 Subject: [PATCH 007/176] Add new screen names --- .../android/designsystem/DesignSystemDataSource.kt | 10 +++++++++- WordPress/src/main/res/values/strings.xml | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt index 13d1ed9477f6..a77353ed90fe 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt @@ -3,8 +3,16 @@ package org.wordpress.android.designsystem import org.wordpress.android.R object DesignSystemDataSource { - val buttonOptions = listOf( + val startScreenButtonOptions = listOf( R.string.design_system_foundation, R.string.design_system_components ) + val foundationScreenButtonOptions = listOf( + R.string.design_system_foundation_colors, + R.string.design_system_foundation_fonts, + R.string.design_system_foundation_Lengths + ) + val componentsScreenButtonOptions = listOf( + R.string.design_system_components_dsbutton + ) } diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index e9449d4c778d..0b4b73c32a2b 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -958,6 +958,10 @@ Design System Foundation Components + Colors + Fonts + Lengths + DSButton Stats From 130a534f9a32f8c1fc6613cdfe3c2c88f47d4314 Mon Sep 17 00:00:00 2001 From: Aditi Bhatia Date: Tue, 23 Jan 2024 16:44:21 -0800 Subject: [PATCH 008/176] Add start, component, and foundation screens --- .../DesignSystemComponentsScreen.kt | 52 ++++++++++++++++++ .../DesignSystemFoundationScreen.kt | 52 ++++++++++++++++++ .../designsystem/DesignSystemStartScreen.kt | 54 +++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt create mode 100644 WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemFoundationScreen.kt create mode 100644 WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt new file mode 100644 index 000000000000..ca8cb78e15f9 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt @@ -0,0 +1,52 @@ +package org.wordpress.android.designsystem + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.tooling.preview.Preview +import org.wordpress.android.R + +@Composable +fun DesignSystemComponentsScreen( + modifier: Modifier = Modifier +){ + Column( + modifier = modifier, + verticalArrangement = Arrangement.SpaceBetween + ) { + Row(modifier = Modifier.weight(1f, false)) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy( + dimensionResource(id = R.dimen.button_container_shadow_height) + ) + ) { + DesignSystemDataSource.componentsScreenButtonOptions.forEach { item -> + SelectOptionButton( + labelResourceId = item, + onClick = {} + ) + } + } + } + } +} + +@Preview +@Composable +fun StartDesignSystemComponentsScreenPreview(){ + DesignSystemComponentsScreen( + modifier = Modifier + .fillMaxSize() + .padding(dimensionResource(R.dimen.button_container_shadow_height)) + ) +} + diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemFoundationScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemFoundationScreen.kt new file mode 100644 index 000000000000..a744f632ef6a --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemFoundationScreen.kt @@ -0,0 +1,52 @@ +package org.wordpress.android.designsystem + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.tooling.preview.Preview +import org.wordpress.android.R + +@Composable +fun DesignSystemFoundationScreen( + modifier: Modifier = Modifier +){ + Column( + modifier = modifier, + verticalArrangement = Arrangement.SpaceBetween + ) { + Row(modifier = Modifier.weight(1f, false)) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy( + dimensionResource(id = R.dimen.button_container_shadow_height) + ) + ) { + DesignSystemDataSource.foundationScreenButtonOptions.forEach { item -> + SelectOptionButton( + labelResourceId = item, + onClick = {} + ) + } + } + } + } +} + +@Preview +@Composable +fun StartDesignSystemFoundationScreenPreview(){ + DesignSystemFoundationScreen( + modifier = Modifier + .fillMaxSize() + .padding(dimensionResource(R.dimen.button_container_shadow_height)) + ) +} + diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt new file mode 100644 index 000000000000..1a26869fb9d4 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt @@ -0,0 +1,54 @@ +package org.wordpress.android.designsystem + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.tooling.preview.Preview +import org.wordpress.android.R + +@Composable +fun DesignSystemStartScreen( + onNextButtonClicked: () -> Unit, + modifier: Modifier = Modifier +){ + Column( + modifier = modifier, + verticalArrangement = Arrangement.SpaceBetween + ) { + Row(modifier = Modifier.weight(1f, false)) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy( + dimensionResource(id = R.dimen.button_container_shadow_height) + ) + ) { + DesignSystemDataSource.startScreenButtonOptions.forEach { item -> + SelectOptionButton( + labelResourceId = item, + onClick = { onNextButtonClicked() } + ) + } + } + } + } +} + +@Preview +@Composable +fun StartDesignSystemStartScreenPreview(){ + DesignSystemStartScreen( + onNextButtonClicked = {}, + modifier = Modifier + .fillMaxSize() + .padding(dimensionResource(R.dimen.button_container_shadow_height)) + ) +} + From 8f7dee812d616099ee54e796dd9313240d9d4cea Mon Sep 17 00:00:00 2001 From: Andy Valdez Date: Wed, 24 Jan 2024 15:14:50 -0500 Subject: [PATCH 009/176] [Lib] Update about-automattic to 1.4.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5cb7f225ec83..e3a503a8b365 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ ext { ext { // libs - automatticAboutVersion = '1.3.0' + automatticAboutVersion = '1.4.0' automatticRestVersion = '1.0.8' automatticStoriesVersion = '2.4.0' automatticTracksVersion = '3.3.0' From 155fae064b536dd1988be4010f6a121896cfe99b Mon Sep 17 00:00:00 2001 From: Aditi Bhatia Date: Wed, 24 Jan 2024 12:33:42 -0800 Subject: [PATCH 010/176] Add top bar and onBackPressed navigation --- .../designsystem/DesignSystemActivity.kt | 4 +- .../designsystem/DesignSystemScreen.kt | 134 ++++++++++++------ 2 files changed, 92 insertions(+), 46 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemActivity.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemActivity.kt index 581d711e1b61..5d15ef196cc9 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemActivity.kt @@ -11,7 +11,7 @@ class DesignSystemActivity : LocaleAwareActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { - DesignSystem() + DesignSystem(onBackPressedDispatcher::onBackPressed) } } @@ -24,7 +24,7 @@ class DesignSystemActivity : LocaleAwareActivity() { @Composable fun PreviewDesignSystemActivity() { - DesignSystem() + DesignSystem(onBackPressedDispatcher::onBackPressed) } } diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt index d04d1cc1ad7c..bbef21bbf1d9 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt @@ -1,55 +1,39 @@ package org.wordpress.android.designsystem import androidx.annotation.StringRes -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.widthIn +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController import org.wordpress.android.R -import org.wordpress.android.designsystem.DesignSystemDataSource.buttonOptions +import org.wordpress.android.ui.compose.components.MainTopAppBar +import org.wordpress.android.ui.compose.components.NavigationIcons enum class DesignSystemScreen { - Start -} -@Composable -fun DesignSystemStartScreen( - modifier: Modifier = Modifier -){ - Column( - modifier = modifier, - verticalArrangement = Arrangement.SpaceBetween - ) { - Row(modifier = Modifier.weight(1f, false)) { - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy( - dimensionResource(id = R.dimen.button_container_shadow_height) - ) - ) { - buttonOptions.forEach { item -> - SelectOptionButton( - labelResourceId = item, - onClick = {} - ) - } - } - } - } + Start, + Foundation, + Components } @Composable @@ -69,18 +53,80 @@ fun SelectOptionButton( @Preview @Composable -fun StartDesignSystemPreview() { - DesignSystemStartScreen( - modifier = Modifier - .fillMaxSize() - .padding(dimensionResource(R.dimen.button_container_shadow_height)) - ) +fun StartDesignSystemPreview(){ + DesignSystem {} } + +@OptIn(ExperimentalMaterial3Api::class) @Composable -fun DesignSystem() { - DesignSystemStartScreen( - modifier = Modifier - .fillMaxSize() - .padding(dimensionResource(R.dimen.button_container_shadow_height)) +fun DesignSystemAppBar( +// currentScreen: DesignSystemScreen, + canNavigateBack: Boolean, + navigateUp: () -> Unit, + modifier: Modifier = Modifier +) { + TopAppBar( + title = { Text(stringResource(id = R.string.app_name)) }, + colors = TopAppBarDefaults.mediumTopAppBarColors( + containerColor = MaterialTheme.colorScheme.primaryContainer + ), + modifier = modifier, + navigationIcon = { + if (canNavigateBack) { + IconButton(onClick = navigateUp) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = stringResource(R.string.backdated_for) + ) + } + } + } ) } +@Composable +fun DesignSystem( + onBackTapped: () -> Unit + ) { + val navController: NavHostController = rememberNavController() + Scaffold( + topBar = { + MainTopAppBar( + title = stringResource(R.string.preference_design_system), + navigationIcon = NavigationIcons.BackIcon, + onNavigationIconClick = { onBackTapped() }, + backgroundColor = MaterialTheme.colorScheme.surface, + contentColor = MaterialTheme.colorScheme.onSurface, + ) + }, + ) { innerPadding -> + NavHost( + navController = navController, + startDestination = DesignSystemScreen.Start.name + ) { + composable(route = DesignSystemScreen.Start.name) { + DesignSystemStartScreen( + onNextButtonClicked = { + navController.navigate(DesignSystemScreen.Foundation.name) + }, + modifier = Modifier + .fillMaxSize() + .padding(innerPadding) + ) + } + composable(route = DesignSystemScreen.Foundation.name) { + DesignSystemFoundationScreen( + modifier = Modifier + .fillMaxSize() + .padding(dimensionResource(R.dimen.button_container_shadow_height)) + ) + } + composable(route = DesignSystemScreen.Components.name) { + DesignSystemFoundationScreen( + modifier = Modifier + .fillMaxSize() + .padding(dimensionResource(R.dimen.button_container_shadow_height)) + ) + } + } + } +} From 3e1e9a30d77be4b85ee939664e4935e08eb219fa Mon Sep 17 00:00:00 2001 From: Aditi Bhatia Date: Wed, 24 Jan 2024 12:46:51 -0800 Subject: [PATCH 011/176] Cleanup --- .../designsystem/DesignSystemScreen.kt | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt index bbef21bbf1d9..efc4bea4f10a 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt @@ -57,32 +57,6 @@ fun StartDesignSystemPreview(){ DesignSystem {} } -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun DesignSystemAppBar( -// currentScreen: DesignSystemScreen, - canNavigateBack: Boolean, - navigateUp: () -> Unit, - modifier: Modifier = Modifier -) { - TopAppBar( - title = { Text(stringResource(id = R.string.app_name)) }, - colors = TopAppBarDefaults.mediumTopAppBarColors( - containerColor = MaterialTheme.colorScheme.primaryContainer - ), - modifier = modifier, - navigationIcon = { - if (canNavigateBack) { - IconButton(onClick = navigateUp) { - Icon( - imageVector = Icons.Filled.ArrowBack, - contentDescription = stringResource(R.string.backdated_for) - ) - } - } - } - ) -} @Composable fun DesignSystem( onBackTapped: () -> Unit From 70e2371f29945f61eaeb98b8636c90c58caada09 Mon Sep 17 00:00:00 2001 From: Andy Valdez Date: Wed, 24 Jan 2024 15:59:15 -0500 Subject: [PATCH 012/176] [Lib] Update Wordpress-Utils from 3.11.0 to 3.12.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5cb7f225ec83..e20c78cd7489 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ ext { wordPressFluxCVersion = '2.61.0' wordPressLoginVersion = '1.10.0' wordPressPersistentEditTextVersion = '1.0.2' - wordPressUtilsVersion = '3.11.0' + wordPressUtilsVersion = '3.12.0' indexosMediaForMobileVersion = '43a9026f0973a2f0a74fa813132f6a16f7499c3a' // debug From f132d4fd7163231c01656cd4b6b29dfb9636f5d9 Mon Sep 17 00:00:00 2001 From: Aditi Bhatia Date: Wed, 24 Jan 2024 13:03:38 -0800 Subject: [PATCH 013/176] Detekt --- .../wordpress/android/designsystem/DesignSystemScreen.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt index efc4bea4f10a..70e8bfdf8914 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt @@ -4,18 +4,11 @@ import androidx.annotation.StringRes import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.widthIn -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource From bffba670573c79511671335512a771db3dab2af6 Mon Sep 17 00:00:00 2001 From: Aditi Bhatia Date: Wed, 24 Jan 2024 13:27:51 -0800 Subject: [PATCH 014/176] Update button click handling + padding --- .../android/designsystem/DesignSystemDataSource.kt | 4 ++-- .../wordpress/android/designsystem/DesignSystemScreen.kt | 8 ++++---- .../android/designsystem/DesignSystemStartScreen.kt | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt index a77353ed90fe..d7bf384d4b94 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt @@ -4,8 +4,8 @@ import org.wordpress.android.R object DesignSystemDataSource { val startScreenButtonOptions = listOf( - R.string.design_system_foundation, - R.string.design_system_components + Pair(R.string.design_system_foundation, DesignSystemScreen.Foundation.name), + Pair(R.string.design_system_components, DesignSystemScreen.Components.name), ) val foundationScreenButtonOptions = listOf( R.string.design_system_foundation_colors, diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt index 70e8bfdf8914..ffffe2f961ee 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt @@ -73,7 +73,7 @@ fun DesignSystem( composable(route = DesignSystemScreen.Start.name) { DesignSystemStartScreen( onNextButtonClicked = { - navController.navigate(DesignSystemScreen.Foundation.name) + navController.navigate(it) }, modifier = Modifier .fillMaxSize() @@ -84,14 +84,14 @@ fun DesignSystem( DesignSystemFoundationScreen( modifier = Modifier .fillMaxSize() - .padding(dimensionResource(R.dimen.button_container_shadow_height)) + .padding(innerPadding) ) } composable(route = DesignSystemScreen.Components.name) { - DesignSystemFoundationScreen( + DesignSystemComponentsScreen( modifier = Modifier .fillMaxSize() - .padding(dimensionResource(R.dimen.button_container_shadow_height)) + .padding(innerPadding) ) } } diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt index 1a26869fb9d4..ff2a5ea23083 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt @@ -15,7 +15,7 @@ import org.wordpress.android.R @Composable fun DesignSystemStartScreen( - onNextButtonClicked: () -> Unit, + onNextButtonClicked: (String) -> Unit, modifier: Modifier = Modifier ){ Column( @@ -32,8 +32,8 @@ fun DesignSystemStartScreen( ) { DesignSystemDataSource.startScreenButtonOptions.forEach { item -> SelectOptionButton( - labelResourceId = item, - onClick = { onNextButtonClicked() } + labelResourceId = item.first, + onClick = { onNextButtonClicked(item.second) } ) } } From 965fe2a82cfed5e709b10e6ae1162a4b1190947c Mon Sep 17 00:00:00 2001 From: Aditi Bhatia Date: Wed, 24 Jan 2024 13:28:15 -0800 Subject: [PATCH 015/176] Unused import --- .../org/wordpress/android/designsystem/DesignSystemScreen.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt index ffffe2f961ee..2168e7048b22 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemScreen.kt @@ -11,7 +11,6 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp From 79018e5cdbac3a708b99be8ddb34dfa4b25914f8 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Thu, 25 Jan 2024 12:35:30 +0100 Subject: [PATCH 016/176] Update Gutenberg Mobile reference --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1b836d9383cc..a5c768978d42 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 = '6568-2d7cfb9b0308cebdd0f970ff8023d89e660dfb55' + gutenbergMobileVersion = '6568-0f3651afefe61f4ec6e45489eda307b4ca9d62b3' wordPressAztecVersion = 'v1.9.0' wordPressFluxCVersion = '2.61.0' wordPressLoginVersion = '1.10.0' From 6f5e57c8d9e8cc447d623bd8ef21679bc35f53d2 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Thu, 25 Jan 2024 13:36:15 +0100 Subject: [PATCH 017/176] Update Gutenberg Mobile reference --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a5c768978d42..fe486b0b87f9 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 = '6568-0f3651afefe61f4ec6e45489eda307b4ca9d62b3' + gutenbergMobileVersion = '6568-674dc6550184c3b60cbb392091f7e9166ab06cad' wordPressAztecVersion = 'v1.9.0' wordPressFluxCVersion = '2.61.0' wordPressLoginVersion = '1.10.0' From 709aae04a534b74fb7e20c07d705538521865887 Mon Sep 17 00:00:00 2001 From: Oguz Kocer Date: Thu, 25 Jan 2024 09:01:44 -0500 Subject: [PATCH 018/176] Switch gutenberg-mobile's dependency group to org.wordpress --- WordPress/build.gradle | 5 ----- config/gradle/included_builds.gradle | 2 +- libs/editor/build.gradle | 6 +----- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 710331e05165..0ca627ad6fbc 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -40,11 +40,6 @@ repositories { includeGroup "com.automattic" includeGroup "com.automattic.stories" includeGroup "com.automattic.tracks" - // 'org.wordpress-mobile' group is deprecated. It's kept for now for smoother transition - // but it should be removed soon (within couple weeks) - includeGroup "org.wordpress-mobile" - includeGroup "org.wordpress-mobile.gutenberg-mobile" - includeGroupByRegex "org.wordpress-mobile.react-native-libraries.*" } } maven { diff --git a/config/gradle/included_builds.gradle b/config/gradle/included_builds.gradle index 30075447e471..493a2dedb405 100644 --- a/config/gradle/included_builds.gradle +++ b/config/gradle/included_builds.gradle @@ -1,6 +1,6 @@ gradle.ext.fluxCBinaryPath = "org.wordpress:fluxc" gradle.ext.wputilsBinaryPath = "org.wordpress:utils" -gradle.ext.gutenbergMobileBinaryPath = "org.wordpress-mobile.gutenberg-mobile:react-native-gutenberg-bridge" +gradle.ext.gutenbergMobileBinaryPath = "org.wordpress.gutenberg-mobile:react-native-gutenberg-bridge" gradle.ext.includedBuildGutenbergMobilePath = null gradle.ext.loginFlowBinaryPath = "org.wordpress:login" gradle.ext.storiesAndroidPath = "com.automattic:stories" diff --git a/libs/editor/build.gradle b/libs/editor/build.gradle index 288035530a8a..1c92342a989d 100644 --- a/libs/editor/build.gradle +++ b/libs/editor/build.gradle @@ -11,12 +11,8 @@ repositories { content { includeGroup "org.wordpress" includeGroup "org.wordpress.aztec" + includeGroup "org.wordpress.gutenberg-mobile" includeGroupByRegex "org.wordpress.react-native-libraries.*" - // 'org.wordpress-mobile' group is deprecated. It's kept for now for smoother transition - // but it should be removed soon (within couple weeks) - includeGroup "org.wordpress-mobile" - includeGroup "org.wordpress-mobile.gutenberg-mobile" - includeGroupByRegex "org.wordpress-mobile.react-native-libraries.*" } } maven { From df45fc7909d27e5478d5b8b3d100e5449ca7de06 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Thu, 25 Jan 2024 15:25:38 +0100 Subject: [PATCH 019/176] Update Gutenberg Mobile binary path to use new group id --- config/gradle/included_builds.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/gradle/included_builds.gradle b/config/gradle/included_builds.gradle index 30075447e471..493a2dedb405 100644 --- a/config/gradle/included_builds.gradle +++ b/config/gradle/included_builds.gradle @@ -1,6 +1,6 @@ gradle.ext.fluxCBinaryPath = "org.wordpress:fluxc" gradle.ext.wputilsBinaryPath = "org.wordpress:utils" -gradle.ext.gutenbergMobileBinaryPath = "org.wordpress-mobile.gutenberg-mobile:react-native-gutenberg-bridge" +gradle.ext.gutenbergMobileBinaryPath = "org.wordpress.gutenberg-mobile:react-native-gutenberg-bridge" gradle.ext.includedBuildGutenbergMobilePath = null gradle.ext.loginFlowBinaryPath = "org.wordpress:login" gradle.ext.storiesAndroidPath = "com.automattic:stories" From 8c233d433e66698453223384f3227b218b5ba306 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Thu, 25 Jan 2024 15:26:01 +0100 Subject: [PATCH 020/176] Include new group id in editor `build.gradle` --- libs/editor/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/editor/build.gradle b/libs/editor/build.gradle index 288035530a8a..6f518cf2b000 100644 --- a/libs/editor/build.gradle +++ b/libs/editor/build.gradle @@ -11,6 +11,7 @@ repositories { content { includeGroup "org.wordpress" includeGroup "org.wordpress.aztec" + includeGroup "org.wordpress.gutenberg-mobile" includeGroupByRegex "org.wordpress.react-native-libraries.*" // 'org.wordpress-mobile' group is deprecated. It's kept for now for smoother transition // but it should be removed soon (within couple weeks) From 8cd50840318fa97ba065b444d6fc1278987502d7 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Thu, 25 Jan 2024 18:10:24 +0200 Subject: [PATCH 021/176] Add Site monitoring FF to SiteListItemBuilder --- .../items/listitem/SiteListItemBuilder.kt | 7 +++--- .../config/SiteMonitoringFeatureConfig.kt | 9 +++++-- .../items/listitem/SiteListItemBuilderTest.kt | 24 ++++++++++++++++--- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilder.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilder.kt index d847635c9626..196e1f8aee2e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilder.kt @@ -29,6 +29,7 @@ import org.wordpress.android.ui.utils.UiString.UiStringText import org.wordpress.android.util.BuildConfigWrapper import org.wordpress.android.util.DateTimeUtils import org.wordpress.android.util.SiteUtilsWrapper +import org.wordpress.android.util.config.SiteMonitoringFeatureConfig import java.util.GregorianCalendar import java.util.TimeZone import javax.inject.Inject @@ -39,7 +40,8 @@ class SiteListItemBuilder @Inject constructor( private val siteUtilsWrapper: SiteUtilsWrapper, private val buildConfigWrapper: BuildConfigWrapper, private val themeBrowserUtils: ThemeBrowserUtils, - private val jetpackFeatureRemovalPhaseHelper: JetpackFeatureRemovalPhaseHelper + private val jetpackFeatureRemovalPhaseHelper: JetpackFeatureRemovalPhaseHelper, + private val siteMonitoringFeatureConfig: SiteMonitoringFeatureConfig ) { fun buildActivityLogItemIfAvailable(site: SiteModel, onClick: (ListItemAction) -> Unit): ListItem? { val isWpComOrJetpack = siteUtilsWrapper.isAccessedViaWPComRest( @@ -246,8 +248,7 @@ class SiteListItemBuilder @Inject constructor( } fun buildSiteMonitoringItemIfAvailable(site: SiteModel, onClick: (ListItemAction) -> Unit): MySiteCardAndItem? { - // todo: Add the feature flag wrapper once it is available - return if (buildConfigWrapper.isJetpackApp && site.isWPComAtomic && site.isAdmin) { + return if (siteMonitoringFeatureConfig.isEnabled() && site.isWPComAtomic && site.isAdmin) { ListItem( R.drawable.gb_ic_tool, UiStringRes(R.string.site_monitoring), diff --git a/WordPress/src/main/java/org/wordpress/android/util/config/SiteMonitoringFeatureConfig.kt b/WordPress/src/main/java/org/wordpress/android/util/config/SiteMonitoringFeatureConfig.kt index 0a7789dda5e2..6a2cc90c1fdb 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/config/SiteMonitoringFeatureConfig.kt +++ b/WordPress/src/main/java/org/wordpress/android/util/config/SiteMonitoringFeatureConfig.kt @@ -2,14 +2,19 @@ package org.wordpress.android.util.config import org.wordpress.android.BuildConfig import org.wordpress.android.annotation.Feature +import javax.inject.Inject private const val SITE_MONITORING_FEATURE_REMOTE_FIELD = "site_monitoring" @Feature(SITE_MONITORING_FEATURE_REMOTE_FIELD, false) -class SiteMonitoringFeatureConfig( +class SiteMonitoringFeatureConfig @Inject constructor( appConfig: AppConfig ) : FeatureConfig( appConfig, BuildConfig.ENABLE_SITE_MONITORING, SITE_MONITORING_FEATURE_REMOTE_FIELD -) +) { + override fun isEnabled(): Boolean { + return super.isEnabled() && BuildConfig.IS_JETPACK_APP + } +} diff --git a/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt index 7d579919727b..a8f6e54b341c 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt @@ -29,6 +29,7 @@ import org.wordpress.android.ui.plugins.PluginUtilsWrapper import org.wordpress.android.ui.themes.ThemeBrowserUtils import org.wordpress.android.util.BuildConfigWrapper import org.wordpress.android.util.SiteUtilsWrapper +import org.wordpress.android.util.config.SiteMonitoringFeatureConfig @RunWith(MockitoJUnitRunner::class) class SiteListItemBuilderTest { @@ -53,6 +54,9 @@ class SiteListItemBuilderTest { @Mock lateinit var jetpackFeatureRemovalPhaseHelper: JetpackFeatureRemovalPhaseHelper + @Mock + lateinit var siteMonitoringFeatureConfig: SiteMonitoringFeatureConfig + private lateinit var siteListItemBuilder: SiteListItemBuilder @Before @@ -63,7 +67,8 @@ class SiteListItemBuilderTest { siteUtilsWrapper, buildConfigWrapper, themeBrowserUtils, - jetpackFeatureRemovalPhaseHelper + jetpackFeatureRemovalPhaseHelper, + siteMonitoringFeatureConfig ) } @@ -417,14 +422,25 @@ class SiteListItemBuilderTest { /* SITE MONITORING */ @Test - fun `give jetpack app, when is atomic and admin, then site monitoring item is built`() { - setupSiteMonitoringItems() + fun `give jetpack app, when is atomic and admin and FF is enabled, then site monitoring item is built`() { + setupSiteMonitoringItems( + isSiteMonitoringFeatureFlagEnabled = true + ) val item = siteListItemBuilder.buildSiteMonitoringItemIfAvailable(siteModel, SITE_ITEM_ACTION) assertThat(item).isEqualTo(SITE_MONITORING_ITEM) } + @Test + fun `give jetpack app, when is atomic and admin and FF is disabled, then site monitoring item is not built`() { + setupSiteMonitoringItems() + + val item = siteListItemBuilder.buildSiteMonitoringItemIfAvailable(siteModel, SITE_ITEM_ACTION) + + assertThat(item).isNull() + } + @Test fun `give jetpack app, when is not atomic, then site monitoring item is not built`() { setupSiteMonitoringItems( @@ -460,10 +476,12 @@ class SiteListItemBuilderTest { private fun setupSiteMonitoringItems( isJetpackApp: Boolean = true, + isSiteMonitoringFeatureFlagEnabled: Boolean = false, isAtomic: Boolean = true, isAdmin: Boolean = true ) { whenever(buildConfigWrapper.isJetpackApp).thenReturn(isJetpackApp) + whenever(siteMonitoringFeatureConfig.isEnabled()).thenReturn(isSiteMonitoringFeatureFlagEnabled) whenever(siteModel.isAdmin).thenReturn(isAdmin) whenever(siteModel.isWPComAtomic).thenReturn(isAtomic) } From 95c3644fbc3f80fae4a1737c14c95e6968ebae80 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 01:21:38 +0000 Subject: [PATCH 022/176] feat: Remove pop-up for in-editor photo selection --- .../android/ui/posts/EditPostActivity.java | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index a6884db857a2..b7a9e24ab287 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -2842,12 +2842,6 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { // handleMediaPickerResult -> addExistingMediaToEditorAndSave break; case RequestCodes.PHOTO_PICKER: - if (WPMediaUtils.shouldAdvertiseImageOptimization(this)) { - WPMediaUtils.advertiseImageOptimization(this, () -> handlePhotoPickerResult(data)); - } else { - handlePhotoPickerResult(data); - } - break; case RequestCodes.STOCK_MEDIA_PICKER_SINGLE_SELECT: handlePhotoPickerResult(data); break; @@ -2861,18 +2855,12 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { break; case RequestCodes.MEDIA_LIBRARY: case RequestCodes.PICTURE_LIBRARY: - mEditorMedia.advertiseImageOptimisationAndAddMedia(WPMediaUtils.retrieveMediaUris(data)); - break; - case RequestCodes.TAKE_PHOTO: - if (WPMediaUtils.shouldAdvertiseImageOptimization(this)) { - WPMediaUtils.advertiseImageOptimization(this, this::addLastTakenPicture); - } else { - addLastTakenPicture(); - } - break; case RequestCodes.VIDEO_LIBRARY: mEditorMedia.addNewMediaItemsToEditorAsync(WPMediaUtils.retrieveMediaUris(data), false); break; + case RequestCodes.TAKE_PHOTO: + addLastTakenPicture(); + break; case RequestCodes.TAKE_VIDEO: Uri videoUri = data.getData(); mEditorMedia.addNewMediaToEditorAsync(videoUri, true); @@ -3940,10 +3928,6 @@ public void syncPostObjectWithUiAndSaveIt(@Nullable OnPostUpdatedFromUIListener updateAndSavePostAsync(listener); } - @Override public void advertiseImageOptimization(@NonNull Function0 listener) { - WPMediaUtils.advertiseImageOptimization(this, listener::invoke); - } - @Override public void onMediaModelsCreatedFromOptimizedUris(@NonNull Map oldUriToMediaModels) { // no op - we're not doing any special handling on MediaModels in EditPostActivity From b02c0029c90c4747c911307280366890d8de189d Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 01:22:30 +0000 Subject: [PATCH 023/176] feat: Remove pop-up for Story posts --- .../ui/stories/StoryComposerActivity.kt | 4 -- .../ui/stories/media/StoryEditorMedia.kt | 21 +------ .../stories/usecase/StoryEditorMediaTest.kt | 58 +------------------ 3 files changed, 2 insertions(+), 81 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt index 4f6c7cdfa70e..793dc32ce3a5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt @@ -488,10 +488,6 @@ class StoryComposerActivity : ComposeLoopFrameActivity(), listener?.onPostUpdatedFromUI(null) } - override fun advertiseImageOptimization(listener: () -> Unit) { - WPMediaUtils.advertiseImageOptimization(this) { listener.invoke() } - } - override fun onMediaModelsCreatedFromOptimizedUris(oldUriToMediaFiles: Map) { // no op - we're not doing any special handling while composing, only when saving in the UploadBridge } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt b/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt index 4a7dac9dd852..78f11123c791 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt @@ -55,20 +55,6 @@ class StoryEditorMedia @Inject constructor( _uiState.value = AddingMediaToStoryIdle } - // region Adding new media to a post - fun advertiseImageOptimisationAndAddMedia(uriList: List) { - if (mediaUtilsWrapper.shouldAdvertiseImageOptimization()) { - editorMediaListener.advertiseImageOptimization { - addNewMediaItemsToEditorAsync( - uriList, - false - ) - } - } else { - addNewMediaItemsToEditorAsync(uriList, false) - } - } - fun addNewMediaItemsToEditorAsync(uriList: List, freshlyTaken: Boolean) { launch { _uiState.value = if (uriList.size > 1) { @@ -92,12 +78,7 @@ class StoryEditorMedia @Inject constructor( } fun onPhotoPickerMediaChosen(uriList: List) { - val onlyVideos = uriList.all { mediaUtilsWrapper.isVideo(it.toString()) } - if (onlyVideos) { - addNewMediaItemsToEditorAsync(uriList, false) - } else { - advertiseImageOptimisationAndAddMedia(uriList) - } + addNewMediaItemsToEditorAsync(uriList, false) } // endregion diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt index 2bc45b71e985..a42a90bb2d11 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt @@ -28,38 +28,6 @@ import org.wordpress.android.viewmodel.Event @ExperimentalCoroutinesApi class StoryEditorMediaTest : BaseUnitTest() { - @Test - fun `advertiseImageOptimisationAndAddMedia shows dialog when shouldAdvertiseImageOptimization is true`() { - // Arrange - val editorMediaListener = mock() - val mediaUtilsWrapper = createMediaUtilsWrapper(shouldAdvertiseImageOptimization = true) - - // Act - createStoryEditorMedia( - editorMediaListener = editorMediaListener, - mediaUtilsWrapper = mediaUtilsWrapper - ).advertiseImageOptimisationAndAddMedia(mock()) - - // Assert - verify(editorMediaListener).advertiseImageOptimization(anyOrNull()) - } - - @Test - fun `advertiseImageOptimisationAndAddMedia does NOT show dialog when shouldAdvertiseImageOptimization is false`() { - // Arrange - val editorMediaListener = mock() - val mediaUtilsWrapper = createMediaUtilsWrapper(shouldAdvertiseImageOptimization = false) - - // Act - createStoryEditorMedia( - editorMediaListener = editorMediaListener, - mediaUtilsWrapper = mediaUtilsWrapper - ) - .advertiseImageOptimisationAndAddMedia(mock()) - // Assert - verify(editorMediaListener, never()).advertiseImageOptimization(anyOrNull()) - } - @Test fun `addNewMediaItemsToEditorAsync emits AddingSingleMedia for a single uri`() = test { // Arrange @@ -117,26 +85,6 @@ class StoryEditorMediaTest : BaseUnitTest() { verify(observer, never()).onChanged(captor.capture()) } - @Test - fun `onPhotoPickerMediaChosen does NOT invoke shouldAdvertiseImageOptimization when only video files`() = - test { - // Arrange - val uris = listOf(VIDEO_URI, VIDEO_URI, VIDEO_URI, VIDEO_URI) - val editorMediaListener = mock() - - val mediaUtilsWrapper = createMediaUtilsWrapper() - - // Act - createStoryEditorMedia( - mediaUtilsWrapper = mediaUtilsWrapper, - editorMediaListener = editorMediaListener - ) - .onPhotoPickerMediaChosen(uris) - // Assert - verify(editorMediaListener, never()).advertiseImageOptimization(anyOrNull()) - verify(mediaUtilsWrapper, never()).shouldAdvertiseImageOptimization() - } - @Test fun `onPhotoPickerMediaChosen invokes shouldAdvertiseImageOptimization when at least 1 image file`() = test { @@ -177,12 +125,8 @@ class StoryEditorMediaTest : BaseUnitTest() { return editorMedia } - fun createMediaUtilsWrapper( - shouldAdvertiseImageOptimization: Boolean = false - ) = + fun createMediaUtilsWrapper() = mock { - on { shouldAdvertiseImageOptimization() } - .thenReturn(shouldAdvertiseImageOptimization) on { isVideo(VIDEO_URI.toString()) }.thenReturn(true) on { isVideo(IMAGE_URI.toString()) }.thenReturn(false) } From 4c238dc6142b9f5b2805f21888207761c3e2fbfe Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 01:24:38 +0000 Subject: [PATCH 024/176] feat: Remove pop-up for uploads in media screen --- .../ui/media/MediaBrowserActivity.java | 14 +--- .../ui/posts/editor/media/EditorMedia.kt | 21 +----- .../posts/editor/media/EditorMediaListener.kt | 1 - .../ui/posts/editor/media/EditorMediaTest.kt | 71 ------------------- 4 files changed, 3 insertions(+), 104 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java index 520773af12f0..d434f5024f09 100755 --- a/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java @@ -508,24 +508,14 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { case RequestCodes.PICTURE_LIBRARY: case RequestCodes.VIDEO_LIBRARY: case RequestCodes.AUDIO_LIBRARY: - handlePickerResult(data, resultCode); - break; case RequestCodes.FILE_LIBRARY: if (resultCode == Activity.RESULT_OK && data != null) { - if (WPMediaUtils.shouldAdvertiseImageOptimization(this)) { - WPMediaUtils.advertiseImageOptimization(this, () -> handlePickerResult(data, resultCode)); - } else { - handlePickerResult(data, resultCode); - } + handlePickerResult(data, resultCode); } break; case RequestCodes.TAKE_PHOTO: if (resultCode == Activity.RESULT_OK) { - if (WPMediaUtils.shouldAdvertiseImageOptimization(this)) { - WPMediaUtils.advertiseImageOptimization(this, this::addLastTakenPicture); - } else { - addLastTakenPicture(); - } + addLastTakenPicture(); } break; case RequestCodes.TAKE_VIDEO: diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt index 0edca25c46ee..90ae61b8893d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt @@ -95,20 +95,6 @@ class EditorMedia @Inject constructor( _uiState.value = AddingMediaIdle } - // region Adding new media to a post - fun advertiseImageOptimisationAndAddMedia(uriList: List) { - if (mediaUtilsWrapper.shouldAdvertiseImageOptimization()) { - editorMediaListener.advertiseImageOptimization { - addNewMediaItemsToEditorAsync( - uriList, - false - ) - } - } else { - addNewMediaItemsToEditorAsync(uriList, false) - } - } - fun addNewMediaToEditorAsync(mediaUri: Uri, freshlyTaken: Boolean) { addNewMediaItemsToEditorAsync(listOf(mediaUri), freshlyTaken) } @@ -147,12 +133,7 @@ class EditorMedia @Inject constructor( } fun onPhotoPickerMediaChosen(uriList: List) { - val onlyVideos = uriList.all { mediaUtilsWrapper.isVideo(it.toString()) } - if (onlyVideos) { - addNewMediaItemsToEditorAsync(uriList, false) - } else { - advertiseImageOptimisationAndAddMedia(uriList) - } + addNewMediaItemsToEditorAsync(uriList, false) } // endregion diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMediaListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMediaListener.kt index 4f40d9affda0..b597d9c3ea18 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMediaListener.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMediaListener.kt @@ -9,7 +9,6 @@ import org.wordpress.android.util.helpers.MediaFile interface EditorMediaListener { fun appendMediaFiles(mediaFiles: Map) fun syncPostObjectWithUiAndSaveIt(listener: OnPostUpdatedFromUIListener? = null) - fun advertiseImageOptimization(listener: () -> Unit) fun onMediaModelsCreatedFromOptimizedUris(oldUriToMediaFiles: Map) fun getImmutablePost(): PostImmutableModel fun showVideoDurationLimitWarning(fileName: String) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt index c081fceead0b..786662f9e9e6 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt @@ -36,38 +36,6 @@ import org.wordpress.android.viewmodel.helpers.ToastMessageHolder @ExperimentalCoroutinesApi class EditorMediaTest : BaseUnitTest() { - @Test - fun `advertiseImageOptimisationAndAddMedia shows dialog when shouldAdvertiseImageOptimization is true`() { - // Arrange - val editorMediaListener = mock() - val mediaUtilsWrapper = createMediaUtilsWrapper(shouldAdvertiseImageOptimization = true) - - // Act - createEditorMedia( - editorMediaListener = editorMediaListener, - mediaUtilsWrapper = mediaUtilsWrapper - ) - .advertiseImageOptimisationAndAddMedia(mock()) - // Assert - verify(editorMediaListener).advertiseImageOptimization(anyOrNull()) - } - - @Test - fun `advertiseImageOptimisationAndAddMedia does NOT show dialog when shouldAdvertiseImageOptimization is false`() { - // Arrange - val editorMediaListener = mock() - val mediaUtilsWrapper = createMediaUtilsWrapper(shouldAdvertiseImageOptimization = false) - - // Act - createEditorMedia( - editorMediaListener = editorMediaListener, - mediaUtilsWrapper = mediaUtilsWrapper - ) - .advertiseImageOptimisationAndAddMedia(mock()) - // Assert - verify(editorMediaListener, never()).advertiseImageOptimization(anyOrNull()) - } - @Test fun `addNewMediaItemsToEditorAsync emits AddingSingleMedia for a single uri`() = test { // Arrange @@ -142,45 +110,6 @@ class EditorMediaTest : BaseUnitTest() { ) } - @Test - fun `onPhotoPickerMediaChosen does NOT invoke shouldAdvertiseImageOptimization when only video files`() = - test { - // Arrange - val uris = listOf(VIDEO_URI, VIDEO_URI, VIDEO_URI, VIDEO_URI) - val editorMediaListener = mock() - - val mediaUtilsWrapper = createMediaUtilsWrapper() - - // Act - createEditorMedia( - mediaUtilsWrapper = mediaUtilsWrapper, - editorMediaListener = editorMediaListener - ) - .onPhotoPickerMediaChosen(uris) - // Assert - verify(editorMediaListener, never()).advertiseImageOptimization(anyOrNull()) - verify(mediaUtilsWrapper, never()).shouldAdvertiseImageOptimization() - } - - @Test - fun `onPhotoPickerMediaChosen invokes shouldAdvertiseImageOptimization when at least 1 image file`() = - test { - // Arrange - val uris = listOf(VIDEO_URI, VIDEO_URI, IMAGE_URI, VIDEO_URI) - val editorMediaListener = mock() - - val mediaUtilsWrapper = createMediaUtilsWrapper() - - // Act - createEditorMedia( - mediaUtilsWrapper = mediaUtilsWrapper, - editorMediaListener = editorMediaListener - ) - .onPhotoPickerMediaChosen(uris) - // Assert - verify(mediaUtilsWrapper).shouldAdvertiseImageOptimization() - } - @Test fun `addExistingMediaToEditorAsync passes mediaId to addExistingMediaToPostUseCase`() = test { From c30528e2f1c9660ffc72270a3384aea084cb56ca Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 01:25:00 +0000 Subject: [PATCH 025/176] refactor: Delete unused logic for displaying promo --- .../UserFlagsProviderHelper.kt | 1 - .../wordpress/android/ui/prefs/AppPrefs.java | 11 --- .../android/util/MediaUtilsWrapper.kt | 3 - .../wordpress/android/util/WPMediaUtils.java | 69 ------------------- WordPress/src/main/res/values/strings.xml | 6 -- 5 files changed, 90 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/localcontentmigration/UserFlagsProviderHelper.kt b/WordPress/src/main/java/org/wordpress/android/localcontentmigration/UserFlagsProviderHelper.kt index fb11f809225b..839474dc2f14 100644 --- a/WordPress/src/main/java/org/wordpress/android/localcontentmigration/UserFlagsProviderHelper.kt +++ b/WordPress/src/main/java/org/wordpress/android/localcontentmigration/UserFlagsProviderHelper.kt @@ -66,7 +66,6 @@ class UserFlagsProviderHelper @Inject constructor( DeletablePrefKey.RECENTLY_PICKED_SITE_IDS.name, UndeletablePrefKey.THEME_IMAGE_SIZE_WIDTH.name, UndeletablePrefKey.BOOKMARKS_SAVED_LOCALLY_DIALOG_SHOWN.name, - UndeletablePrefKey.IMAGE_OPTIMIZE_PROMO_REQUIRED.name, UndeletablePrefKey.SWIPE_TO_NAVIGATE_NOTIFICATIONS.name, UndeletablePrefKey.SWIPE_TO_NAVIGATE_READER.name, UndeletablePrefKey.SHOULD_SHOW_STORIES_INTRO.name, diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java index bfb0ae37d01a..eb9e37a9e514 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java @@ -218,9 +218,6 @@ public enum UndeletablePrefKey implements PrefKey { BOOKMARKS_SAVED_LOCALLY_DIALOG_SHOWN, - // When we need to show the new image optimize promo dialog - IMAGE_OPTIMIZE_PROMO_REQUIRED, - // When we need to show the snackbar indicating how notifications can be navigated through SWIPE_TO_NAVIGATE_NOTIFICATIONS, @@ -603,14 +600,6 @@ public static void setBookmarksSavedLocallyDialogShown() { setBoolean(UndeletablePrefKey.BOOKMARKS_SAVED_LOCALLY_DIALOG_SHOWN, false); } - public static boolean isImageOptimizePromoRequired() { - return getBoolean(UndeletablePrefKey.IMAGE_OPTIMIZE_PROMO_REQUIRED, true); - } - - public static void setImageOptimizePromoRequired(boolean required) { - setBoolean(UndeletablePrefKey.IMAGE_OPTIMIZE_PROMO_REQUIRED, required); - } - /** * This method should only be used by specific client classes that need access to the persisted selected site * instance due to the fact that the in-memory selected site instance might not be yet available. diff --git a/WordPress/src/main/java/org/wordpress/android/util/MediaUtilsWrapper.kt b/WordPress/src/main/java/org/wordpress/android/util/MediaUtilsWrapper.kt index 3ec86333c275..b906fbd95702 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/MediaUtilsWrapper.kt +++ b/WordPress/src/main/java/org/wordpress/android/util/MediaUtilsWrapper.kt @@ -41,9 +41,6 @@ class MediaUtilsWrapper @Inject constructor(private val appContext: Context) { fun copyFileToAppStorage(imageUri: Uri, headers: Map? = null): Uri? = MediaUtils.downloadExternalMedia(appContext, imageUri, headers) - fun shouldAdvertiseImageOptimization(): Boolean = - WPMediaUtils.shouldAdvertiseImageOptimization(appContext) - fun getMimeType(uri: Uri): String? = appContext.contentResolver.getType(uri) fun getVideoThumbnail(videoPath: String, headers: Map): String? = diff --git a/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java b/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java index ef971cb663ec..758517d80138 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java @@ -104,75 +104,6 @@ public static boolean isVideoOptimizationEnabled() { return AppPrefs.isVideoOptimize(); } - /** - * Check if we should advertise image optimization feature for the current site. - *

- * The following condition need to be all true: - * 1) Image optimization is ON on the site. - * 2) Didn't already ask to keep or disable the feature. - * 3) The user has granted storage access to the app. - * This is because we don't want to ask so much things to users the first time they try to add a picture to the app. - * - * @param context The context - * @return true if we should advertise the feature, false otherwise. - */ - public static boolean shouldAdvertiseImageOptimization(final Context context) { - boolean isPromoRequired = AppPrefs.isImageOptimizePromoRequired(); - if (!isPromoRequired) { - return false; - } - - // Check we can access storage before asking for optimizing image - boolean hasStoreAccess = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R - || ContextCompat.checkSelfPermission(context, - android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; - if (!hasStoreAccess) { - return false; - } - - // Check whether image optimization is enabled for the site - return AppPrefs.isImageOptimize(); - } - - public interface OnAdvertiseImageOptimizationListener { - void done(); - } - - public static void advertiseImageOptimization(final Context context, - final OnAdvertiseImageOptimizationListener listener) { - DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String propertyValue = (which == DialogInterface.BUTTON_POSITIVE) ? "on" : "off"; - AnalyticsTracker.track(AnalyticsTracker.Stat.APP_SETTINGS_OPTIMIZE_IMAGES_POPUP_TAPPED, - Collections.singletonMap("option", propertyValue)); - - if (which == DialogInterface.BUTTON_NEGATIVE && AppPrefs.isImageOptimize()) { - AppPrefs.setImageOptimize(false); - } - - listener.done(); - } - }; - - DialogInterface.OnCancelListener onCancelListener = new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - listener.done(); - } - }; - - AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context); - builder.setTitle(R.string.image_optimization_popup_title); - builder.setMessage(R.string.image_optimization_popup_desc); - builder.setPositiveButton(R.string.leave_on, onClickListener); - builder.setNegativeButton(R.string.turn_off, onClickListener); - builder.setOnCancelListener(onCancelListener); - builder.show(); - // Do not ask again - AppPrefs.setImageOptimizePromoRequired(false); - } - /** * Given a media error returns the error message to display on the UI. * diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index f7865454b8b2..32fe5037b220 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2983,12 +2983,6 @@ Camera Microphone - - Yes, leave on - No, turn off - Keep optimizing images? - Image optimization shrinks images for faster uploading.\n\nThis option is enabled by default, but you can change it in the app settings at any time. - From b747605ff6164efacc8335171672cf346906ae99 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 01:37:45 +0000 Subject: [PATCH 026/176] refactor: Remove tracking for deleted code --- .../java/org/wordpress/android/analytics/AnalyticsTracker.java | 1 - .../org/wordpress/android/analytics/AnalyticsTrackerNosara.java | 2 -- 2 files changed, 3 deletions(-) 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 fbc2df7a413e..12ef44396989 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 @@ -896,7 +896,6 @@ public enum Stat { APP_SETTINGS_VIDEO_OPTIMIZATION_CHANGED, APP_SETTINGS_MAX_VIDEO_SIZE_CHANGED, APP_SETTINGS_VIDEO_QUALITY_CHANGED, - APP_SETTINGS_OPTIMIZE_IMAGES_POPUP_TAPPED, PRIVACY_SETTINGS_OPENED, PRIVACY_SETTINGS_REPORT_CRASHES_TOGGLED, SHARING_BUTTONS_EDIT_SHARING_BUTTONS_CHANGED, 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 1ea594ddff90..6eeaa539722c 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 @@ -2273,8 +2273,6 @@ public static String getEventNameForStat(AnalyticsTracker.Stat stat) { return "app_settings_privacy_settings_tapped"; case APP_SETTINGS_OPEN_DEVICE_SETTINGS_TAPPED: return "app_settings_open_device_settings_tapped"; - case APP_SETTINGS_OPTIMIZE_IMAGES_POPUP_TAPPED: - return "app_settings_optimize_images_popup_tapped"; case APP_SETTINGS_MAX_IMAGE_SIZE_CHANGED: return "app_settings_max_image_size_changed"; case APP_SETTINGS_IMAGE_QUALITY_CHANGED: From 773a8f9787ffe778f7d55ef1aa3a1aead38bf5db Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 11:47:32 +0000 Subject: [PATCH 027/176] refactor: Delete unused code after pop-up removal --- .../android/ui/posts/EditPostActivity.java | 3 --- .../android/ui/posts/editor/media/EditorMedia.kt | 2 -- .../android/ui/stories/StoryComposerActivity.kt | 1 - .../ui/stories/media/StoryMediaSaveUploadBridge.kt | 4 ---- .../org/wordpress/android/util/WPMediaUtils.java | 3 --- .../ui/posts/editor/media/EditorMediaTest.kt | 13 ------------- 6 files changed, 26 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index b7a9e24ab287..e072bfe9d1c4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -260,9 +260,6 @@ import static org.wordpress.android.imageeditor.preview.PreviewImageFragment.PREVIEW_IMAGE_REDUCED_SIZE_FACTOR; import static org.wordpress.android.ui.history.HistoryDetailContainerFragment.KEY_REVISION; -import kotlin.Unit; -import kotlin.jvm.functions.Function0; - public class EditPostActivity extends LocaleAwareActivity implements EditorFragmentActivity, EditorImageSettingsListener, diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt index 90ae61b8893d..23a488455fdd 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt @@ -34,7 +34,6 @@ import org.wordpress.android.ui.posts.editor.media.EditorMedia.AddMediaToPostUiS import org.wordpress.android.ui.posts.editor.media.EditorMedia.AddMediaToPostUiState.AddingSingleMedia import org.wordpress.android.ui.uploads.UploadService import org.wordpress.android.ui.utils.UiString.UiStringRes -import org.wordpress.android.util.MediaUtilsWrapper import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.util.StringUtils import org.wordpress.android.util.ToastUtils.Duration @@ -52,7 +51,6 @@ class EditorMedia @Inject constructor( private val updateMediaModelUseCase: UpdateMediaModelUseCase, private val getMediaModelUseCase: GetMediaModelUseCase, private val dispatcher: Dispatcher, - private val mediaUtilsWrapper: MediaUtilsWrapper, private val networkUtilsWrapper: NetworkUtilsWrapper, private val addLocalMediaToPostUseCase: AddLocalMediaToPostUseCase, private val addExistingMediaToPostUseCase: AddExistingMediaToPostUseCase, diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt index 793dc32ce3a5..62450f838df8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt @@ -81,7 +81,6 @@ import org.wordpress.android.util.ListUtils import org.wordpress.android.util.MediaUtils import org.wordpress.android.util.ToastUtils import org.wordpress.android.util.ToastUtils.Duration.LONG -import org.wordpress.android.util.WPMediaUtils import org.wordpress.android.util.WPPermissionUtils import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper import org.wordpress.android.util.analytics.AnalyticsUtilsWrapper diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryMediaSaveUploadBridge.kt b/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryMediaSaveUploadBridge.kt index cc84f6fad6d1..77c7c52fb953 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryMediaSaveUploadBridge.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryMediaSaveUploadBridge.kt @@ -133,10 +133,6 @@ class StoryMediaSaveUploadBridge @Inject constructor( listener?.onPostUpdatedFromUI(null) } - override fun advertiseImageOptimization(listener: () -> Unit) { - // no op - } - override fun onMediaModelsCreatedFromOptimizedUris(oldUriToMediaFiles: Map) { // in order to support Story editing capabilities, we save a serialized version of the Story slides // after their composedFrameFiles have been processed. diff --git a/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java b/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java index 758517d80138..753fbcdb14ac 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java @@ -6,10 +6,8 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.pm.PackageManager; import android.media.MediaScannerConnection; import android.net.Uri; -import android.os.Build; import android.os.Environment; import android.provider.MediaStore; import android.view.ViewConfiguration; @@ -19,7 +17,6 @@ import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.appcompat.app.AlertDialog; -import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import com.google.android.material.dialog.MaterialAlertDialogBuilder; diff --git a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt index 786662f9e9e6..7ac997e0e3a2 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt @@ -27,7 +27,6 @@ import org.wordpress.android.fluxc.store.MediaStore.FetchMediaListPayload import org.wordpress.android.ui.pages.SnackbarMessageHolder import org.wordpress.android.ui.posts.editor.media.EditorMedia.AddMediaToPostUiState import org.wordpress.android.ui.utils.UiString.UiStringRes -import org.wordpress.android.util.MediaUtilsWrapper import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper import org.wordpress.android.util.analytics.AnalyticsUtilsWrapper @@ -270,7 +269,6 @@ class EditorMediaTest : BaseUnitTest() { updateMediaModelUseCase: UpdateMediaModelUseCase = mock(), getMediaModelUseCase: GetMediaModelUseCase = createGetMediaModelUseCase(), dispatcher: Dispatcher = mock(), - mediaUtilsWrapper: MediaUtilsWrapper = createMediaUtilsWrapper(), networkUtilsWrapper: NetworkUtilsWrapper = mock(), addLocalMediaToPostUseCase: AddLocalMediaToPostUseCase = createAddLocalMediaToPostUseCase(), addExistingMediaToPostUseCase: AddExistingMediaToPostUseCase = mock(), @@ -287,7 +285,6 @@ class EditorMediaTest : BaseUnitTest() { updateMediaModelUseCase, getMediaModelUseCase, dispatcher, - mediaUtilsWrapper, networkUtilsWrapper, addLocalMediaToPostUseCase, addExistingMediaToPostUseCase, @@ -304,16 +301,6 @@ class EditorMediaTest : BaseUnitTest() { return editorMedia } - fun createMediaUtilsWrapper( - shouldAdvertiseImageOptimization: Boolean = false - ) = - mock { - on { shouldAdvertiseImageOptimization() } - .thenReturn(shouldAdvertiseImageOptimization) - on { isVideo(VIDEO_URI.toString()) }.thenReturn(true) - on { isVideo(IMAGE_URI.toString()) }.thenReturn(false) - } - fun createAddLocalMediaToPostUseCase(resultForAddNewMediaToEditorAsync: Boolean = true) = mock { onBlocking { From 371c7db62e0bfc3141176630632d4377a611a70c Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 11:50:04 +0000 Subject: [PATCH 028/176] refactor: Delete redundant test --- .../stories/usecase/StoryEditorMediaTest.kt | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt index a42a90bb2d11..607b1f36c518 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt @@ -85,25 +85,6 @@ class StoryEditorMediaTest : BaseUnitTest() { verify(observer, never()).onChanged(captor.capture()) } - @Test - fun `onPhotoPickerMediaChosen invokes shouldAdvertiseImageOptimization when at least 1 image file`() = - test { - // Arrange - val uris = listOf(VIDEO_URI, VIDEO_URI, IMAGE_URI, VIDEO_URI) - val editorMediaListener = mock() - - val mediaUtilsWrapper = createMediaUtilsWrapper() - - // Act - createStoryEditorMedia( - mediaUtilsWrapper = mediaUtilsWrapper, - editorMediaListener = editorMediaListener - ) - .onPhotoPickerMediaChosen(uris) - // Assert - verify(mediaUtilsWrapper).shouldAdvertiseImageOptimization() - } - private companion object Fixtures { private val VIDEO_URI = mock() private val IMAGE_URI = mock() @@ -125,12 +106,6 @@ class StoryEditorMediaTest : BaseUnitTest() { return editorMedia } - fun createMediaUtilsWrapper() = - mock { - on { isVideo(VIDEO_URI.toString()) }.thenReturn(true) - on { isVideo(IMAGE_URI.toString()) }.thenReturn(false) - } - fun createAddLocalMediaToPostUseCase(resultForAddNewMediaToEditorAsync: Boolean = true) = mock { onBlocking { From f29418c2727e2f3a6c6f17c202c63f25bf1e6a80 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 11:58:24 +0000 Subject: [PATCH 029/176] refactor: Remove unused imports and vars --- .../wordpress/android/ui/stories/media/StoryEditorMedia.kt | 2 -- .../main/java/org/wordpress/android/util/WPMediaUtils.java | 1 - .../android/ui/posts/editor/media/EditorMediaTest.kt | 2 -- .../android/ui/stories/usecase/StoryEditorMediaTest.kt | 6 ------ 4 files changed, 11 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt b/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt index 78f11123c791..74df66b04211 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt @@ -22,14 +22,12 @@ import org.wordpress.android.ui.stories.media.StoryEditorMedia.AddMediaToStoryPo import org.wordpress.android.ui.stories.media.StoryEditorMedia.AddMediaToStoryPostUiState.AddingMultipleMediaToStory import org.wordpress.android.ui.stories.media.StoryEditorMedia.AddMediaToStoryPostUiState.AddingSingleMediaToStory import org.wordpress.android.ui.utils.UiString.UiStringRes -import org.wordpress.android.util.MediaUtilsWrapper import org.wordpress.android.viewmodel.Event import javax.inject.Inject import javax.inject.Named import kotlin.coroutines.CoroutineContext class StoryEditorMedia @Inject constructor( - private val mediaUtilsWrapper: MediaUtilsWrapper, private val addLocalMediaToPostUseCase: AddLocalMediaToPostUseCase, private val addExistingMediaToPostUseCase: AddExistingMediaToPostUseCase, @Named(UI_THREAD) private val mainDispatcher: CoroutineDispatcher diff --git a/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java b/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java index 753fbcdb14ac..f8eb64f1f5d7 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/util/WPMediaUtils.java @@ -43,7 +43,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; public class WPMediaUtils { diff --git a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt index 7ac997e0e3a2..f903ad16a950 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt @@ -260,8 +260,6 @@ class EditorMediaTest : BaseUnitTest() { } private companion object Fixtures { - private val VIDEO_URI = mock() - private val IMAGE_URI = mock() private const val MEDIA_MODEL_REMOTE_ID = 123L private const val MEDIA_MODEL_LOCAL_ID = 1 diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt index 607b1f36c518..54511c11bd53 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt @@ -1,6 +1,5 @@ package org.wordpress.android.ui.stories.usecase -import android.net.Uri import androidx.lifecycle.Observer import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -86,18 +85,13 @@ class StoryEditorMediaTest : BaseUnitTest() { } private companion object Fixtures { - private val VIDEO_URI = mock() - private val IMAGE_URI = mock() - fun createStoryEditorMedia( - mediaUtilsWrapper: MediaUtilsWrapper = createMediaUtilsWrapper(), addLocalMediaToPostUseCase: AddLocalMediaToPostUseCase = createAddLocalMediaToPostUseCase(), addExistingMediaToPostUseCase: AddExistingMediaToPostUseCase = mock(), siteModel: SiteModel = mock(), editorMediaListener: EditorMediaListener = mock() ): StoryEditorMedia { val editorMedia = StoryEditorMedia( - mediaUtilsWrapper, addLocalMediaToPostUseCase, addExistingMediaToPostUseCase, UnconfinedTestDispatcher() From ccef9166e34ab0698b1cfea7c31af28da0fd4da0 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 12:09:06 +0000 Subject: [PATCH 030/176] refactor: Remove unused imports --- .../wordpress/android/ui/posts/editor/media/EditorMediaTest.kt | 1 - .../wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt index f903ad16a950..ac43eaf276c9 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt @@ -1,6 +1,5 @@ package org.wordpress.android.ui.posts.editor.media -import android.net.Uri import androidx.lifecycle.Observer import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt index 54511c11bd53..90176998e575 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/stories/usecase/StoryEditorMediaTest.kt @@ -22,7 +22,6 @@ import org.wordpress.android.ui.posts.editor.media.EditorMediaListener import org.wordpress.android.ui.stories.media.StoryEditorMedia import org.wordpress.android.ui.stories.media.StoryEditorMedia.AddMediaToStoryPostUiState import org.wordpress.android.ui.utils.UiString.UiStringRes -import org.wordpress.android.util.MediaUtilsWrapper import org.wordpress.android.viewmodel.Event @ExperimentalCoroutinesApi From a62ee3c23848ec5fe84e825ceb1fb496886526b3 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 13:34:17 +0000 Subject: [PATCH 031/176] refactor: Tidy up functions with little logic --- .../java/org/wordpress/android/ui/posts/EditPostActivity.java | 2 +- .../wordpress/android/ui/posts/editor/media/EditorMedia.kt | 4 ---- .../org/wordpress/android/ui/stories/StoryComposerActivity.kt | 4 ++-- .../wordpress/android/ui/stories/media/StoryEditorMedia.kt | 4 ---- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index e072bfe9d1c4..50b27a4a7d78 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -1306,7 +1306,7 @@ public void onPhotoPickerHidden() { @Override public void onPhotoPickerMediaChosen(@NonNull final List uriList) { mEditorPhotoPicker.hidePhotoPicker(); - mEditorMedia.onPhotoPickerMediaChosen(uriList); + mEditorMedia.addNewMediaItemsToEditorAsync(uriList, false); } /* diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt index 23a488455fdd..658ad80e7bac 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt @@ -129,10 +129,6 @@ class EditorMedia @Inject constructor( ) } } - - fun onPhotoPickerMediaChosen(uriList: List) { - addNewMediaItemsToEditorAsync(uriList, false) - } // endregion // region Add existing media to a post diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt index 62450f838df8..50055bc6f87a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stories/StoryComposerActivity.kt @@ -345,7 +345,7 @@ class StoryComposerActivity : ComposeLoopFrameActivity(), it.hasExtra(MediaPickerConstants.EXTRA_MEDIA_URIS) -> { data.getStringArrayExtra(MediaPickerConstants.EXTRA_MEDIA_URIS)?.let { val uriList: List = convertStringArrayIntoUrisList(it) - storyEditorMedia.onPhotoPickerMediaChosen(uriList) + storyEditorMedia.addNewMediaItemsToEditorAsync(uriList, false) } } it.hasExtra(MediaBrowserActivity.RESULT_IDS) -> { @@ -421,7 +421,7 @@ class StoryComposerActivity : ComposeLoopFrameActivity(), val uriList: List = convertStringArrayIntoUrisList(it) if (uriList.isNotEmpty()) { - storyEditorMedia.onPhotoPickerMediaChosen(uriList) + storyEditorMedia.addNewMediaItemsToEditorAsync(uriList, false) } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt b/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt index 74df66b04211..1a91710c5bc6 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stories/media/StoryEditorMedia.kt @@ -74,10 +74,6 @@ class StoryEditorMedia @Inject constructor( _uiState.value = AddingMediaToStoryIdle } } - - fun onPhotoPickerMediaChosen(uriList: List) { - addNewMediaItemsToEditorAsync(uriList, false) - } // endregion fun addExistingMediaToEditorAsync(source: AddExistingMediaSource, mediaIdList: List) { From 25de3fe9e250fd810930a6953f37b9557c94a78f Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 01:21:38 +0000 Subject: [PATCH 032/176] feat: Remove pop-up for in-editor photo selection From 43f830257d1329a964223ade1546abd555402054 Mon Sep 17 00:00:00 2001 From: Siobhan Date: Thu, 25 Jan 2024 01:22:30 +0000 Subject: [PATCH 033/176] feat: Remove pop-up for Story posts From 5fd198164e13a9db78962a2584f7cac93d68dfea Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Thu, 25 Jan 2024 18:54:15 +0200 Subject: [PATCH 034/176] 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 544a483ca1aa9ac6ad62363c85dccc785d23c801 Mon Sep 17 00:00:00 2001 From: Andy Valdez Date: Thu, 25 Jan 2024 12:49:17 -0500 Subject: [PATCH 035/176] [Lib] Update AztecEditor lib from 1.9 to 2.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5cb7f225ec83..e55b41b25634 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ ext { automatticStoriesVersion = '2.4.0' automatticTracksVersion = '3.3.0' gutenbergMobileVersion = 'v1.111.1' - wordPressAztecVersion = 'v1.9.0' + wordPressAztecVersion = 'v2.0' wordPressFluxCVersion = '2.61.0' wordPressLoginVersion = '1.10.0' wordPressPersistentEditTextVersion = '1.0.2' From 94cfc25af94f85812770b2a704f8d0540401fe62 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Thu, 25 Jan 2024 17:03:28 -0500 Subject: [PATCH 036/176] Add utils class for Site Monitor feature --- .../ui/sitemonitor/SiteMonitorUtils.kt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt 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 new file mode 100644 index 000000000000..891931689048 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt @@ -0,0 +1,31 @@ +package org.wordpress.android.ui.sitemonitor + +import org.wordpress.android.WordPress +import org.wordpress.android.analytics.AnalyticsTracker +import org.wordpress.android.ui.WPWebViewActivity +import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper +import javax.inject.Inject + +class SiteMonitorUtils @Inject constructor( + private val analyticsTrackerWrapper: AnalyticsTrackerWrapper +) { + fun getUserAgent() = WordPress.getUserAgent() + + fun getAuthenticationPostData(authenticationUrl: String, + urlToLoad: String, + username: String, + password: String, + token: String): String = + WPWebViewActivity.getAuthenticationPostData(authenticationUrl, urlToLoad, username, password, token) + + + fun trackActivityLaunched() { + analyticsTrackerWrapper.track(AnalyticsTracker.Stat.SITE_MONITORING_SCREEN_SHOWN) + } + + fun sanitizeSiteUrl(url: String?) = url?.replace(Regex(HTTP_PATTERN), "") ?: "" + + companion object { + const val HTTP_PATTERN = "(https?://)" + } +} From de18b624c763e04ba334083d9559f625fd301d1c Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Thu, 25 Jan 2024 17:04:23 -0500 Subject: [PATCH 037/176] Add the site monitor uiState and Model classes --- .../ui/sitemonitor/SiteMonitorUiState.kt | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUiState.kt 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 new file mode 100644 index 000000000000..42434621a8e3 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorUiState.kt @@ -0,0 +1,67 @@ +package org.wordpress.android.ui.sitemonitor + +import org.wordpress.android.R +import org.wordpress.android.ui.utils.UiString + +sealed class SiteMonitorUiState { + object Preparing : SiteMonitorUiState() + + data class Prepared( + val model: SiteMonitorModel + ) : SiteMonitorUiState() + + object Loaded : SiteMonitorUiState() + + open class Error( + val title: UiString, + val description: UiString, + val button: ErrorButton? = null + ) : SiteMonitorUiState() { + data class ErrorButton( + val text: UiString, + val click: () -> Unit + ) + } + + data class NoNetworkError(val buttonClick: () -> Unit): Error( + title = UiString.UiStringRes(R.string.campaign_detail_no_network_error_title), + description = UiString.UiStringRes(R.string.campaign_detail_error_description), + button = ErrorButton( + text = UiString.UiStringRes(R.string.campaign_detail_error_button_text), + click = buttonClick + ) + ) + + data class GenericError(val buttonClick: () -> Unit): Error( + title = UiString.UiStringRes(R.string.campaign_detail_error_title), + description = UiString.UiStringRes(R.string.campaign_detail_error_description), + button = ErrorButton( + text = UiString.UiStringRes(R.string.campaign_detail_error_button_text), + click = buttonClick + ) + ) +} + +data class SiteMonitorModel( + val enableJavascript: Boolean = true, + val enableDomStorage: Boolean = true, + val enableChromeClient: Boolean = true, + val userAgent: String = "", + val urls: List = emptyList() +) { + fun getUrlByType(type: SiteMonitorUrl.SiteMonitorType): SiteMonitorUrl? { + return urls.find { it.type == type } + } +} + +data class SiteMonitorUrl( + val type: SiteMonitorType, + val url: String, + val addressToLoad: String +) { + enum class SiteMonitorType { + METRICS, + PHP_LOGS, + WEB_SERVER_LOGS + } +} From 604a1090069f37796d85149139221becfa958330 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Thu, 25 Jan 2024 17:05:06 -0500 Subject: [PATCH 038/176] Add the site monitor mapper helper to map to uiState --- .../ui/sitemonitor/SiteMonitorMapper.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapper.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapper.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapper.kt new file mode 100644 index 000000000000..ac21f85e5ba2 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapper.kt @@ -0,0 +1,21 @@ +package org.wordpress.android.ui.sitemonitor + +import javax.inject.Inject + +class SiteMonitorMapper @Inject constructor( + private val siteMonitorUtils: SiteMonitorUtils +) { + fun toPrepared(urls: List) = SiteMonitorUiState.Prepared( + model = SiteMonitorModel( + enableJavascript = true, + enableDomStorage = true, + userAgent = siteMonitorUtils.getUserAgent(), + enableChromeClient = true, + urls = urls + ) + ) + + fun toNoNetworkError(buttonClick: () -> Unit) = SiteMonitorUiState.NoNetworkError(buttonClick = buttonClick) + + fun toGenericError(buttonClick: () -> Unit) = SiteMonitorUiState.GenericError(buttonClick = buttonClick) +} From dea69ec82cc3d4f60d1cbefb3e66875345e93438 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Thu, 25 Jan 2024 17:10:06 -0500 Subject: [PATCH 039/176] Add the site monitor webview client --- .../ui/sitemonitor/SiteMonitorWebViewClient.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClient.kt 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 new file mode 100644 index 000000000000..fd13c1309bcb --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorWebViewClient.kt @@ -0,0 +1,17 @@ +package org.wordpress.android.ui.sitemonitor + +import android.webkit.WebResourceRequest +import android.webkit.WebView +import org.wordpress.android.util.ErrorManagedWebViewClient + +class SiteMonitorWebViewClient( + listener: SiteMonitorWebViewClientListener +) : ErrorManagedWebViewClient(listener) { + interface SiteMonitorWebViewClientListener : ErrorManagedWebViewClientListener { + fun onRedirectToExternalBrowser(url: String) + } + + override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest) : Boolean { + return false + } +} From aad1477192b4f03f5a5f3ee8d7701e23675f46c9 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Thu, 25 Jan 2024 17:10:50 -0500 Subject: [PATCH 040/176] Add the basics for building the uiState for Site Monitoring --- .../sitemonitor/SiteMonitorParentViewModel.kt | 127 +++++++++++++++++- 1 file changed, 121 insertions(+), 6 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 00c337746eed..60afa9910ff4 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,11 +1,16 @@ 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 org.wordpress.android.analytics.AnalyticsTracker +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow 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.analytics.AnalyticsTrackerWrapper +import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.viewmodel.ScopedViewModel import javax.inject.Inject import javax.inject.Named @@ -13,16 +18,126 @@ import javax.inject.Named @HiltViewModel class SiteMonitorParentViewModel @Inject constructor( @param:Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, - private val analyticsTrackerWrapper: AnalyticsTrackerWrapper + 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 site: SiteModel + private val metricUrlTemplate = "https://wordpress.com/site-monitoring/{blog}" + private val phpLogsUrlTemplate = "https://wordpress.com/site-monitoring/{blog}/php" + private val webServerLogsUrlTemplate = "https://wordpress.com/site-monitoring/{blog}/web" + + private val _uiState = MutableStateFlow(SiteMonitorUiState.Preparing) + val uiState = _uiState as StateFlow + fun start(site: SiteModel) { this.site = site - trackActivityLaunched() + siteMonitorUtils.trackActivityLaunched() + + loadViews() + } + + private fun loadViews() { + Log.i(javaClass.simpleName, "***=> loadViews") + postUiState(SiteMonitorUiState.Preparing) + + if (!checkForInternetConnectivityAndPostErrorIfNeeded()) return + + if (!validateAndPostErrorIfNeeded()) return + + assembleAndShowSiteMonitor() + } + + private fun assembleAndShowSiteMonitor() { + val sanitizedUrl = siteMonitorUtils.sanitizeSiteUrl(site.url) + + val siteMonitorUrls = mutableListOf().apply { + add( + createSiteMonitorUrl( + metricUrlTemplate.replace("{blog}", sanitizedUrl), SiteMonitorUrl.SiteMonitorType.METRICS) + ) + add( + createSiteMonitorUrl( + phpLogsUrlTemplate.replace("{blog}", sanitizedUrl), + SiteMonitorUrl.SiteMonitorType.PHP_LOGS + ) + ) + add( + createSiteMonitorUrl( + webServerLogsUrlTemplate.replace("{blog}", sanitizedUrl), + SiteMonitorUrl.SiteMonitorType.WEB_SERVER_LOGS + ) + ) + } + postUiState(mapper.toPrepared(siteMonitorUrls)) + } + + private fun createSiteMonitorUrl(url: String, type: SiteMonitorUrl.SiteMonitorType): SiteMonitorUrl { + return SiteMonitorUrl( + type = type, + url = url, + addressToLoad = prepareAddressToLoad(url) + ) + } + private fun prepareAddressToLoad(url: String): String { + val username = accountStore.account.userName + val accessToken = accountStore.accessToken + + var addressToLoad = url + + // Custom domains are not properly authenticated due to a server side(?) issue, so this gets around that + if (!addressToLoad.contains(WPCOM_DOMAIN)) { + val wpComSites: List = siteStore.wPComSites + for (siteModel in wpComSites) { + // Only replace the url if we know the unmapped url and if it's a custom domain + if (!TextUtils.isEmpty(siteModel.unmappedUrl) + && !siteModel.url.contains(WPCOM_DOMAIN) + ) { + addressToLoad = addressToLoad.replace(siteModel.url, siteModel.unmappedUrl) + } + } + } + return siteMonitorUtils.getAuthenticationPostData( + WPCOM_LOGIN_URL, + addressToLoad, + username, + "", + accessToken?:"" + ) + } + private fun checkForInternetConnectivityAndPostErrorIfNeeded(): Boolean { + if (networkUtilsWrapper.isNetworkAvailable()) return true + postUiState(mapper.toNoNetworkError(this@SiteMonitorParentViewModel::loadViews)) + return false + } + + private fun validateAndPostErrorIfNeeded(): Boolean { + if (accountStore.account.userName.isNullOrEmpty() || accountStore.accessToken.isNullOrEmpty()) { + postUiState(mapper.toGenericError(this@SiteMonitorParentViewModel::loadViews)) + return false + } + return true + } + + private fun postUiState(uiState: SiteMonitorUiState) { + launch { + _uiState.value = uiState + } + } + + fun onUrlLoaded() { + postUiState(SiteMonitorUiState.Loaded) + } + + fun onWebViewError() { + postUiState(mapper.toGenericError(this@SiteMonitorParentViewModel::loadViews)) } - private fun trackActivityLaunched() { - analyticsTrackerWrapper.track(AnalyticsTracker.Stat.SITE_MONITORING_SCREEN_SHOWN) + companion object { + const val WPCOM_LOGIN_URL = "https://wordpress.com/wp-login.php" + const val WPCOM_DOMAIN = ".wordpress.com" } } From ffc8b5998ce3e34ccd8e4bd80c820f751a7499eb Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Thu, 25 Jan 2024 17:11:55 -0500 Subject: [PATCH 041/176] Refactor to support showing web views in each tab for metrics, php logs, and web server logs --- .../sitemonitor/SiteMonitorParentActivity.kt | 129 ++++++++++++++++-- 1 file changed, 118 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 96087a86b48e..6e7b3df2048e 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,35 +2,63 @@ package org.wordpress.android.ui.sitemonitor import android.annotation.SuppressLint import android.os.Bundle +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.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.Tab import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf 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.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView 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.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.ui.main.jetpack.migration.compose.state.LoadingState +import org.wordpress.android.ui.sitemonitor.SiteMonitorWebViewClient.SiteMonitorWebViewClientListener import org.wordpress.android.util.extensions.getSerializableExtraCompat @AndroidEntryPoint -class SiteMonitorParentActivity: AppCompatActivity() { - val viewModel:SiteMonitorParentViewModel by viewModels() +class SiteMonitorParentActivity: AppCompatActivity(), SiteMonitorWebViewClientListener { + override fun onRedirectToExternalBrowser(url: String) { + // todo: not sure if this is needed + } + + override fun onWebViewPageLoaded() = viewModel.onUrlLoaded() + + override fun onWebViewReceivedError() = viewModel.onWebViewError() + +val viewModel:SiteMonitorParentViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -48,7 +76,9 @@ class SiteMonitorParentActivity: AppCompatActivity() { @Composable @SuppressLint("UnusedMaterialScaffoldPaddingParameter") - fun SiteMonitorScreen(modifier: Modifier = Modifier) { + fun SiteMonitorScreen(modifier: Modifier = Modifier, + viewModel: SiteMonitorParentViewModel = androidx.lifecycle.viewmodel.compose.viewModel()) { + val uiState by viewModel.uiState.collectAsState() Scaffold( topBar = { MainTopAppBar( @@ -58,15 +88,15 @@ class SiteMonitorParentActivity: AppCompatActivity() { ) }, content = { - TabScreen(modifier = modifier) + TabScreen(modifier = modifier, uiState) } ) } @Composable @SuppressLint("UnusedMaterialScaffoldPaddingParameter") - fun TabScreen(modifier: Modifier = Modifier) { - var tabIndex by remember { mutableStateOf(0) } + fun TabScreen(modifier: Modifier = Modifier, uiState: SiteMonitorUiState) { + var tabIndex by remember { mutableIntStateOf(0) } val tabs = listOf( R.string.site_monitoring_tab_title_metrics, @@ -88,15 +118,92 @@ class SiteMonitorParentActivity: AppCompatActivity() { } } when (tabIndex) { - 0 -> SiteMonitoringWebView() - 1 -> SiteMonitoringWebView() - 2 -> SiteMonitoringWebView() + 0 -> SiteMonitoringWebViewForTab(uiState, SiteMonitorUrl.SiteMonitorType.METRICS) + 1 -> SiteMonitoringWebViewForTab(uiState, SiteMonitorUrl.SiteMonitorType.PHP_LOGS) + 2 -> SiteMonitoringWebViewForTab(uiState, SiteMonitorUrl.SiteMonitorType.WEB_SERVER_LOGS) } } } @Composable - fun SiteMonitoringWebView(){ - Text(text = "SiteMonitoringWebView") + fun SiteMonitoringWebViewForTab(uiState: SiteMonitorUiState, tab: SiteMonitorUrl.SiteMonitorType) { + when (uiState) { + is SiteMonitorUiState.Preparing -> LoadingState() + is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitoringWebView(uiState, tab) + is SiteMonitorUiState.Error -> SiteMonitorError(uiState) + } + } + + @Composable + fun SiteMonitorError(error: SiteMonitorUiState.Error) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier + .padding(20.dp) + .fillMaxWidth() + .fillMaxHeight(), + ) { + Text( + text = uiStringText(uiString = error.title), + style = MaterialTheme.typography.h5, + textAlign = TextAlign.Center + ) + Text( + text = uiStringText(uiString = error.description), + style = 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)) + } + } + } + } + @SuppressLint("SetJavaScriptEnabled") + @Composable + fun SiteMonitoringWebView(uiState: SiteMonitorUiState, tab: SiteMonitorUrl.SiteMonitorType) { + var webView: WebView? by remember { mutableStateOf(null) } + + if (uiState is SiteMonitorUiState.Prepared) { + val model = uiState.model + 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) + model.getUrlByType(tab)?.addressToLoad?.let { + postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, it.toByteArray()) + } + } + } + } + + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + if (uiState is SiteMonitorUiState.Prepared) { + LoadingState() + } else { + webView?.let { theWebView -> + AndroidView( + factory = { theWebView }, + modifier = Modifier.fillMaxSize() + ) + } + } + } } } From 7dd8cac9b175f3cd3461818485fb7071c8191cff Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Thu, 25 Jan 2024 17:12:32 -0500 Subject: [PATCH 042/176] Refactor: remove log lines --- .../android/ui/sitemonitor/SiteMonitorParentViewModel.kt | 2 -- 1 file changed, 2 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 60afa9910ff4..38e2b43fc1fd 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,7 +1,6 @@ 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 @@ -41,7 +40,6 @@ class SiteMonitorParentViewModel @Inject constructor( } private fun loadViews() { - Log.i(javaClass.simpleName, "***=> loadViews") postUiState(SiteMonitorUiState.Preparing) if (!checkForInternetConnectivityAndPostErrorIfNeeded()) return From cdc2253dd9ab0ea3ccf6b88ac5e2fa3d8f59ad73 Mon Sep 17 00:00:00 2001 From: Aditi Bhatia Date: Thu, 25 Jan 2024 15:28:31 -0800 Subject: [PATCH 043/176] Typo --- .../wordpress/android/designsystem/DesignSystemDataSource.kt | 2 +- WordPress/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt index d7bf384d4b94..dba23937a37e 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemDataSource.kt @@ -10,7 +10,7 @@ object DesignSystemDataSource { val foundationScreenButtonOptions = listOf( R.string.design_system_foundation_colors, R.string.design_system_foundation_fonts, - R.string.design_system_foundation_Lengths + R.string.design_system_foundation_lengths ) val componentsScreenButtonOptions = listOf( R.string.design_system_components_dsbutton diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 0b4b73c32a2b..71424da6647d 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -960,7 +960,7 @@ Components Colors Fonts - Lengths + Lengths DSButton From 94e3984955b27fcf5418d65f99bc3d3ae23143b6 Mon Sep 17 00:00:00 2001 From: Aditi Bhatia Date: Thu, 25 Jan 2024 15:31:22 -0800 Subject: [PATCH 044/176] Update to use LazyColumn --- .../DesignSystemComponentsScreen.kt | 28 +++++++---------- .../DesignSystemFoundationScreen.kt | 31 +++++++------------ .../designsystem/DesignSystemStartScreen.kt | 28 +++++++---------- 3 files changed, 36 insertions(+), 51 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt index ca8cb78e15f9..3430d8d69f3d 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Row 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.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -16,25 +17,20 @@ import org.wordpress.android.R @Composable fun DesignSystemComponentsScreen( modifier: Modifier = Modifier -){ - Column( +) { + LazyColumn ( modifier = modifier, - verticalArrangement = Arrangement.SpaceBetween + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy( + dimensionResource(id = R.dimen.reader_follow_sheet_button_margin_top) + ) ) { - Row(modifier = Modifier.weight(1f, false)) { - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy( - dimensionResource(id = R.dimen.button_container_shadow_height) + item { + DesignSystemDataSource.componentsScreenButtonOptions.forEach { item -> + SelectOptionButton( + labelResourceId = item, + onClick = {} ) - ) { - DesignSystemDataSource.componentsScreenButtonOptions.forEach { item -> - SelectOptionButton( - labelResourceId = item, - onClick = {} - ) - } } } } diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemFoundationScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemFoundationScreen.kt index a744f632ef6a..6564580c0606 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemFoundationScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemFoundationScreen.kt @@ -1,11 +1,9 @@ package org.wordpress.android.designsystem import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row 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.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -16,25 +14,20 @@ import org.wordpress.android.R @Composable fun DesignSystemFoundationScreen( modifier: Modifier = Modifier -){ - Column( +) { + LazyColumn ( modifier = modifier, - verticalArrangement = Arrangement.SpaceBetween + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy( + dimensionResource(id = R.dimen.reader_follow_sheet_button_margin_top) + ) ) { - Row(modifier = Modifier.weight(1f, false)) { - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy( - dimensionResource(id = R.dimen.button_container_shadow_height) + item { + DesignSystemDataSource.foundationScreenButtonOptions.forEach { item -> + SelectOptionButton( + labelResourceId = item, + onClick = {} ) - ) { - DesignSystemDataSource.foundationScreenButtonOptions.forEach { item -> - SelectOptionButton( - labelResourceId = item, - onClick = {} - ) - } } } } diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt index ff2a5ea23083..33633123cb65 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Row 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.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -17,25 +18,20 @@ import org.wordpress.android.R fun DesignSystemStartScreen( onNextButtonClicked: (String) -> Unit, modifier: Modifier = Modifier -){ - Column( +) { + LazyColumn ( modifier = modifier, - verticalArrangement = Arrangement.SpaceBetween + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy( + dimensionResource(id = R.dimen.reader_follow_sheet_button_margin_top) + ) ) { - Row(modifier = Modifier.weight(1f, false)) { - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy( - dimensionResource(id = R.dimen.button_container_shadow_height) + item { + DesignSystemDataSource.startScreenButtonOptions.forEach { item -> + SelectOptionButton( + labelResourceId = item.first, + onClick = { onNextButtonClicked(item.second) } ) - ) { - DesignSystemDataSource.startScreenButtonOptions.forEach { item -> - SelectOptionButton( - labelResourceId = item.first, - onClick = { onNextButtonClicked(item.second) } - ) - } } } } From 08f82a72bb6753d70d3379468e05c4d1f3d9e9ae Mon Sep 17 00:00:00 2001 From: Aditi Bhatia Date: Thu, 25 Jan 2024 16:53:23 -0800 Subject: [PATCH 045/176] Cleanup --- .../android/designsystem/DesignSystemComponentsScreen.kt | 3 --- .../wordpress/android/designsystem/DesignSystemStartScreen.kt | 3 --- 2 files changed, 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt index 3430d8d69f3d..9ad12beb4467 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemComponentsScreen.kt @@ -1,10 +1,7 @@ package org.wordpress.android.designsystem import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row 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.runtime.Composable diff --git a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt index 33633123cb65..e082a6fb5f64 100644 --- a/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/designsystem/DesignSystemStartScreen.kt @@ -1,10 +1,7 @@ package org.wordpress.android.designsystem import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row 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.runtime.Composable From ce3cda92cf2aefdc24657c3c71ed636f21e34f0e Mon Sep 17 00:00:00 2001 From: Jarvis Lin Date: Fri, 26 Jan 2024 15:25:39 +0800 Subject: [PATCH 046/176] 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 047/176] 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 c1306526a06c2d8b9736bd2eba81ccc8c96dd8e3 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Fri, 26 Jan 2024 13:15:33 +0200 Subject: [PATCH 048/176] Fix tests in SiteListItemBuilderTest --- .../items/listitem/SiteListItemBuilderTest.kt | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt index a8f6e54b341c..f0fe7a9a46a4 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt @@ -422,9 +422,11 @@ class SiteListItemBuilderTest { /* SITE MONITORING */ @Test - fun `give jetpack app, when is atomic and admin and FF is enabled, then site monitoring item is built`() { + fun `give site monitoring FF is true, when is atomic and admin, then site monitoring item is built`() { setupSiteMonitoringItems( - isSiteMonitoringFeatureFlagEnabled = true + isSiteMonitoringFeatureFlagEnabled = true, + isAtomic = true, + isAdmin = true ) val item = siteListItemBuilder.buildSiteMonitoringItemIfAvailable(siteModel, SITE_ITEM_ACTION) @@ -433,18 +435,11 @@ class SiteListItemBuilderTest { } @Test - fun `give jetpack app, when is atomic and admin and FF is disabled, then site monitoring item is not built`() { - setupSiteMonitoringItems() - - val item = siteListItemBuilder.buildSiteMonitoringItemIfAvailable(siteModel, SITE_ITEM_ACTION) - - assertThat(item).isNull() - } - - @Test - fun `give jetpack app, when is not atomic, then site monitoring item is not built`() { + fun `give site monitoring FF is true, when is atomic and NOT admin, then site monitoring item is not built`() { setupSiteMonitoringItems( - isAtomic = false + isSiteMonitoringFeatureFlagEnabled = true, + isAtomic = true, + isAdmin = false ) val item = siteListItemBuilder.buildSiteMonitoringItemIfAvailable(siteModel, SITE_ITEM_ACTION) @@ -453,9 +448,10 @@ class SiteListItemBuilderTest { } @Test - fun `give jetpack app, when is not admin, then site monitoring item is not built`() { + fun `give site monitoring FF is true, when is admin and NOT atomic, then site monitoring item is not built`() { setupSiteMonitoringItems( - isAdmin = false + isSiteMonitoringFeatureFlagEnabled = true, + isAdmin = true ) val item = siteListItemBuilder.buildSiteMonitoringItemIfAvailable(siteModel, SITE_ITEM_ACTION) @@ -464,9 +460,10 @@ class SiteListItemBuilderTest { } @Test - fun `give not jetpack app, when site monitoring item requested, then site monitoring item is not built`() { + fun `give site monitoring FF is false, when is admin and atomic, then site monitoring item is not built`() { setupSiteMonitoringItems( - isJetpackApp = false + isAtomic = true, + isAdmin = true ) val item = siteListItemBuilder.buildSiteMonitoringItemIfAvailable(siteModel, SITE_ITEM_ACTION) @@ -475,12 +472,10 @@ class SiteListItemBuilderTest { } private fun setupSiteMonitoringItems( - isJetpackApp: Boolean = true, isSiteMonitoringFeatureFlagEnabled: Boolean = false, - isAtomic: Boolean = true, - isAdmin: Boolean = true + isAtomic: Boolean = false, + isAdmin: Boolean = false ) { - whenever(buildConfigWrapper.isJetpackApp).thenReturn(isJetpackApp) whenever(siteMonitoringFeatureConfig.isEnabled()).thenReturn(isSiteMonitoringFeatureFlagEnabled) whenever(siteModel.isAdmin).thenReturn(isAdmin) whenever(siteModel.isWPComAtomic).thenReturn(isAtomic) From a4716de0a1cb3f7aa65b171ccdf539f8b975496e Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Fri, 26 Jan 2024 13:30:00 +0100 Subject: [PATCH 049/176] Update Gutenberg Mobile reference --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5cb7f225ec83..8ccb2fce17eb 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 = '6580-9fe963032e189dc6bb8dbbb4b9238d34759c0ed8' wordPressAztecVersion = 'v1.9.0' wordPressFluxCVersion = '2.61.0' wordPressLoginVersion = '1.10.0' From 343c35291309180fbc9e73aab30410d558f90733 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Fri, 26 Jan 2024 15:47:09 +0200 Subject: [PATCH 050/176] Remove jetpack app check from SiteMonitoringFeatureConfig --- .../items/listitem/SiteListItemBuilder.kt | 7 ++++- .../config/SiteMonitoringFeatureConfig.kt | 7 ++--- .../items/listitem/SiteListItemBuilderTest.kt | 28 ++++++++++++++++--- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilder.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilder.kt index 196e1f8aee2e..7bc0263630ad 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilder.kt @@ -247,8 +247,13 @@ class SiteListItemBuilder @Inject constructor( } else null } + @Suppress("ComplexCondition") fun buildSiteMonitoringItemIfAvailable(site: SiteModel, onClick: (ListItemAction) -> Unit): MySiteCardAndItem? { - return if (siteMonitoringFeatureConfig.isEnabled() && site.isWPComAtomic && site.isAdmin) { + return if (buildConfigWrapper.isJetpackApp + && site.isWPComAtomic + && site.isAdmin + && siteMonitoringFeatureConfig.isEnabled() + ) { ListItem( R.drawable.gb_ic_tool, UiStringRes(R.string.site_monitoring), diff --git a/WordPress/src/main/java/org/wordpress/android/util/config/SiteMonitoringFeatureConfig.kt b/WordPress/src/main/java/org/wordpress/android/util/config/SiteMonitoringFeatureConfig.kt index 6a2cc90c1fdb..3102f90ad70a 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/config/SiteMonitoringFeatureConfig.kt +++ b/WordPress/src/main/java/org/wordpress/android/util/config/SiteMonitoringFeatureConfig.kt @@ -13,8 +13,5 @@ class SiteMonitoringFeatureConfig @Inject constructor( appConfig, BuildConfig.ENABLE_SITE_MONITORING, SITE_MONITORING_FEATURE_REMOTE_FIELD -) { - override fun isEnabled(): Boolean { - return super.isEnabled() && BuildConfig.IS_JETPACK_APP - } -} +) + diff --git a/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt index f0fe7a9a46a4..d1bfd2e7eac7 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/listitem/SiteListItemBuilderTest.kt @@ -422,8 +422,9 @@ class SiteListItemBuilderTest { /* SITE MONITORING */ @Test - fun `give site monitoring FF is true, when is atomic and admin, then site monitoring item is built`() { + fun `give jetpack app, when FF is true and site is atomic and admin, then site monitoring item is built`() { setupSiteMonitoringItems( + isJetpackApp = true, isSiteMonitoringFeatureFlagEnabled = true, isAtomic = true, isAdmin = true @@ -435,8 +436,9 @@ class SiteListItemBuilderTest { } @Test - fun `give site monitoring FF is true, when is atomic and NOT admin, then site monitoring item is not built`() { + fun `give jetpack app, when FF is true and site is atomic and NOT admin, then site monitoring item is not built`() { setupSiteMonitoringItems( + isJetpackApp = true, isSiteMonitoringFeatureFlagEnabled = true, isAtomic = true, isAdmin = false @@ -448,8 +450,9 @@ class SiteListItemBuilderTest { } @Test - fun `give site monitoring FF is true, when is admin and NOT atomic, then site monitoring item is not built`() { + fun `give jetpack app, when FF is true and site is admin and NOT atomic, then site monitoring item is not built`() { setupSiteMonitoringItems( + isJetpackApp = true, isSiteMonitoringFeatureFlagEnabled = true, isAdmin = true ) @@ -460,8 +463,23 @@ class SiteListItemBuilderTest { } @Test - fun `give site monitoring FF is false, when is admin and atomic, then site monitoring item is not built`() { + fun `give jetpack app, when FF is false and site is admin and atomic, then site monitoring item is not built`() { setupSiteMonitoringItems( + isJetpackApp = true, + isAtomic = true, + isAdmin = true + ) + + val item = siteListItemBuilder.buildSiteMonitoringItemIfAvailable(siteModel, SITE_ITEM_ACTION) + + assertThat(item).isNull() + } + + @Test + fun `give not jetpack app, when FF is true and site is atomic and admin, then site monitoring item is not built`() { + setupSiteMonitoringItems( + isJetpackApp = false, + isSiteMonitoringFeatureFlagEnabled = true, isAtomic = true, isAdmin = true ) @@ -472,10 +490,12 @@ class SiteListItemBuilderTest { } private fun setupSiteMonitoringItems( + isJetpackApp: Boolean = false, isSiteMonitoringFeatureFlagEnabled: Boolean = false, isAtomic: Boolean = false, isAdmin: Boolean = false ) { + whenever(buildConfigWrapper.isJetpackApp).thenReturn(isJetpackApp) whenever(siteMonitoringFeatureConfig.isEnabled()).thenReturn(isSiteMonitoringFeatureFlagEnabled) whenever(siteModel.isAdmin).thenReturn(isAdmin) whenever(siteModel.isWPComAtomic).thenReturn(isAtomic) From e66ac0789fe035600cf80c8162802757621bb183 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Tue, 23 Jan 2024 16:41:20 +0100 Subject: [PATCH 051/176] Disable Story block --- .../java/org/wordpress/android/ui/posts/EditPostActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index a6884db857a2..5a4637715143 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -2513,7 +2513,7 @@ private GutenbergPropsBuilder getGutenbergPropsBuilder() { SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_INSTAGRAM_EMBED_JETPACK_VERSION), SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_LOOM_EMBED_JETPACK_VERSION), SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_SMARTFRAME_EMBED_JETPACK_VERSION), - SiteUtils.supportsStoriesFeature(mSite, mJetpackFeatureRemovalPhaseHelper), + false, mSite.isUsingWpComRestApi(), enableXPosts, isUnsupportedBlockEditorEnabled, From f2e21cb8b0a3ff2463811ba6cbc3971633df70ac Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Tue, 23 Jan 2024 18:30:39 +0100 Subject: [PATCH 052/176] Remove initial prop to control Story block --- .../java/org/wordpress/android/ui/posts/EditPostActivity.java | 2 -- .../wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt | 2 -- 2 files changed, 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index 5a4637715143..b9fbbf75af0f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -2490,7 +2490,6 @@ private GutenbergPropsBuilder getGutenbergPropsBuilder() { false, false, false, - false, true, false, !isFreeWPCom, @@ -2513,7 +2512,6 @@ private GutenbergPropsBuilder getGutenbergPropsBuilder() { SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_INSTAGRAM_EMBED_JETPACK_VERSION), SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_LOOM_EMBED_JETPACK_VERSION), SiteUtils.supportsEmbedVariationFeature(mSite, SiteUtils.WP_SMARTFRAME_EMBED_JETPACK_VERSION), - false, mSite.isUsingWpComRestApi(), enableXPosts, isUnsupportedBlockEditorEnabled, diff --git a/libs/editor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt b/libs/editor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt index c4117e0251f9..53ad2c0c9aae 100644 --- a/libs/editor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt +++ b/libs/editor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt @@ -18,7 +18,6 @@ data class GutenbergPropsBuilder( private val enableInstagramEmbed: Boolean, private val enableLoomEmbed: Boolean, private val enableSmartframeEmbed: Boolean, - private val enableMediaFilesCollectionBlocks: Boolean, private val enableMentions: Boolean, private val enableXPosts: Boolean, private val enableUnsupportedBlockEditor: Boolean, @@ -43,7 +42,6 @@ data class GutenbergPropsBuilder( enableInstagramEmbed = enableInstagramEmbed, enableLoomEmbed = enableLoomEmbed, enableSmartframeEmbed = enableSmartframeEmbed, - enableMediaFilesCollectionBlocks = enableMediaFilesCollectionBlocks, enableMentions = enableMentions, enableXPosts = enableXPosts, enableUnsupportedBlockEditor = enableUnsupportedBlockEditor, From aa4f6eb8bba1967f5e133796fca809aea1401008 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Fri, 26 Jan 2024 16:08:21 +0100 Subject: [PATCH 053/176] Update release notes --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index e835d3e7d3e2..592153fa492d 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -7,6 +7,7 @@ 24.1 ----- * [**] Disabled the ability of creating new Story posts. [#20014] +* [**] Disable Story block [https://github.com/wordpress-mobile/WordPress-Android/pull/20005] 24.0.1 ----- From 4bc201c469240062cefaf01b918312d74d29c19c Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Fri, 26 Jan 2024 17:03:03 +0100 Subject: [PATCH 054/176] Update Gutenberg Mobile reference with tag --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fe486b0b87f9..913ad424afe0 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 = '6568-674dc6550184c3b60cbb392091f7e9166ab06cad' + gutenbergMobileVersion = 'v1.112.0-alpha3' wordPressAztecVersion = 'v1.9.0' wordPressFluxCVersion = '2.61.0' wordPressLoginVersion = '1.10.0' From 8845481641fc6beffcb69e747f20946968eced97 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 26 Jan 2024 11:40:46 -0500 Subject: [PATCH 055/176] Refactor: remove SiteMonitorURL and list. Replace with url and addressToLoad --- .../ui/sitemonitor/SiteMonitorUiState.kt | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) 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 42434621a8e3..50bca3c0dec8 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 @@ -43,25 +43,16 @@ sealed class SiteMonitorUiState { } data class SiteMonitorModel( + val siteMonitorType: SiteMonitorType, val enableJavascript: Boolean = true, val enableDomStorage: Boolean = true, val enableChromeClient: Boolean = true, val userAgent: String = "", - val urls: List = emptyList() -) { - fun getUrlByType(type: SiteMonitorUrl.SiteMonitorType): SiteMonitorUrl? { - return urls.find { it.type == type } - } -} - -data class SiteMonitorUrl( - val type: SiteMonitorType, val url: String, val addressToLoad: String -) { - enum class SiteMonitorType { - METRICS, - PHP_LOGS, - WEB_SERVER_LOGS - } +) +enum class SiteMonitorType { + METRICS, + PHP_LOGS, + WEB_SERVER_LOGS } From a57a6d81da1c80d5f8dbc8e087dc70e2edd381f9 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 26 Jan 2024 11:41:26 -0500 Subject: [PATCH 056/176] Refactor: remove SiteMonitorURL list. Replace with values specific to that type --- .../wordpress/android/ui/sitemonitor/SiteMonitorMapper.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapper.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapper.kt index ac21f85e5ba2..f4bcb0d3c619 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapper.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorMapper.kt @@ -5,13 +5,15 @@ import javax.inject.Inject class SiteMonitorMapper @Inject constructor( private val siteMonitorUtils: SiteMonitorUtils ) { - fun toPrepared(urls: List) = SiteMonitorUiState.Prepared( + fun toPrepared(url: String, addressToLoad: String, siteMonitorType: SiteMonitorType) = SiteMonitorUiState.Prepared( model = SiteMonitorModel( enableJavascript = true, enableDomStorage = true, userAgent = siteMonitorUtils.getUserAgent(), enableChromeClient = true, - urls = urls + url = url, + addressToLoad = addressToLoad, + siteMonitorType = siteMonitorType ) ) From 5a2f30f6a3453b895b2d9952e4d174c19495aa0b Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 26 Jan 2024 11:42:03 -0500 Subject: [PATCH 057/176] Refactor: create a more specific web client so the URLs can be passed along to the activity/vm --- .../sitemonitor/SiteMonitorWebViewClient.kt | 43 ++++++++++++++++--- 1 file changed, 36 insertions(+), 7 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 fd13c1309bcb..29305e0d2ea0 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,17 +1,46 @@ package org.wordpress.android.ui.sitemonitor +import android.graphics.Bitmap +import android.webkit.WebResourceError import android.webkit.WebResourceRequest import android.webkit.WebView -import org.wordpress.android.util.ErrorManagedWebViewClient +import android.webkit.WebViewClient class SiteMonitorWebViewClient( - listener: SiteMonitorWebViewClientListener -) : ErrorManagedWebViewClient(listener) { - interface SiteMonitorWebViewClientListener : ErrorManagedWebViewClientListener { - fun onRedirectToExternalBrowser(url: String) + private val listener: SiteMonitorWebViewClientListener +) : WebViewClient() { + private var errorReceived = false + private var requestedUrl: String? = null + interface SiteMonitorWebViewClientListener { + fun onWebViewPageLoaded(url: String) + fun onWebViewReceivedError(url: String) } - - override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest) : Boolean { + override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { return false } + + override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { + super.onPageStarted(view, url, favicon) + errorReceived = false + requestedUrl = url + } + + override fun onPageFinished(view: WebView, url: String?) { + super.onPageFinished(view, url) + if (!errorReceived) { + url?.let { listener.onWebViewPageLoaded(it) } + } + } + + override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) { + super.onReceivedError(view, request, error) + // From the documentation: + // > These errors usually indicate inability to connect to the server. + // > will be called for any resource (iframe, image, etc.), not just for the main page. + // > 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()) + } + } } From 5aba4a3666a071b40e335097466fba3710ed1d61 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 26 Jan 2024 11:42:22 -0500 Subject: [PATCH 058/176] Add a helper function to convert from url to siteMonitor type --- .../android/ui/sitemonitor/SiteMonitorUtils.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 891931689048..dbaa7b25cebd 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 @@ -25,7 +25,17 @@ class SiteMonitorUtils @Inject constructor( fun sanitizeSiteUrl(url: String?) = url?.replace(Regex(HTTP_PATTERN), "") ?: "" + fun urlToType(url: String): SiteMonitorType { + return when { + url.contains(PHP_LOGS_PATTERN) -> SiteMonitorType.PHP_LOGS + url.contains(WEB_SERVER_LOGS_PATTERN) -> SiteMonitorType.WEB_SERVER_LOGS + else -> SiteMonitorType.METRICS + } + } + companion object { const val HTTP_PATTERN = "(https?://)" + const val PHP_LOGS_PATTERN = "/php" + const val WEB_SERVER_LOGS_PATTERN = "/web" } } From a7e48c5766dba115c645fc91f38fdaf181816709 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 26 Jan 2024 11:42:59 -0500 Subject: [PATCH 059/176] Refactor: Use a Map for the uiStates instead of a single uiState, so that each tab can hold it's own state --- .../sitemonitor/SiteMonitorParentViewModel.kt | 83 +++++++++---------- 1 file changed, 38 insertions(+), 45 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 38e2b43fc1fd..b691949c07a0 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 @@ -29,8 +29,9 @@ class SiteMonitorParentViewModel @Inject constructor( private val phpLogsUrlTemplate = "https://wordpress.com/site-monitoring/{blog}/php" private val webServerLogsUrlTemplate = "https://wordpress.com/site-monitoring/{blog}/web" - private val _uiState = MutableStateFlow(SiteMonitorUiState.Preparing) - val uiState = _uiState as StateFlow + private val _uiStates = MutableStateFlow>(emptyMap()) + val uiStates: StateFlow> = _uiStates + fun start(site: SiteModel) { this.site = site @@ -40,46 +41,30 @@ class SiteMonitorParentViewModel @Inject constructor( } private fun loadViews() { - postUiState(SiteMonitorUiState.Preparing) + SiteMonitorType.entries.forEach { type -> + postUiState(type, SiteMonitorUiState.Preparing) - if (!checkForInternetConnectivityAndPostErrorIfNeeded()) return + if (!checkForInternetConnectivityAndPostErrorIfNeeded(type)) return@forEach - if (!validateAndPostErrorIfNeeded()) return + if (!validateAndPostErrorIfNeeded(type)) return@forEach - assembleAndShowSiteMonitor() + assembleAndShowSiteMonitor(type) + } } - private fun assembleAndShowSiteMonitor() { + private fun assembleAndShowSiteMonitor(type: SiteMonitorType) { val sanitizedUrl = siteMonitorUtils.sanitizeSiteUrl(site.url) - - val siteMonitorUrls = mutableListOf().apply { - add( - createSiteMonitorUrl( - metricUrlTemplate.replace("{blog}", sanitizedUrl), SiteMonitorUrl.SiteMonitorType.METRICS) - ) - add( - createSiteMonitorUrl( - phpLogsUrlTemplate.replace("{blog}", sanitizedUrl), - SiteMonitorUrl.SiteMonitorType.PHP_LOGS - ) - ) - add( - createSiteMonitorUrl( - webServerLogsUrlTemplate.replace("{blog}", sanitizedUrl), - SiteMonitorUrl.SiteMonitorType.WEB_SERVER_LOGS - ) - ) - } - postUiState(mapper.toPrepared(siteMonitorUrls)) + val url = when (type) { + SiteMonitorType.METRICS -> metricUrlTemplate + SiteMonitorType.PHP_LOGS -> phpLogsUrlTemplate + SiteMonitorType.WEB_SERVER_LOGS -> webServerLogsUrlTemplate + }.replace("{blog}", sanitizedUrl) + + val addressToLoad = prepareAddressToLoad(url) + val uiState = mapper.toPrepared(url, addressToLoad, type) + postUiState(type, uiState) } - private fun createSiteMonitorUrl(url: String, type: SiteMonitorUrl.SiteMonitorType): SiteMonitorUrl { - return SiteMonitorUrl( - type = type, - url = url, - addressToLoad = prepareAddressToLoad(url) - ) - } private fun prepareAddressToLoad(url: String): String { val username = accountStore.account.userName val accessToken = accountStore.accessToken @@ -106,32 +91,40 @@ class SiteMonitorParentViewModel @Inject constructor( accessToken?:"" ) } - private fun checkForInternetConnectivityAndPostErrorIfNeeded(): Boolean { + private fun checkForInternetConnectivityAndPostErrorIfNeeded(type: SiteMonitorType) : Boolean { if (networkUtilsWrapper.isNetworkAvailable()) return true - postUiState(mapper.toNoNetworkError(this@SiteMonitorParentViewModel::loadViews)) - return false + postUiState(type, mapper.toNoNetworkError(this@SiteMonitorParentViewModel::loadViews)) + return false } - private fun validateAndPostErrorIfNeeded(): Boolean { + private fun validateAndPostErrorIfNeeded(type: SiteMonitorType): Boolean { if (accountStore.account.userName.isNullOrEmpty() || accountStore.accessToken.isNullOrEmpty()) { - postUiState(mapper.toGenericError(this@SiteMonitorParentViewModel::loadViews)) + postUiState(type, mapper.toGenericError(this@SiteMonitorParentViewModel::loadViews)) return false } return true } - private fun postUiState(uiState: SiteMonitorUiState) { + private fun postUiState(type: SiteMonitorType, uiState: SiteMonitorUiState) { launch { - _uiState.value = uiState + _uiStates.value = _uiStates.value.toMutableMap().apply { + this[type] = uiState + } } } - fun onUrlLoaded() { - postUiState(SiteMonitorUiState.Loaded) + fun onUrlLoaded(url: String) { + val currentState = _uiStates.value + val type = siteMonitorUtils.urlToType(url) + val updatedState = currentState + (type to SiteMonitorUiState.Loaded) + _uiStates.value = updatedState } - fun onWebViewError() { - postUiState(mapper.toGenericError(this@SiteMonitorParentViewModel::loadViews)) + fun onWebViewError(url: String) { + val currentState = _uiStates.value + val type = siteMonitorUtils.urlToType(url) + val updatedState = currentState + (type to mapper.toGenericError(this@SiteMonitorParentViewModel::loadViews)) + _uiStates.value = updatedState } companion object { From 8049c13ff94b5cd900c37919d58ea17660160924 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 26 Jan 2024 11:43:43 -0500 Subject: [PATCH 060/176] Refactor: Handle a Map of uiStates instead of a single uiState. Use type to determine views. This needs more work --- .../sitemonitor/SiteMonitorParentActivity.kt | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 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 6e7b3df2048e..3c1537d45533 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 @@ -50,13 +50,9 @@ import org.wordpress.android.util.extensions.getSerializableExtraCompat @AndroidEntryPoint class SiteMonitorParentActivity: AppCompatActivity(), SiteMonitorWebViewClientListener { - override fun onRedirectToExternalBrowser(url: String) { - // todo: not sure if this is needed - } - - override fun onWebViewPageLoaded() = viewModel.onUrlLoaded() + override fun onWebViewPageLoaded(url: String) = viewModel.onUrlLoaded(url) - override fun onWebViewReceivedError() = viewModel.onWebViewError() + override fun onWebViewReceivedError(url: String) = viewModel.onWebViewError(url) val viewModel:SiteMonitorParentViewModel by viewModels() @@ -78,7 +74,7 @@ val viewModel:SiteMonitorParentViewModel by viewModels() @SuppressLint("UnusedMaterialScaffoldPaddingParameter") fun SiteMonitorScreen(modifier: Modifier = Modifier, viewModel: SiteMonitorParentViewModel = androidx.lifecycle.viewmodel.compose.viewModel()) { - val uiState by viewModel.uiState.collectAsState() + val uiStates by viewModel.uiStates.collectAsState() Scaffold( topBar = { MainTopAppBar( @@ -88,14 +84,14 @@ val viewModel:SiteMonitorParentViewModel by viewModels() ) }, content = { - TabScreen(modifier = modifier, uiState) + TabScreen(modifier = modifier, uiStates) } ) } @Composable @SuppressLint("UnusedMaterialScaffoldPaddingParameter") - fun TabScreen(modifier: Modifier = Modifier, uiState: SiteMonitorUiState) { + fun TabScreen(modifier: Modifier = Modifier, uiStates: Map) { var tabIndex by remember { mutableIntStateOf(0) } val tabs = listOf( @@ -104,6 +100,12 @@ val viewModel:SiteMonitorParentViewModel by viewModels() R.string.site_monitoring_tab_title_web_server_logs ) + val tabsToType = mapOf( + 0 to SiteMonitorType.METRICS, + 1 to SiteMonitorType.PHP_LOGS, + 2 to SiteMonitorType.WEB_SERVER_LOGS + ) + Column(modifier = modifier.fillMaxWidth()) { TabRow( selectedTabIndex = tabIndex, @@ -117,19 +119,16 @@ val viewModel:SiteMonitorParentViewModel by viewModels() ) } } - when (tabIndex) { - 0 -> SiteMonitoringWebViewForTab(uiState, SiteMonitorUrl.SiteMonitorType.METRICS) - 1 -> SiteMonitoringWebViewForTab(uiState, SiteMonitorUrl.SiteMonitorType.PHP_LOGS) - 2 -> SiteMonitoringWebViewForTab(uiState, SiteMonitorUrl.SiteMonitorType.WEB_SERVER_LOGS) - } + val uiState = uiStates[tabsToType[tabIndex]] as SiteMonitorUiState + SiteMonitoringWebViewForTab(uiState) } } @Composable - fun SiteMonitoringWebViewForTab(uiState: SiteMonitorUiState, tab: SiteMonitorUrl.SiteMonitorType) { + fun SiteMonitoringWebViewForTab(uiState: SiteMonitorUiState) { when (uiState) { is SiteMonitorUiState.Preparing -> LoadingState() - is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitoringWebView(uiState, tab) + is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitoringWebView(uiState) is SiteMonitorUiState.Error -> SiteMonitorError(uiState) } } @@ -167,7 +166,7 @@ val viewModel:SiteMonitorParentViewModel by viewModels() } @SuppressLint("SetJavaScriptEnabled") @Composable - fun SiteMonitoringWebView(uiState: SiteMonitorUiState, tab: SiteMonitorUrl.SiteMonitorType) { + fun SiteMonitoringWebView(uiState: SiteMonitorUiState) { var webView: WebView? by remember { mutableStateOf(null) } if (uiState is SiteMonitorUiState.Prepared) { @@ -183,9 +182,7 @@ val viewModel:SiteMonitorParentViewModel by viewModels() settings.javaScriptEnabled = true settings.domStorageEnabled = true webViewClient = SiteMonitorWebViewClient(this@SiteMonitorParentActivity) - model.getUrlByType(tab)?.addressToLoad?.let { - postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, it.toByteArray()) - } + postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, model.addressToLoad.toByteArray()) } } } From 6419fcd89a7e13cceec87e818e68304272de7f9c Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Fri, 26 Jan 2024 19:14:08 +0100 Subject: [PATCH 061/176] Update Gutenberg Mobile reference with tag --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8ccb2fce17eb..e29ad0136166 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 = '6580-9fe963032e189dc6bb8dbbb4b9238d34759c0ed8' + gutenbergMobileVersion = 'v1.111.2' wordPressAztecVersion = 'v1.9.0' wordPressFluxCVersion = '2.61.0' wordPressLoginVersion = '1.10.0' From cb4044ef786c544f1ea7145d21b22afc636665d6 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Fri, 26 Jan 2024 19:43:40 +0100 Subject: [PATCH 062/176] Remove deprecated group id from Dependabot configuration --- .github/dependabot.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f0c244ca5c84..17b9023f0012 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -36,9 +36,6 @@ updates: # dependapot. - dependency-name: "org.wordpress:fluxc" - dependency-name: "org.wordpress:utils" - # org.wordpress-mobile.gutenberg-mobile is deprecated and org.wordpress.gutenberg-mobile is used instead. - # Temporarily leaving this declaration during transition, but this should be removed soon. - - dependency-name: "org.wordpress-mobile.gutenberg-mobile:react-native-gutenberg-bridge" - dependency-name: "org.wordpress.gutenberg-mobile:react-native-gutenberg-bridge" - dependency-name: "org.wordpress:login" - dependency-name: "com.automattic:stories" From b5f3cd2e1fdcaa9ac75ec1039326356bf1bb0e57 Mon Sep 17 00:00:00 2001 From: Oguz Kocer Date: Fri, 26 Jan 2024 14:27:32 -0500 Subject: [PATCH 063/176] Bump version number --- version.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.properties b/version.properties index 3920603cc85b..49023e812e58 100644 --- a/version.properties +++ b/version.properties @@ -1,2 +1,2 @@ -versionName=24.0.1 -versionCode=1402 +versionName=24.0.2 +versionCode=1404 \ No newline at end of file From a4bfd24c959c09a033183d748e5f64928b921990 Mon Sep 17 00:00:00 2001 From: David Calhoun Date: Fri, 26 Jan 2024 12:09:35 -0500 Subject: [PATCH 064/176] fix: Prevent Gutenberg connection logic from crashing Aztec A network connectivity subscriber was added to the post activity in: https://github.com/wordpress-mobile/WordPress-Android/pull/19692 However, it was not scoped to only run in the Gutenberg editor. Because no guard was in place, the subscriber attempted to invoke a non-existent method on the Aztec editor, resulting in a crash. --- .../java/org/wordpress/android/ui/posts/EditPostActivity.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index 8eb3b555a0c8..f37bd022b9ce 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -71,6 +71,7 @@ import org.wordpress.android.editor.EditorMediaUtils; import org.wordpress.android.editor.EditorThemeUpdateListener; import org.wordpress.android.editor.ExceptionLogger; +import org.wordpress.android.editor.gutenberg.GutenbergNetworkConnectionListener; import org.wordpress.android.editor.savedinstance.SavedInstanceDatabase; import org.wordpress.android.editor.gutenberg.DialogVisibility; import org.wordpress.android.editor.gutenberg.GutenbergEditorFragment; @@ -3844,6 +3845,8 @@ public void onEventMainThread(UploadService.UploadMediaRetryEvent event) { @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(ConnectionChangeReceiver.ConnectionChangeEvent event) { + if (!(mEditorFragment instanceof GutenbergNetworkConnectionListener)) return; + ((GutenbergEditorFragment) mEditorFragment).onConnectionStatusChange(event.isConnected()); } From a931b5db32c1f583dc9a044ff4c3c4003c4f97e0 Mon Sep 17 00:00:00 2001 From: David Calhoun Date: Fri, 26 Jan 2024 12:20:35 -0500 Subject: [PATCH 065/176] docs: Add release note --- RELEASE-NOTES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index bea44db9b619..a2152b86784b 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -3,6 +3,10 @@ 24.1 ----- +24.0.2 +----- +* [**] Fix Aztec editor crash when losing or gaining network connectivity [https://github.com/wordpress-mobile/WordPress-Android/pull/20053] + 24.0.1 ----- * [**] Fix crash when RichText values are not defined [https://github.com/wordpress-mobile/gutenberg-mobile/pull/6563] From 271dcea802fe85b517b761aa7ab759d0e7b0cfd7 Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Fri, 26 Jan 2024 20:26:19 +0000 Subject: [PATCH 066/176] Freeze strings for translation --- fastlane/resources/values/strings.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fastlane/resources/values/strings.xml b/fastlane/resources/values/strings.xml index f7865454b8b2..32fe5037b220 100644 --- a/fastlane/resources/values/strings.xml +++ b/fastlane/resources/values/strings.xml @@ -2983,12 +2983,6 @@ Camera Microphone - - Yes, leave on - No, turn off - Keep optimizing images? - Image optimization shrinks images for faster uploading.\n\nThis option is enabled by default, but you can change it in the app settings at any time. - From 187a58f6d965e59db0d36fa7f6b6bcdad2c88ac9 Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Fri, 26 Jan 2024 20:28:08 +0000 Subject: [PATCH 067/176] Update translations --- WordPress/src/main/res/values-ar/strings.xml | 8 ++++++-- WordPress/src/main/res/values-az/strings.xml | 2 +- WordPress/src/main/res/values-bg/strings.xml | 2 +- WordPress/src/main/res/values-cs/strings.xml | 2 +- WordPress/src/main/res/values-cy/strings.xml | 2 +- WordPress/src/main/res/values-da/strings.xml | 2 +- WordPress/src/main/res/values-de/strings.xml | 7 +++++-- WordPress/src/main/res/values-el/strings.xml | 2 +- WordPress/src/main/res/values-en-rCA/strings.xml | 2 +- WordPress/src/main/res/values-en-rGB/strings.xml | 2 +- WordPress/src/main/res/values-es-rCL/strings.xml | 2 +- WordPress/src/main/res/values-es-rCO/strings.xml | 2 +- WordPress/src/main/res/values-es-rMX/strings.xml | 2 +- WordPress/src/main/res/values-es-rVE/strings.xml | 2 +- WordPress/src/main/res/values-es/strings.xml | 2 +- WordPress/src/main/res/values-eu/strings.xml | 2 +- WordPress/src/main/res/values-fr-rCA/strings.xml | 9 ++++++--- WordPress/src/main/res/values-fr/strings.xml | 9 ++++++--- WordPress/src/main/res/values-gd/strings.xml | 2 +- WordPress/src/main/res/values-gl/strings.xml | 5 +++-- WordPress/src/main/res/values-he/strings.xml | 7 +++++-- WordPress/src/main/res/values-hi/strings.xml | 2 +- WordPress/src/main/res/values-hr/strings.xml | 2 +- WordPress/src/main/res/values-hu/strings.xml | 2 +- WordPress/src/main/res/values-id/strings.xml | 7 +++++-- WordPress/src/main/res/values-is/strings.xml | 2 +- WordPress/src/main/res/values-it/strings.xml | 7 +++++-- WordPress/src/main/res/values-ja/strings.xml | 7 +++++-- WordPress/src/main/res/values-kmr/strings.xml | 2 +- WordPress/src/main/res/values-ko/strings.xml | 7 +++++-- WordPress/src/main/res/values-lv/strings.xml | 2 +- WordPress/src/main/res/values-mk/strings.xml | 2 +- WordPress/src/main/res/values-ms/strings.xml | 2 +- WordPress/src/main/res/values-nb/strings.xml | 2 +- WordPress/src/main/res/values-nl/strings.xml | 7 +++++-- WordPress/src/main/res/values-pl/strings.xml | 2 +- WordPress/src/main/res/values-pt-rBR/strings.xml | 2 +- WordPress/src/main/res/values-ro/strings.xml | 2 +- WordPress/src/main/res/values-ru/strings.xml | 2 +- WordPress/src/main/res/values-sk/strings.xml | 2 +- WordPress/src/main/res/values-sq/strings.xml | 7 +++++-- WordPress/src/main/res/values-sr/strings.xml | 2 +- WordPress/src/main/res/values-sv/strings.xml | 2 +- WordPress/src/main/res/values-th/strings.xml | 2 +- WordPress/src/main/res/values-tr/strings.xml | 7 +++++-- WordPress/src/main/res/values-uz/strings.xml | 2 +- WordPress/src/main/res/values-vi/strings.xml | 2 +- WordPress/src/main/res/values-zh-rCN/strings.xml | 7 +++++-- WordPress/src/main/res/values-zh-rHK/strings.xml | 7 +++++-- WordPress/src/main/res/values-zh-rTW/strings.xml | 7 +++++-- 50 files changed, 115 insertions(+), 68 deletions(-) diff --git a/WordPress/src/main/res/values-ar/strings.xml b/WordPress/src/main/res/values-ar/strings.xml index 58019d934b74..bc2a65e86636 100644 --- a/WordPress/src/main/res/values-ar/strings.xml +++ b/WordPress/src/main/res/values-ar/strings.xml @@ -1,11 +1,13 @@ + انتظار الاتصال + حركة المرور العمل من دون اتصال بالإنترنت أعيد إنشاء الاتصال بالشبكة فقدان الاتصال بالشبكة، العمل من دون اتصال بالإنترنت @@ -197,6 +199,7 @@ Language: ar إغلاق المحرر إعادة آخر تغيير الاشتراك لمشاركة المزيد + التراجع عن آخر تغيير قم بزيادة حركة المرور لديك من حلال مشاركة تدويناتك تلقائيًا مع أصدقائك على شبكات التواصل الاجتماعي. المشاركة عبر شبكات التواصل الاجتماعي تم فصل %s @@ -399,6 +402,7 @@ Language: ar آخر 7 أيام %d من الأسابيع أسبوع واحد + من <b>Day One</b> ذكرني لاحقًا التبديل إلى تطبيق Jetpack معرفة المزيد على jetpack.com diff --git a/WordPress/src/main/res/values-az/strings.xml b/WordPress/src/main/res/values-az/strings.xml index 8ef3522f0308..45a82373b48d 100644 --- a/WordPress/src/main/res/values-az/strings.xml +++ b/WordPress/src/main/res/values-az/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-bg/strings.xml b/WordPress/src/main/res/values-bg/strings.xml index 6c8ba2ed0123..bfc4f3e4ef16 100644 --- a/WordPress/src/main/res/values-bg/strings.xml +++ b/WordPress/src/main/res/values-bg/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-cs/strings.xml b/WordPress/src/main/res/values-cs/strings.xml index 1f365fe039fb..f644591552d7 100644 --- a/WordPress/src/main/res/values-cs/strings.xml +++ b/WordPress/src/main/res/values-cs/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-cy/strings.xml b/WordPress/src/main/res/values-cy/strings.xml index 848c9af8016e..cf2f3993492f 100644 --- a/WordPress/src/main/res/values-cy/strings.xml +++ b/WordPress/src/main/res/values-cy/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-da/strings.xml b/WordPress/src/main/res/values-da/strings.xml index 39d3c5999818..2fa65fa5095a 100644 --- a/WordPress/src/main/res/values-da/strings.xml +++ b/WordPress/src/main/res/values-da/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-de/strings.xml b/WordPress/src/main/res/values-de/strings.xml index b344a08f4dba..a6041634c997 100644 --- a/WordPress/src/main/res/values-de/strings.xml +++ b/WordPress/src/main/res/values-de/strings.xml @@ -1,11 +1,13 @@ + Warten auf Verbindung + Traffic Offline arbeiten Die Netzwerkverbindung wurde wiederhergestellt Die Netzwerkverbindung ging verloren, offline arbeiten @@ -411,6 +413,7 @@ Language: de Letzte 7 Tage %d Wochen 1 Woche + Von <b>Day One</b> Später daran erinnern Die Statistiken, der Reader, die Benachrichtigungen und weitere Funktionen werden bald in die Jetpack-Mobil-App verschoben. Zur Jetpack-App wechseln diff --git a/WordPress/src/main/res/values-el/strings.xml b/WordPress/src/main/res/values-el/strings.xml index e53294030905..b63b80a5d756 100644 --- a/WordPress/src/main/res/values-el/strings.xml +++ b/WordPress/src/main/res/values-el/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-en-rCA/strings.xml b/WordPress/src/main/res/values-en-rCA/strings.xml index b4f0dad06a92..6e2422d699f5 100644 --- a/WordPress/src/main/res/values-en-rCA/strings.xml +++ b/WordPress/src/main/res/values-en-rCA/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-en-rGB/strings.xml b/WordPress/src/main/res/values-en-rGB/strings.xml index bf14691fa081..6ee3c41bdc2d 100644 --- a/WordPress/src/main/res/values-en-rGB/strings.xml +++ b/WordPress/src/main/res/values-en-rGB/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-es-rCL/strings.xml b/WordPress/src/main/res/values-es-rCL/strings.xml index 0cc931e5cd23..810fd0e3a9e4 100644 --- a/WordPress/src/main/res/values-es-rCL/strings.xml +++ b/WordPress/src/main/res/values-es-rCL/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-es-rCO/strings.xml b/WordPress/src/main/res/values-es-rCO/strings.xml index efe422874b90..b3c8d47f5c84 100644 --- a/WordPress/src/main/res/values-es-rCO/strings.xml +++ b/WordPress/src/main/res/values-es-rCO/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-es-rMX/strings.xml b/WordPress/src/main/res/values-es-rMX/strings.xml index 6b0bfb2edaf0..f48b7a71dbe8 100644 --- a/WordPress/src/main/res/values-es-rMX/strings.xml +++ b/WordPress/src/main/res/values-es-rMX/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-es-rVE/strings.xml b/WordPress/src/main/res/values-es-rVE/strings.xml index 6f74dca7181d..2ed81faa5a5a 100644 --- a/WordPress/src/main/res/values-es-rVE/strings.xml +++ b/WordPress/src/main/res/values-es-rVE/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-es/strings.xml b/WordPress/src/main/res/values-es/strings.xml index a455319940dd..a9730daf3cdb 100644 --- a/WordPress/src/main/res/values-es/strings.xml +++ b/WordPress/src/main/res/values-es/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-eu/strings.xml b/WordPress/src/main/res/values-eu/strings.xml index 1f9afd17fff7..0425ccbe20db 100644 --- a/WordPress/src/main/res/values-eu/strings.xml +++ b/WordPress/src/main/res/values-eu/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-fr-rCA/strings.xml b/WordPress/src/main/res/values-fr-rCA/strings.xml index af19b20f9fc9..a40cadc58586 100644 --- a/WordPress/src/main/res/values-fr-rCA/strings.xml +++ b/WordPress/src/main/res/values-fr-rCA/strings.xml @@ -1,11 +1,13 @@ + En attente de connexion + Trafic Travail hors ligne Connexion réseau rétablie Perte de la connexion réseau, travail hors ligne @@ -402,6 +404,7 @@ Language: fr 7 derniers jours %d semaines 1 semaine + De <b>Day One</b> Me rappeler ultérieurement Les statistiques, le lecteur, les notifications et d’autres fonctionnalités seront bientôt transférées vers l’application mobile Jetpack. Passer à l’application Jetpack @@ -1641,7 +1644,7 @@ Language: fr Les étiquettes indiquent aux lecteurs de quoi traite l’article. Date de publication Ajouter des étiquettes - Précédent + Retour Enregistrer maintenant Soumettre maintenant Planifier maintenant diff --git a/WordPress/src/main/res/values-fr/strings.xml b/WordPress/src/main/res/values-fr/strings.xml index af19b20f9fc9..a40cadc58586 100644 --- a/WordPress/src/main/res/values-fr/strings.xml +++ b/WordPress/src/main/res/values-fr/strings.xml @@ -1,11 +1,13 @@ + En attente de connexion + Trafic Travail hors ligne Connexion réseau rétablie Perte de la connexion réseau, travail hors ligne @@ -402,6 +404,7 @@ Language: fr 7 derniers jours %d semaines 1 semaine + De <b>Day One</b> Me rappeler ultérieurement Les statistiques, le lecteur, les notifications et d’autres fonctionnalités seront bientôt transférées vers l’application mobile Jetpack. Passer à l’application Jetpack @@ -1641,7 +1644,7 @@ Language: fr Les étiquettes indiquent aux lecteurs de quoi traite l’article. Date de publication Ajouter des étiquettes - Précédent + Retour Enregistrer maintenant Soumettre maintenant Planifier maintenant diff --git a/WordPress/src/main/res/values-gd/strings.xml b/WordPress/src/main/res/values-gd/strings.xml index 6c6648de0fd4..6a5a0d125644 100644 --- a/WordPress/src/main/res/values-gd/strings.xml +++ b/WordPress/src/main/res/values-gd/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-gl/strings.xml b/WordPress/src/main/res/values-gl/strings.xml index acc26a8e298e..277f902dbc54 100644 --- a/WordPress/src/main/res/values-gl/strings.xml +++ b/WordPress/src/main/res/values-gl/strings.xml @@ -1,8 +1,8 @@ @@ -411,6 +411,7 @@ Language: gl_ES As túas visitas nos últimos sete días son %1$s máis que nos sete días anteriores. Os teus visitantes nos últimos sete días son %1$s menos que nos sete días anteriores. Os teus visitantes nos últimos sete días son %1$s máis que nos sete días anteriores. + Desde <b>Day One</b> Recórdamo máis tarde Cambiar á aplicación de Jetpack Máis información en jetpack.com diff --git a/WordPress/src/main/res/values-he/strings.xml b/WordPress/src/main/res/values-he/strings.xml index d340794b050c..b83d4237be00 100644 --- a/WordPress/src/main/res/values-he/strings.xml +++ b/WordPress/src/main/res/values-he/strings.xml @@ -1,11 +1,13 @@ + ממתין לחיבור + תעבורה עבודה במצב לא מקוון החיבור לרשת בוצע מחדש החיבור לרשת אבד, העבודה מתבצעת במצב לא מקוון @@ -405,6 +407,7 @@ Language: he_IL שבעת הימים האחרונים %d שבועות שבוע אחד + מ-<b>Day One</b> הזכירו לי מאוחר יותר האפשרויות של נתונים סטטיסטיים, Reader, הודעות ואפשרויות אחרות יועברו בקרוב אל האפליקציה של Jetpack לנייד. החלפה לאפליקציה של Jetpack diff --git a/WordPress/src/main/res/values-hi/strings.xml b/WordPress/src/main/res/values-hi/strings.xml index 712dd2704dc1..c0606d541d14 100644 --- a/WordPress/src/main/res/values-hi/strings.xml +++ b/WordPress/src/main/res/values-hi/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-hr/strings.xml b/WordPress/src/main/res/values-hr/strings.xml index f15df2e120a1..6d57986c56a1 100644 --- a/WordPress/src/main/res/values-hr/strings.xml +++ b/WordPress/src/main/res/values-hr/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-hu/strings.xml b/WordPress/src/main/res/values-hu/strings.xml index 304c13ec9c62..01d6aeffe4e5 100644 --- a/WordPress/src/main/res/values-hu/strings.xml +++ b/WordPress/src/main/res/values-hu/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-id/strings.xml b/WordPress/src/main/res/values-id/strings.xml index 50d352f5b3c9..a66909914ce0 100644 --- a/WordPress/src/main/res/values-id/strings.xml +++ b/WordPress/src/main/res/values-id/strings.xml @@ -1,11 +1,13 @@ + Menunggu koneksi + Lalu lintas Bekerja secara Offline Koneksi internet terhubung lagi Koneksi internet terputus, bekerja secara offline @@ -404,6 +406,7 @@ Language: id 7 hari terakhir %d minggu 1 minggu + Dari <b>Day One</b> Ingatkan saya nanti Statistik, Reader, Pemberitahuan, dan berbagai fitur lain akan segera berpindah ke aplikasi ponsel Jetpack. Ganti ke aplikasi Jetpack diff --git a/WordPress/src/main/res/values-is/strings.xml b/WordPress/src/main/res/values-is/strings.xml index 4d3bd4a14929..be57d67f7a78 100644 --- a/WordPress/src/main/res/values-is/strings.xml +++ b/WordPress/src/main/res/values-is/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-it/strings.xml b/WordPress/src/main/res/values-it/strings.xml index fd8b70cce538..43d3cb8e8c78 100644 --- a/WordPress/src/main/res/values-it/strings.xml +++ b/WordPress/src/main/res/values-it/strings.xml @@ -1,11 +1,13 @@ + In attesa della connessione + Traffico Lavorare offline Connessione di rete ristabilita Connessione di rete persa, lavoro offline @@ -404,6 +406,7 @@ Language: it Ultimi 7 giorni %d settimane 1 settimana + Da <b>Day One</b> Ricordamelo più tardi Statistiche, Reader, Notifiche e altre funzionalità passeranno presto all\'app mobile Jetpack. Passa all\'app Jetpack diff --git a/WordPress/src/main/res/values-ja/strings.xml b/WordPress/src/main/res/values-ja/strings.xml index 2c537eaf6246..90195aa9846b 100644 --- a/WordPress/src/main/res/values-ja/strings.xml +++ b/WordPress/src/main/res/values-ja/strings.xml @@ -1,11 +1,13 @@ + 接続を待機中 + トラフィック オフラインで作業 ネットワーク接続が再確立されました ネットワーク接続が失われ、オフラインで作業しています @@ -404,6 +406,7 @@ Language: ja_JP 過去7日間 %d週 1週 + <b>Day One</b> から 後で再通知 統計、Reader、通知などの機能は、まもなく Jetpack モバイルアプリに移動します。 Jetpack アプリに切り替える diff --git a/WordPress/src/main/res/values-kmr/strings.xml b/WordPress/src/main/res/values-kmr/strings.xml index 39e76501d264..ed354762eb26 100644 --- a/WordPress/src/main/res/values-kmr/strings.xml +++ b/WordPress/src/main/res/values-kmr/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-ko/strings.xml b/WordPress/src/main/res/values-ko/strings.xml index b68d773d4495..b92b8c0e492e 100644 --- a/WordPress/src/main/res/values-ko/strings.xml +++ b/WordPress/src/main/res/values-ko/strings.xml @@ -1,11 +1,13 @@ + 연결 대기 중 + 트래픽 오프라인 작업 중 네트워크 연결 다시 설정됨 네트워크 연결 해제됨, 오프라인 작업 중 @@ -404,6 +406,7 @@ Language: ko_KR 최근 7일 %d주 1주 + 출처: <b>Day One</b> 나중에 다시 알림 곧 통계, 리더, 알림 및 기타 기능이 젯팩 모바일 앱으로 이동됩니다. 젯팩 앱으로 전환 diff --git a/WordPress/src/main/res/values-lv/strings.xml b/WordPress/src/main/res/values-lv/strings.xml index 4bf6bfb4b0ea..dafbd0d2af5d 100644 --- a/WordPress/src/main/res/values-lv/strings.xml +++ b/WordPress/src/main/res/values-lv/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-mk/strings.xml b/WordPress/src/main/res/values-mk/strings.xml index efc617b4d405..ecb4f36353e0 100644 --- a/WordPress/src/main/res/values-mk/strings.xml +++ b/WordPress/src/main/res/values-mk/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-ms/strings.xml b/WordPress/src/main/res/values-ms/strings.xml index be872a599ce4..e37bf5e6eb0b 100644 --- a/WordPress/src/main/res/values-ms/strings.xml +++ b/WordPress/src/main/res/values-ms/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-nb/strings.xml b/WordPress/src/main/res/values-nb/strings.xml index 013567705df3..94168831f849 100644 --- a/WordPress/src/main/res/values-nb/strings.xml +++ b/WordPress/src/main/res/values-nb/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-nl/strings.xml b/WordPress/src/main/res/values-nl/strings.xml index a0b32c67f6fe..4a2ae1469679 100644 --- a/WordPress/src/main/res/values-nl/strings.xml +++ b/WordPress/src/main/res/values-nl/strings.xml @@ -1,11 +1,12 @@ + Bezoekersaantallen Werk offline Netwerk opnieuw verbonden Netwerkverbinding verbroken, offline werken @@ -111,6 +112,7 @@ Language: nl Een ondersteuningsticket aanmaken … Hoe kan ik mijn aangepaste domein gebruiken in de app? Ik ben mijn inloggegevens vergeten + Ik kan geen foto\'s en video\'s uploaden Help, mijn site is onbereikbaar! Wat is mijn siteadres? Weet je niet wat je moet vragen? @@ -347,6 +349,7 @@ Language: nl Afgelopen 7 dagen %d weken 1 week + Van <b>Day One</b> Herinner mij hier later aan Statistieken, Lezer, Meldingen en andere functies worden binnenkort verplaatst naar de mobiele Jetpack-app. Schakel over naar de Jetpack-app diff --git a/WordPress/src/main/res/values-pl/strings.xml b/WordPress/src/main/res/values-pl/strings.xml index c4ca4fcb25c2..424a431caa58 100644 --- a/WordPress/src/main/res/values-pl/strings.xml +++ b/WordPress/src/main/res/values-pl/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-pt-rBR/strings.xml b/WordPress/src/main/res/values-pt-rBR/strings.xml index de26267f7c52..08155fb58c69 100644 --- a/WordPress/src/main/res/values-pt-rBR/strings.xml +++ b/WordPress/src/main/res/values-pt-rBR/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-ro/strings.xml b/WordPress/src/main/res/values-ro/strings.xml index cef589d6243d..7de4ae575c96 100644 --- a/WordPress/src/main/res/values-ro/strings.xml +++ b/WordPress/src/main/res/values-ro/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-ru/strings.xml b/WordPress/src/main/res/values-ru/strings.xml index bdf7541bd763..a396869a87fd 100644 --- a/WordPress/src/main/res/values-ru/strings.xml +++ b/WordPress/src/main/res/values-ru/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-sk/strings.xml b/WordPress/src/main/res/values-sk/strings.xml index 46ac29c7e93f..8ac07425a11d 100644 --- a/WordPress/src/main/res/values-sk/strings.xml +++ b/WordPress/src/main/res/values-sk/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-sq/strings.xml b/WordPress/src/main/res/values-sq/strings.xml index 8a2748e80e81..996c03a9a9d8 100644 --- a/WordPress/src/main/res/values-sq/strings.xml +++ b/WordPress/src/main/res/values-sq/strings.xml @@ -1,11 +1,13 @@ + Po pritet për lidhje + Trafik Punim i Palidhur Lidhja me rrjetin u rivendos Humbi lidhja me rrjetin, po punohet pa u lidhur @@ -410,6 +412,7 @@ Language: sq_AL 7 ditët e fundit %d javë 1 javë + Nga <b>Dita e Parë</b> Kujtoma më vonë Statistikat, Lexuesi, Njoftimet dhe të tjera veçorit të Jetpack-ut së shpejti do të kalohen te aplikacioni Jetpack për celular. Kaloni te aplikacioni Jetpack diff --git a/WordPress/src/main/res/values-sr/strings.xml b/WordPress/src/main/res/values-sr/strings.xml index 4c94593801da..a84ce6fd31f2 100644 --- a/WordPress/src/main/res/values-sr/strings.xml +++ b/WordPress/src/main/res/values-sr/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-sv/strings.xml b/WordPress/src/main/res/values-sv/strings.xml index ebfee79526c4..f5c947862364 100644 --- a/WordPress/src/main/res/values-sv/strings.xml +++ b/WordPress/src/main/res/values-sv/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-th/strings.xml b/WordPress/src/main/res/values-th/strings.xml index 2b302fdcc746..f206c5a3881b 100644 --- a/WordPress/src/main/res/values-th/strings.xml +++ b/WordPress/src/main/res/values-th/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-tr/strings.xml b/WordPress/src/main/res/values-tr/strings.xml index 4405348524d1..a212e63c54f0 100644 --- a/WordPress/src/main/res/values-tr/strings.xml +++ b/WordPress/src/main/res/values-tr/strings.xml @@ -1,11 +1,13 @@ + Bağlantı bekleniyor + Trafik Çevrimdışı Çalışıyor Ağ bağlantısı yeniden kuruldu Ağ bağlantısı kesildi, çevrimdışı çalışıyor @@ -408,6 +410,7 @@ Language: tr Son 7 gün %d hafta 1 hafta + <b>Day One</b>\'dan Daha sonra hatırlat İstatistikler, Okuyucu, Bildirimler ve diğer özellikler yakında Jetpack mobil uygulamasına taşınacak. Jetpack uygulamasına geçiş yapın diff --git a/WordPress/src/main/res/values-uz/strings.xml b/WordPress/src/main/res/values-uz/strings.xml index 5b1f9e22c192..7f93f6fed4a2 100644 --- a/WordPress/src/main/res/values-uz/strings.xml +++ b/WordPress/src/main/res/values-uz/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-vi/strings.xml b/WordPress/src/main/res/values-vi/strings.xml index 2a92fcc70b3a..343282b4c0ff 100644 --- a/WordPress/src/main/res/values-vi/strings.xml +++ b/WordPress/src/main/res/values-vi/strings.xml @@ -2,7 +2,7 @@ diff --git a/WordPress/src/main/res/values-zh-rCN/strings.xml b/WordPress/src/main/res/values-zh-rCN/strings.xml index 7cef5ff8e92b..8a15435f6ddf 100644 --- a/WordPress/src/main/res/values-zh-rCN/strings.xml +++ b/WordPress/src/main/res/values-zh-rCN/strings.xml @@ -1,11 +1,13 @@ + 正在等待连接 + 流量 离线工作 已重新建立网络连接 网络连接中断,正在离线工作 @@ -401,6 +403,7 @@ Language: zh_CN 过去 7 天 %d 周 1 周 + 来自 <b>Day One</b> 稍后提醒我 统计信息、阅读器、通知和其他功能即将移至 Jetpack 移动应用。 切换到 Jetpack 应用 diff --git a/WordPress/src/main/res/values-zh-rHK/strings.xml b/WordPress/src/main/res/values-zh-rHK/strings.xml index b15514a48548..702f478c199b 100644 --- a/WordPress/src/main/res/values-zh-rHK/strings.xml +++ b/WordPress/src/main/res/values-zh-rHK/strings.xml @@ -1,11 +1,13 @@ + 正在等待連線 + 流量 離線作業 重新建立網路連線 網路連線中斷,離線作業 @@ -405,6 +407,7 @@ Language: zh_TW 過去 7 天 %d 週 1 週 + 來自 <b>Day One</b> 稍後再提醒我 「統計資料」、「閱讀器」、「通知」及其他功能即將搬遷至 Jetpack 行動應用程式。 切換至 Jetpack 應用程式 diff --git a/WordPress/src/main/res/values-zh-rTW/strings.xml b/WordPress/src/main/res/values-zh-rTW/strings.xml index b15514a48548..702f478c199b 100644 --- a/WordPress/src/main/res/values-zh-rTW/strings.xml +++ b/WordPress/src/main/res/values-zh-rTW/strings.xml @@ -1,11 +1,13 @@ + 正在等待連線 + 流量 離線作業 重新建立網路連線 網路連線中斷,離線作業 @@ -405,6 +407,7 @@ Language: zh_TW 過去 7 天 %d 週 1 週 + 來自 <b>Day One</b> 稍後再提醒我 「統計資料」、「閱讀器」、「通知」及其他功能即將搬遷至 Jetpack 行動應用程式。 切換至 Jetpack 應用程式 From 3b84931bf634cd50d61722305707931383bf623d Mon Sep 17 00:00:00 2001 From: Automattic Release Bot Date: Fri, 26 Jan 2024 20:28:15 +0000 Subject: [PATCH 068/176] Bump version number --- version.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.properties b/version.properties index 677e9c3a4ea9..b05a338ca1af 100644 --- a/version.properties +++ b/version.properties @@ -1,2 +1,2 @@ -versionName=24.1-rc-2 -versionCode=1404 +versionName=24.1-rc-3 +versionCode=1405 \ No newline at end of file From 6a3da3e85162e6636e6a2e8b10687a42e459fa74 Mon Sep 17 00:00:00 2001 From: Renan Lukas <14964993+RenanLukas@users.noreply.github.com> Date: Fri, 26 Jan 2024 17:53:55 -0300 Subject: [PATCH 069/176] Add Followed P2s item do Reader dropdown menu --- .../ui/reader/tracker/ReaderTracker.kt | 1 + .../ui/reader/utils/ReaderTopBarMenuHelper.kt | 13 +++++++++++ .../utils/ReaderTopBarMenuHelperTest.kt | 23 ++++++++++++++----- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/tracker/ReaderTracker.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/tracker/ReaderTracker.kt index 15822295422c..b40dfc0380ee 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/tracker/ReaderTracker.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/tracker/ReaderTracker.kt @@ -388,6 +388,7 @@ class ReaderTracker @Inject constructor( readerTag.isPostsILike -> "liked" readerTag.isA8C -> "a8c" readerTag.isListTopic -> "list" + readerTag.isP2 -> "p2" else -> null }?.let { trackingId -> analyticsTrackerWrapper.track( diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelper.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelper.kt index 05f6f28d8c1b..26e2f876a83c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelper.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelper.kt @@ -31,6 +31,12 @@ class ReaderTopBarMenuHelper @Inject constructor() { readerTagsList.indexOrNull { it.isA8C }?.let { a8cIndex -> add(createAutomatticItem(getMenuItemIdFromReaderTagIndex(a8cIndex))) } + readerTagsList.indexOrNull { it.isP2 }?.let { followedP2sIndex -> + add(createFollowedP2sItem( + id = getMenuItemIdFromReaderTagIndex(followedP2sIndex), + text = readerTagsList[followedP2sIndex].tagTitle, + )) + } readerTagsList .foldIndexed(SparseArrayCompat()) { index, sparseArray, readerTag -> if (readerTag.tagType == ReaderTagType.CUSTOM_LIST) { @@ -85,6 +91,13 @@ class ReaderTopBarMenuHelper @Inject constructor() { ) } + private fun createFollowedP2sItem(id: String, text: String): MenuElementData.Item.Single { + return MenuElementData.Item.Single( + id = id, + text = UiString.UiStringText(text), + ) + } + private fun createCustomListsItem(customLists: SparseArrayCompat): MenuElementData.Item.SubMenu { val customListsMenuItems = mutableListOf() customLists.forEach { index, readerTag -> diff --git a/WordPress/src/test/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelperTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelperTest.kt index b8a4180dff9d..0279f25bee2d 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelperTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelperTest.kt @@ -23,9 +23,10 @@ class ReaderTopBarMenuHelperTest { add(mockSavedTag()) // item 2 add(mockLikedTag()) // item 3 add(mockA8CTag()) // item 4 - add(createCustomListTag("custom-list-1")) // item 5 - add(createCustomListTag("custom-list-2")) // item 6 - add(createCustomListTag("custom-list-3")) // item 7 + add(mockFollowedP2sTag()) // item 5 + add(createCustomListTag("custom-list-1")) // item 6 + add(createCustomListTag("custom-list-2")) // item 7 + add(createCustomListTag("custom-list-3")) // item 8 } val menu = helper.createMenu(tags) @@ -46,18 +47,21 @@ class ReaderTopBarMenuHelperTest { val a8cItem = menu.findSingleItem { it.id == "4" }!! assertThat(a8cItem.text).isEqualTo(UiStringRes(R.string.reader_dropdown_menu_automattic)) + val followedP2sItem = menu.findSingleItem { it.id == "5" }!! + assertThat(followedP2sItem.text).isEqualTo(UiStringText("Followed P2s")) + assertThat(menu).contains(MenuElementData.Divider) val customListsItem = menu.findSubMenu()!! assertThat(customListsItem.text).isEqualTo(UiStringRes(R.string.reader_dropdown_menu_lists)) - val customList1Item = customListsItem.children.findSingleItem { it.id == "5" }!! + val customList1Item = customListsItem.children.findSingleItem { it.id == "6" }!! assertThat(customList1Item.text).isEqualTo(UiStringText("custom-list-1")) - val customList2Item = customListsItem.children.findSingleItem { it.id == "6" }!! + val customList2Item = customListsItem.children.findSingleItem { it.id == "7" }!! assertThat(customList2Item.text).isEqualTo(UiStringText("custom-list-2")) - val customList3Item = customListsItem.children.findSingleItem { it.id == "7" }!! + val customList3Item = customListsItem.children.findSingleItem { it.id == "8" }!! assertThat(customList3Item.text).isEqualTo(UiStringText("custom-list-3")) } @@ -264,6 +268,13 @@ class ReaderTopBarMenuHelperTest { } } + private fun mockFollowedP2sTag(): ReaderTag { + return mock { + on { isP2 } doReturn true + on { tagTitle } doReturn "Followed P2s" + } + } + private fun createCustomListTag(title: String): ReaderTag { return ReaderTag( title, From 3375148372cfc1a8add27945624b24a4852840fc Mon Sep 17 00:00:00 2001 From: Andy Valdez Date: Fri, 26 Jan 2024 17:10:01 -0500 Subject: [PATCH 070/176] [Lib] Bump fluxc to 2.64.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bad2fe1751d9..ebd7a9c3a9d9 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ ext { automatticTracksVersion = '3.3.0' gutenbergMobileVersion = 'v1.111.1' wordPressAztecVersion = 'v2.0' - wordPressFluxCVersion = '2.61.0' + wordPressFluxCVersion = '2.64.0' wordPressLoginVersion = '1.10.0' wordPressPersistentEditTextVersion = '1.0.2' wordPressUtilsVersion = '3.12.0' From c21a0de61a37a69b87943c4767d02b43f09c2fcb Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Sat, 27 Jan 2024 19:17:02 -0500 Subject: [PATCH 071/176] Refactor: Update the webClient methods, add onTabSelected and adjust loadViews to handle a single or all types --- .../sitemonitor/SiteMonitorParentViewModel.kt | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 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 b691949c07a0..ef09fe2a216d 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 @@ -40,16 +40,23 @@ class SiteMonitorParentViewModel @Inject constructor( loadViews() } - private fun loadViews() { - SiteMonitorType.entries.forEach { type -> - postUiState(type, SiteMonitorUiState.Preparing) + private fun loadViews(siteMonitorType: SiteMonitorType? = null) { + if (siteMonitorType != null) { + loadIndividualView(siteMonitorType) + return + } + + SiteMonitorType.entries.forEach { type -> loadIndividualView(type) } + } - if (!checkForInternetConnectivityAndPostErrorIfNeeded(type)) return@forEach + private fun loadIndividualView(siteMonitorType: SiteMonitorType) { + postUiState(siteMonitorType, SiteMonitorUiState.Preparing) - if (!validateAndPostErrorIfNeeded(type)) return@forEach + if (!checkForInternetConnectivityAndPostErrorIfNeeded(siteMonitorType)) return - assembleAndShowSiteMonitor(type) - } + if (!validateAndPostErrorIfNeeded(siteMonitorType)) return + + assembleAndShowSiteMonitor(siteMonitorType) } private fun assembleAndShowSiteMonitor(type: SiteMonitorType) { @@ -94,7 +101,7 @@ class SiteMonitorParentViewModel @Inject constructor( private fun checkForInternetConnectivityAndPostErrorIfNeeded(type: SiteMonitorType) : Boolean { if (networkUtilsWrapper.isNetworkAvailable()) return true postUiState(type, mapper.toNoNetworkError(this@SiteMonitorParentViewModel::loadViews)) - return false + return false } private fun validateAndPostErrorIfNeeded(type: SiteMonitorType): Boolean { @@ -114,17 +121,17 @@ class SiteMonitorParentViewModel @Inject constructor( } fun onUrlLoaded(url: String) { - val currentState = _uiStates.value val type = siteMonitorUtils.urlToType(url) - val updatedState = currentState + (type to SiteMonitorUiState.Loaded) - _uiStates.value = updatedState + postUiState(type, SiteMonitorUiState.Loaded) } fun onWebViewError(url: String) { - val currentState = _uiStates.value val type = siteMonitorUtils.urlToType(url) - val updatedState = currentState + (type to mapper.toGenericError(this@SiteMonitorParentViewModel::loadViews)) - _uiStates.value = updatedState + postUiState(type, mapper.toGenericError(this@SiteMonitorParentViewModel::loadViews)) + } + + fun onTabSelected(siteMonitorType: SiteMonitorType?) { + loadViews(siteMonitorType) } companion object { From 09d2aa4fd6508f88c85b9e81702820fd62d203e7 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Sat, 27 Jan 2024 19:18:33 -0500 Subject: [PATCH 072/176] [WIP] Separate WebView composables by type, send onTabSelected back to webview for a state update. --- .../sitemonitor/SiteMonitorParentActivity.kt | 153 ++++++++++++++++-- 1 file changed, 142 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 3c1537d45533..3bae47007aa0 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 @@ -15,7 +15,10 @@ 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.layout.size +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.Button +import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold import androidx.compose.material.TabRow @@ -44,7 +47,6 @@ 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.ui.main.jetpack.migration.compose.state.LoadingState import org.wordpress.android.ui.sitemonitor.SiteMonitorWebViewClient.SiteMonitorWebViewClientListener import org.wordpress.android.util.extensions.getSerializableExtraCompat @@ -54,7 +56,7 @@ class SiteMonitorParentActivity: AppCompatActivity(), SiteMonitorWebViewClientLi override fun onWebViewReceivedError(url: String) = viewModel.onWebViewError(url) -val viewModel:SiteMonitorParentViewModel by viewModels() + val viewModel:SiteMonitorParentViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -115,21 +117,73 @@ val viewModel:SiteMonitorParentViewModel by viewModels() tabs.forEachIndexed { index, title -> Tab(text = { Text(stringResource(id = title)) }, selected = tabIndex == index, - onClick = { tabIndex = index } + onClick = { + tabIndex = index + viewModel.onTabSelected(tabsToType[index]) + } ) } } - val uiState = uiStates[tabsToType[tabIndex]] as SiteMonitorUiState - SiteMonitoringWebViewForTab(uiState) + val siteMonitorType = tabsToType[tabIndex] ?: SiteMonitorType.METRICS + val uiState = uiStates[siteMonitorType] as SiteMonitorUiState + when(siteMonitorType) { + SiteMonitorType.METRICS -> SiteMonitoringWebViewForMetric(uiState) + SiteMonitorType.PHP_LOGS -> SiteMonitoringWebViewForTabPhp(uiState) + SiteMonitorType.WEB_SERVER_LOGS -> SiteMonitoringWebViewForTabWeb(uiState) + } } } @Composable - fun SiteMonitoringWebViewForTab(uiState: SiteMonitorUiState) { - when (uiState) { - is SiteMonitorUiState.Preparing -> LoadingState() - is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitoringWebView(uiState) - is SiteMonitorUiState.Error -> SiteMonitorError(uiState) + fun SiteMonitoringWebViewForMetric(uiState: SiteMonitorUiState) { + LazyColumn { + item { + when (uiState) { + is SiteMonitorUiState.Preparing -> LoadingState() + is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitoringWebViewMetric(uiState) + is SiteMonitorUiState.Error -> SiteMonitorError(uiState) + } + } + } + } + + @SuppressLint("SetJavaScriptEnabled") + @Composable + fun SiteMonitoringWebViewMetric(uiState: SiteMonitorUiState) { + var webView: WebView? by remember { mutableStateOf(null) } + + if (uiState is SiteMonitorUiState.Prepared) { + val model = uiState.model + 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) + postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, model.addressToLoad.toByteArray()) + } + } + } + + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + if (uiState is SiteMonitorUiState.Prepared) { + LoadingState() + } else { + webView?.let { theWebView -> + AndroidView( + factory = { theWebView }, + modifier = Modifier.fillMaxSize() + ) + } + } } } @@ -164,9 +218,73 @@ val viewModel:SiteMonitorParentViewModel by viewModels() } } } + @Composable + fun SiteMonitoringWebViewForTabPhp(uiState: SiteMonitorUiState) { + LazyColumn { + item { + when (uiState) { + is SiteMonitorUiState.Preparing -> LoadingState() + is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitoringWebViewPhp(uiState) + is SiteMonitorUiState.Error -> SiteMonitorError(uiState) + } + } + } + } + @SuppressLint("SetJavaScriptEnabled") + @Composable + fun SiteMonitoringWebViewPhp(uiState: SiteMonitorUiState) { + var webView: WebView? by remember { mutableStateOf(null) } + + if (uiState is SiteMonitorUiState.Prepared) { + val model = uiState.model + 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) + postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, model.addressToLoad.toByteArray()) + } + } + } + + 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 SiteMonitoringWebViewForTabWeb(uiState: SiteMonitorUiState) { + LazyColumn { + item { + when (uiState) { + is SiteMonitorUiState.Preparing -> LoadingState() + is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitoringWebViewWeb(uiState) + is SiteMonitorUiState.Error -> SiteMonitorError(uiState) + } + } + } + } @SuppressLint("SetJavaScriptEnabled") @Composable - fun SiteMonitoringWebView(uiState: SiteMonitorUiState) { + fun SiteMonitoringWebViewWeb(uiState: SiteMonitorUiState) { var webView: WebView? by remember { mutableStateOf(null) } if (uiState is SiteMonitorUiState.Prepared) { @@ -203,4 +321,17 @@ val viewModel:SiteMonitorParentViewModel by viewModels() } } } + + @Composable + fun LoadingState() { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxSize() + ) { + CircularProgressIndicator( + modifier = Modifier.size(48.dp).fillMaxSize() + ) + Text(text = "Loading...", modifier = Modifier.padding(top = 8.dp)) + } + } } From a7a5b4b030875c1118c50eb81a1eccfe6352a9e1 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Sun, 28 Jan 2024 17:21:35 -0500 Subject: [PATCH 073/176] Add enum class for each site monitor tab --- .../ui/sitemonitor/SiteMonitorTabItem.kt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabItem.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabItem.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabItem.kt new file mode 100644 index 000000000000..5940fd224375 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabItem.kt @@ -0,0 +1,34 @@ +package org.wordpress.android.ui.sitemonitor + +import androidx.annotation.StringRes +import org.wordpress.android.R + +const val METRICS_URL_TEMPLATE = "https://wordpress.com/site-monitoring/{blog}" +const val PHPLOGS_URL_TEMPLATE = "https://wordpress.com/site-monitoring/{blog}/php" +const val WEBSERVERLOGS_URL_TEMPLATE = "https://wordpress.com/site-monitoring/{blog}/web" + +enum class SiteMonitorTabItem( + val route: String, + @StringRes val title: Int, + val urlTemplate: String, + val siteMonitorType: SiteMonitorType +) { + Metrics( + "metrics", + R.string.site_monitoring_tab_title_metrics, + METRICS_URL_TEMPLATE, + SiteMonitorType.METRICS + ), + PHPLogs( + "phplogs", + R.string.site_monitoring_tab_title_php_logs, + PHPLOGS_URL_TEMPLATE, + SiteMonitorType.PHP_LOGS + ), + WebServerLogs( + "webserverlogs", + R.string.site_monitoring_tab_title_web_server_logs, + WEBSERVERLOGS_URL_TEMPLATE, + SiteMonitorType.WEB_SERVER_LOGS + ); +} From b457da1594c961b0074e950b63d5f23467c9c2c0 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Sun, 28 Jan 2024 17:22:28 -0500 Subject: [PATCH 074/176] Add a container to host the fragment for each tab --- .../SiteMonitorFragmentContainer.kt | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorFragmentContainer.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 new file mode 100644 index 000000000000..eb5eea65c8a1 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorFragmentContainer.kt @@ -0,0 +1,76 @@ +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) + } + } + } + } +} From 2bfdb36602d8cadf642cabe596106885e8ec47b8 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Sun, 28 Jan 2024 17:26:58 -0500 Subject: [PATCH 075/176] Add placeholder method to track tab loaded. There is a todo here --- .../wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt | 6 ++++++ 1 file changed, 6 insertions(+) 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 dbaa7b25cebd..f4e7fe8c098d 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 @@ -1,5 +1,6 @@ package org.wordpress.android.ui.sitemonitor +import android.util.Log import org.wordpress.android.WordPress import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.ui.WPWebViewActivity @@ -33,6 +34,11 @@ class SiteMonitorUtils @Inject constructor( } } + fun trackTabLoaded(siteMonitorType: SiteMonitorType) { + // todo: need to set this up properly with track events + Log.i(javaClass.simpleName, "track TabLoaded with $siteMonitorType") + } + companion object { const val HTTP_PATTERN = "(https?://)" const val PHP_LOGS_PATTERN = "/php" From d6329cf27d677b2c1bf3db560117a96c9f4f0b64 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Sun, 28 Jan 2024 17:28:10 -0500 Subject: [PATCH 076/176] Add a composable to hold the current screen so we can go back and restore state on tab to tab --- .../sitemonitor/SiteMonitorTabNavigation.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create 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 new file mode 100644 index 000000000000..023e651a66d5 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabNavigation.kt @@ -0,0 +1,20 @@ +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 869251a8fa6b2731588de4ab701b82994d3d8ad6 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Sun, 28 Jan 2024 17:29:00 -0500 Subject: [PATCH 077/176] Add a composable for the site monitor tab header --- .../ui/sitemonitor/SiteMonitorTabHeader.kt | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create 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/SiteMonitorTabHeader.kt b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabHeader.kt new file mode 100644 index 000000000000..1bf493f7c49d --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabHeader.kt @@ -0,0 +1,51 @@ +package org.wordpress.android.ui.sitemonitor + +import androidx.compose.foundation.layout.Column +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Tab +import androidx.compose.material3.TabRow +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.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.sp + +@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.colorScheme.surface, + contentColor = MaterialTheme.colorScheme.onSurface, + ) { + tabs.forEachIndexed { index, item -> + Tab( + text = { + Column (horizontalAlignment = Alignment.CenterHorizontally) { + Text( + text = stringResource(item.title), + fontSize = 12.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + }, + selected = selectedTabIndex == index, + onClick = { + selectedTabIndex = index + navController(item.route) + }, + ) + } + } +} From 3cabeb3bb4693d383b2b2dbcb6cda0267d406bca Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Sun, 28 Jan 2024 17:30:13 -0500 Subject: [PATCH 078/176] Add fragment and viewmodel pair that will host the webview for each tab. --- .../ui/sitemonitor/SiteMonitorTabFragment.kt | 184 ++++++++++++++++++ .../ui/sitemonitor/SiteMonitorTabViewModel.kt | 120 ++++++++++++ 2 files changed, 304 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabFragment.kt create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt 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 new file mode 100644 index 000000000000..27fbf39c3f12 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabFragment.kt @@ -0,0 +1,184 @@ +package org.wordpress.android.ui.sitemonitor + +import android.annotation.SuppressLint +import android.os.Bundle +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.collectAsState +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.viewModels +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 { + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View = ComposeView(requireContext()).apply { + setContent { + TheContent() + } + } + + private val viewModel: SiteMonitorTabViewModel by viewModels() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initViewModel(getSiteMonitorType(), getUrlTemplate(), getSite()) + } + + @Suppress("DEPRECATION") + private fun getSite(): SiteModel { + return requireNotNull(arguments?.getSerializable(WordPress.SITE)) as SiteModel + } + + private fun getUrlTemplate(): String { + return requireNotNull(arguments?.getString(KEY_URL_TEMPLATE)) + } + + @Suppress("DEPRECATION") + private fun getSiteMonitorType(): SiteMonitorType { + 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 onWebViewReceivedError(url: String) = viewModel.onWebViewError() + + 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 TheContent() { + val uiState by viewModel.uiState.collectAsState() + when (uiState) { + is SiteMonitorUiState.Preparing -> LoadingState() + is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> TheWebView(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 TheWebView(uiState: SiteMonitorUiState) { + var webView: WebView? by remember { mutableStateOf(null) } + + 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) + postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, model.addressToLoad.toByteArray()) + } + } + } + + 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() + } +} 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 new file mode 100644 index 000000000000..617b984d6f56 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModel.kt @@ -0,0 +1,120 @@ +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 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, + 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 site: SiteModel + private lateinit var siteMonitorType: SiteMonitorType + private lateinit var urlTemplate: String + + private val _uiState = MutableStateFlow(SiteMonitorUiState.Preparing) + val uiState: StateFlow = _uiState + + fun start(type: SiteMonitorType, urlTemplate: String, site: SiteModel) { + Log.i("Track", "TheViewModel start with $urlTemplate and $type") + this.siteMonitorType = type + this.urlTemplate = urlTemplate + this.site = site + + loadView() + } + + private fun loadView() { + postUiState(SiteMonitorUiState.Preparing) + + if (!checkForInternetConnectivityAndPostErrorIfNeeded()) return + + if (!validateAndPostErrorIfNeeded()) return + + assembleAndShowSiteMonitor() + } + + private fun checkForInternetConnectivityAndPostErrorIfNeeded() : Boolean { + if (networkUtilsWrapper.isNetworkAvailable()) return true + postUiState(mapper.toNoNetworkError(this@SiteMonitorTabViewModel::loadView)) + return false + } + + private fun validateAndPostErrorIfNeeded(): Boolean { + if (accountStore.account.userName.isNullOrEmpty() || accountStore.accessToken.isNullOrEmpty()) { + postUiState(mapper.toGenericError(this@SiteMonitorTabViewModel::loadView)) + return false + } + return true + } + + private fun assembleAndShowSiteMonitor() { + val sanitizedUrl = siteMonitorUtils.sanitizeSiteUrl(site.url) + val url = urlTemplate.replace("{blog}", sanitizedUrl) + + val addressToLoad = prepareAddressToLoad(url) + postUiState(mapper.toPrepared(url, addressToLoad, siteMonitorType)) + } + + private fun prepareAddressToLoad(url: String): String { + val username = accountStore.account.userName + val accessToken = accountStore.accessToken + + var addressToLoad = url + + // Custom domains are not properly authenticated due to a server side(?) issue, so this gets around that + if (!addressToLoad.contains(SiteMonitorParentViewModel.WPCOM_DOMAIN)) { + val wpComSites: List = siteStore.wPComSites + for (siteModel in wpComSites) { + // Only replace the url if we know the unmapped url and if it's a custom domain + if (!TextUtils.isEmpty(siteModel.unmappedUrl) + && !siteModel.url.contains(SiteMonitorParentViewModel.WPCOM_DOMAIN) + ) { + addressToLoad = addressToLoad.replace(siteModel.url, siteModel.unmappedUrl) + } + } + } + return siteMonitorUtils.getAuthenticationPostData( + WPCOM_LOGIN_URL, + addressToLoad, + username, + "", + accessToken?:"" + ) + } + + private fun postUiState(state: SiteMonitorUiState) { + launch { + _uiState.value = state + } + } + + fun onUrlLoaded() { + siteMonitorUtils.trackTabLoaded(siteMonitorType) + postUiState(SiteMonitorUiState.Loaded) + } + + fun onWebViewError() { + postUiState(mapper.toGenericError(this@SiteMonitorTabViewModel::loadView)) + } + + companion object { + const val WPCOM_LOGIN_URL = "https://wordpress.com/wp-login.php" + } +} From 195b6792800c5bdd69eece8ba012e789a1906d98 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Sun, 28 Jan 2024 17:32:02 -0500 Subject: [PATCH 079/176] Refactor: Use fragments for tab navigation, eliminate the viewModel, save tab state. --- .../sitemonitor/SiteMonitorParentActivity.kt | 344 ++++-------------- 1 file changed, 69 insertions(+), 275 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 3bae47007aa0..7291b52263ab 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,81 +2,78 @@ package org.wordpress.android.ui.sitemonitor import android.annotation.SuppressLint import android.os.Bundle -import android.view.View -import android.view.ViewGroup -import android.webkit.WebView +import android.util.SparseArray 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.foundation.layout.size -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material.Button -import androidx.compose.material.CircularProgressIndicator -import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold -import androidx.compose.material.TabRow -import androidx.compose.material.Text -import androidx.compose.material3.Tab +import androidx.compose.material3.Surface import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState 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.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.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.ui.sitemonitor.SiteMonitorWebViewClient.SiteMonitorWebViewClientListener import org.wordpress.android.util.extensions.getSerializableExtraCompat @AndroidEntryPoint -class SiteMonitorParentActivity: AppCompatActivity(), SiteMonitorWebViewClientListener { - override fun onWebViewPageLoaded(url: String) = viewModel.onUrlLoaded(url) - - override fun onWebViewReceivedError(url: String) = viewModel.onWebViewError(url) - - val viewModel:SiteMonitorParentViewModel by viewModels() +class SiteMonitorParentActivity: AppCompatActivity() { + private var savedStateSparseArray = SparseArray() + private var currentSelectItemId = 0 + @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + if (savedInstanceState != null) { + savedStateSparseArray = savedInstanceState.getSparseParcelableArray( + SAVED_STATE_CONTAINER_KEY + ) + ?: savedStateSparseArray + currentSelectItemId = savedInstanceState.getInt(SAVED_STATE_CURRENT_TAB_KEY) + } setContent { AppTheme { - viewModel.start(getSite()) - SiteMonitorScreen() + Surface( + modifier = Modifier.fillMaxSize(), + ) { + SiteMonitorScreen() + } } } } + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putSparseParcelableArray(SAVED_STATE_CONTAINER_KEY, savedStateSparseArray) + outState.putInt(SAVED_STATE_CURRENT_TAB_KEY, currentSelectItemId) + } + private fun getSite(): SiteModel { return requireNotNull(intent.getSerializableExtraCompat(WordPress.SITE)) as SiteModel } + companion object { + const val SAVED_STATE_CONTAINER_KEY = "ContainerKey" + const val SAVED_STATE_CURRENT_TAB_KEY = "CurrentTabKey" + } + @Composable @SuppressLint("UnusedMaterialScaffoldPaddingParameter") - fun SiteMonitorScreen(modifier: Modifier = Modifier, - viewModel: SiteMonitorParentViewModel = androidx.lifecycle.viewmodel.compose.viewModel()) { - val uiStates by viewModel.uiStates.collectAsState() + fun SiteMonitorScreen() { + var selectedTab by rememberSaveable { mutableStateOf(SiteMonitorTabItem.Metrics.route) } Scaffold( topBar = { MainTopAppBar( @@ -84,254 +81,51 @@ class SiteMonitorParentActivity: AppCompatActivity(), SiteMonitorWebViewClientLi navigationIcon = NavigationIcons.BackIcon, onNavigationIconClick = onBackPressedDispatcher::onBackPressed, ) - }, - content = { - TabScreen(modifier = modifier, uiStates) - } - ) - } - - @Composable - @SuppressLint("UnusedMaterialScaffoldPaddingParameter") - fun TabScreen(modifier: Modifier = Modifier, uiStates: Map) { - var tabIndex by remember { mutableIntStateOf(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 - ) - - val tabsToType = mapOf( - 0 to SiteMonitorType.METRICS, - 1 to SiteMonitorType.PHP_LOGS, - 2 to SiteMonitorType.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 - viewModel.onTabSelected(tabsToType[index]) - } - ) - } } - val siteMonitorType = tabsToType[tabIndex] ?: SiteMonitorType.METRICS - val uiState = uiStates[siteMonitorType] as SiteMonitorUiState - when(siteMonitorType) { - SiteMonitorType.METRICS -> SiteMonitoringWebViewForMetric(uiState) - SiteMonitorType.PHP_LOGS -> SiteMonitoringWebViewForTabPhp(uiState) - SiteMonitorType.WEB_SERVER_LOGS -> SiteMonitoringWebViewForTabWeb(uiState) - } - } - } - - @Composable - fun SiteMonitoringWebViewForMetric(uiState: SiteMonitorUiState) { - LazyColumn { - item { - when (uiState) { - is SiteMonitorUiState.Preparing -> LoadingState() - is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitoringWebViewMetric(uiState) - is SiteMonitorUiState.Error -> SiteMonitorError(uiState) - } - } - } - } - - @SuppressLint("SetJavaScriptEnabled") - @Composable - fun SiteMonitoringWebViewMetric(uiState: SiteMonitorUiState) { - var webView: WebView? by remember { mutableStateOf(null) } - - if (uiState is SiteMonitorUiState.Prepared) { - val model = uiState.model - 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) - postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, model.addressToLoad.toByteArray()) + ) { padding -> + Column(modifier = Modifier.padding(padding)) { + SiteMonitorTabHeader { clickTab -> + selectedTab = clickTab } - } - } - - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - if (uiState is SiteMonitorUiState.Prepared) { - LoadingState() - } else { - webView?.let { theWebView -> - AndroidView( - factory = { theWebView }, - modifier = Modifier.fillMaxSize() + SiteMonitorTabNavigation(selectedTab) { selectedTab -> + val item = enumValues().find { + it.route == selectedTab + } ?: SiteMonitorTabItem.Metrics + + SiteMonitorFragmentContainer( + modifier = Modifier.fillMaxSize(), + commit = getCommitFunction( + SiteMonitorTabFragment.newInstance(item.urlTemplate, item.siteMonitorType, getSite()), + item.route + ) ) } } } } - @Composable - fun SiteMonitorError(error: SiteMonitorUiState.Error) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = Modifier - .padding(20.dp) - .fillMaxWidth() - .fillMaxHeight(), - ) { - Text( - text = uiStringText(uiString = error.title), - style = MaterialTheme.typography.h5, - textAlign = TextAlign.Center - ) - Text( - text = uiStringText(uiString = error.description), - style = 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)) - } - } - } - } - @Composable - fun SiteMonitoringWebViewForTabPhp(uiState: SiteMonitorUiState) { - LazyColumn { - item { - when (uiState) { - is SiteMonitorUiState.Preparing -> LoadingState() - is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitoringWebViewPhp(uiState) - is SiteMonitorUiState.Error -> SiteMonitorError(uiState) - } - } - } - } - @SuppressLint("SetJavaScriptEnabled") - @Composable - fun SiteMonitoringWebViewPhp(uiState: SiteMonitorUiState) { - var webView: WebView? by remember { mutableStateOf(null) } - - if (uiState is SiteMonitorUiState.Prepared) { - val model = uiState.model - 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) - postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, model.addressToLoad.toByteArray()) - } - } - } - - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - if (uiState is SiteMonitorUiState.Prepared) { - LoadingState() - } else { - webView?.let { theWebView -> - AndroidView( - factory = { theWebView }, - modifier = Modifier.fillMaxSize() - ) - } - } + private fun getCommitFunction( + fragment : Fragment, + tag: String + ): FragmentTransaction.(containerId: Int) -> Unit = + { + saveAndRetrieveFragment(supportFragmentManager, it, fragment) + replace(it, fragment, tag) } - } - @Composable - fun SiteMonitoringWebViewForTabWeb(uiState: SiteMonitorUiState) { - LazyColumn { - item { - when (uiState) { - is SiteMonitorUiState.Preparing -> LoadingState() - is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitoringWebViewWeb(uiState) - is SiteMonitorUiState.Error -> SiteMonitorError(uiState) - } - } - } - } - @SuppressLint("SetJavaScriptEnabled") - @Composable - fun SiteMonitoringWebViewWeb(uiState: SiteMonitorUiState) { - var webView: WebView? by remember { mutableStateOf(null) } - - if (uiState is SiteMonitorUiState.Prepared) { - val model = uiState.model - 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) - postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, model.addressToLoad.toByteArray()) - } - } - } - - 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() { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier.fillMaxSize() - ) { - CircularProgressIndicator( - modifier = Modifier.size(48.dp).fillMaxSize() + private fun saveAndRetrieveFragment( + supportFragmentManager: FragmentManager, + tabId: Int, + fragment: Fragment + ) { + val currentFragment = supportFragmentManager.findFragmentById(currentSelectItemId) + if (currentFragment != null) { + savedStateSparseArray.put( + currentSelectItemId, + supportFragmentManager.saveFragmentInstanceState(currentFragment) ) - Text(text = "Loading...", modifier = Modifier.padding(top = 8.dp)) } + currentSelectItemId = tabId + fragment.setInitialSavedState(savedStateSparseArray[currentSelectItemId]) } } From fd628cbc00482170f5559b492ef32dc9aed5a8c9 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Sun, 28 Jan 2024 17:35:46 -0500 Subject: [PATCH 080/176] Refactor: remove references to SiteMonitorParentViewModel --- .../android/ui/sitemonitor/SiteMonitorTabViewModel.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 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 617b984d6f56..aaae3507f424 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 @@ -79,12 +79,12 @@ class SiteMonitorTabViewModel @Inject constructor( var addressToLoad = url // Custom domains are not properly authenticated due to a server side(?) issue, so this gets around that - if (!addressToLoad.contains(SiteMonitorParentViewModel.WPCOM_DOMAIN)) { + if (!addressToLoad.contains(WPCOM_DOMAIN)) { val wpComSites: List = siteStore.wPComSites for (siteModel in wpComSites) { // Only replace the url if we know the unmapped url and if it's a custom domain if (!TextUtils.isEmpty(siteModel.unmappedUrl) - && !siteModel.url.contains(SiteMonitorParentViewModel.WPCOM_DOMAIN) + && !siteModel.url.contains(WPCOM_DOMAIN) ) { addressToLoad = addressToLoad.replace(siteModel.url, siteModel.unmappedUrl) } @@ -116,5 +116,6 @@ class SiteMonitorTabViewModel @Inject constructor( companion object { const val WPCOM_LOGIN_URL = "https://wordpress.com/wp-login.php" + const val WPCOM_DOMAIN = ".wordpress.com" } } From aa95c501e3dfdb1ba149a7d2447f68d7eb13210b Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Sun, 28 Jan 2024 17:35:55 -0500 Subject: [PATCH 081/176] Delete classes --- .../sitemonitor/SiteMonitorParentViewModel.kt | 141 ------------------ .../SiteMonitorParentViewModelTest.kt | 36 ----- 2 files changed, 177 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt delete mode 100644 WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModelTest.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 deleted file mode 100644 index ef09fe2a216d..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModel.kt +++ /dev/null @@ -1,141 +0,0 @@ -package org.wordpress.android.ui.sitemonitor - -import android.text.TextUtils -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -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 SiteMonitorParentViewModel @Inject constructor( - @param:Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, - 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 site: SiteModel - - private val metricUrlTemplate = "https://wordpress.com/site-monitoring/{blog}" - private val phpLogsUrlTemplate = "https://wordpress.com/site-monitoring/{blog}/php" - private val webServerLogsUrlTemplate = "https://wordpress.com/site-monitoring/{blog}/web" - - private val _uiStates = MutableStateFlow>(emptyMap()) - val uiStates: StateFlow> = _uiStates - - - fun start(site: SiteModel) { - this.site = site - siteMonitorUtils.trackActivityLaunched() - - loadViews() - } - - private fun loadViews(siteMonitorType: SiteMonitorType? = null) { - if (siteMonitorType != null) { - loadIndividualView(siteMonitorType) - return - } - - SiteMonitorType.entries.forEach { type -> loadIndividualView(type) } - } - - private fun loadIndividualView(siteMonitorType: SiteMonitorType) { - postUiState(siteMonitorType, SiteMonitorUiState.Preparing) - - if (!checkForInternetConnectivityAndPostErrorIfNeeded(siteMonitorType)) return - - if (!validateAndPostErrorIfNeeded(siteMonitorType)) return - - assembleAndShowSiteMonitor(siteMonitorType) - } - - private fun assembleAndShowSiteMonitor(type: SiteMonitorType) { - val sanitizedUrl = siteMonitorUtils.sanitizeSiteUrl(site.url) - val url = when (type) { - SiteMonitorType.METRICS -> metricUrlTemplate - SiteMonitorType.PHP_LOGS -> phpLogsUrlTemplate - SiteMonitorType.WEB_SERVER_LOGS -> webServerLogsUrlTemplate - }.replace("{blog}", sanitizedUrl) - - val addressToLoad = prepareAddressToLoad(url) - val uiState = mapper.toPrepared(url, addressToLoad, type) - postUiState(type, uiState) - } - - private fun prepareAddressToLoad(url: String): String { - val username = accountStore.account.userName - val accessToken = accountStore.accessToken - - var addressToLoad = url - - // Custom domains are not properly authenticated due to a server side(?) issue, so this gets around that - if (!addressToLoad.contains(WPCOM_DOMAIN)) { - val wpComSites: List = siteStore.wPComSites - for (siteModel in wpComSites) { - // Only replace the url if we know the unmapped url and if it's a custom domain - if (!TextUtils.isEmpty(siteModel.unmappedUrl) - && !siteModel.url.contains(WPCOM_DOMAIN) - ) { - addressToLoad = addressToLoad.replace(siteModel.url, siteModel.unmappedUrl) - } - } - } - return siteMonitorUtils.getAuthenticationPostData( - WPCOM_LOGIN_URL, - addressToLoad, - username, - "", - accessToken?:"" - ) - } - private fun checkForInternetConnectivityAndPostErrorIfNeeded(type: SiteMonitorType) : Boolean { - if (networkUtilsWrapper.isNetworkAvailable()) return true - postUiState(type, mapper.toNoNetworkError(this@SiteMonitorParentViewModel::loadViews)) - return false - } - - private fun validateAndPostErrorIfNeeded(type: SiteMonitorType): Boolean { - if (accountStore.account.userName.isNullOrEmpty() || accountStore.accessToken.isNullOrEmpty()) { - postUiState(type, mapper.toGenericError(this@SiteMonitorParentViewModel::loadViews)) - return false - } - return true - } - - private fun postUiState(type: SiteMonitorType, uiState: SiteMonitorUiState) { - launch { - _uiStates.value = _uiStates.value.toMutableMap().apply { - this[type] = uiState - } - } - } - - fun onUrlLoaded(url: String) { - val type = siteMonitorUtils.urlToType(url) - postUiState(type, SiteMonitorUiState.Loaded) - } - - fun onWebViewError(url: String) { - val type = siteMonitorUtils.urlToType(url) - postUiState(type, mapper.toGenericError(this@SiteMonitorParentViewModel::loadViews)) - } - - fun onTabSelected(siteMonitorType: SiteMonitorType?) { - loadViews(siteMonitorType) - } - - companion object { - const val WPCOM_LOGIN_URL = "https://wordpress.com/wp-login.php" - const val WPCOM_DOMAIN = ".wordpress.com" - } -} 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 deleted file mode 100644 index 7f2031d8b1c5..000000000000 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModelTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.wordpress.android.ui.sitemonitor - -import kotlinx.coroutines.ExperimentalCoroutinesApi -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.mock -import org.mockito.kotlin.verify -import org.wordpress.android.BaseUnitTest -import org.wordpress.android.analytics.AnalyticsTracker -import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper - -@ExperimentalCoroutinesApi -@RunWith(MockitoJUnitRunner::class) -class SiteMonitorParentViewModelTest: BaseUnitTest(){ - @Mock - private lateinit var analyticsTrackerWrapper: AnalyticsTrackerWrapper - - private lateinit var viewModel: SiteMonitorParentViewModel - - @Before - fun setUp() { - viewModel = SiteMonitorParentViewModel(testDispatcher(), analyticsTrackerWrapper) - } - - @Test - fun `when viewmodel is started, then screen shown tracking is done`() { - val site = mock() - viewModel.start(site) - - verify(analyticsTrackerWrapper).track(AnalyticsTracker.Stat.SITE_MONITORING_SCREEN_SHOWN) - } -} From 9b85571d04b0d13610c7030f48aba2ffd58184b4 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Mon, 29 Jan 2024 12:17:38 +0530 Subject: [PATCH 082/176] * Renames: Content to SiteMonitorTabContent --- .../android/ui/sitemonitor/SiteMonitorTabFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 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 27fbf39c3f12..c0cf2b9db50c 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 @@ -43,7 +43,7 @@ class SiteMonitorTabFragment : Fragment(), SiteMonitorWebViewClient.SiteMonitorW savedInstanceState: Bundle? ): View = ComposeView(requireContext()).apply { setContent { - TheContent() + SiteMonitorTabContent() } } @@ -91,7 +91,7 @@ class SiteMonitorTabFragment : Fragment(), SiteMonitorWebViewClient.SiteMonitorW } @Composable - private fun TheContent() { + private fun SiteMonitorTabContent() { val uiState by viewModel.uiState.collectAsState() when (uiState) { is SiteMonitorUiState.Preparing -> LoadingState() From 9362ef000e96538e21fe2499c4f3af92c0a4751a Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Mon, 29 Jan 2024 12:17:56 +0530 Subject: [PATCH 083/176] * Renames: WebView to SiteMonitorWebView --- .../android/ui/sitemonitor/SiteMonitorTabFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 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 c0cf2b9db50c..8fb61cc8ed03 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 @@ -95,7 +95,7 @@ class SiteMonitorTabFragment : Fragment(), SiteMonitorWebViewClient.SiteMonitorW val uiState by viewModel.uiState.collectAsState() when (uiState) { is SiteMonitorUiState.Preparing -> LoadingState() - is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> TheWebView(uiState) + is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> SiteMonitorWebView(uiState) is SiteMonitorUiState.Error -> SiteMonitorError(uiState as SiteMonitorUiState.Error) } } @@ -134,7 +134,7 @@ class SiteMonitorTabFragment : Fragment(), SiteMonitorWebViewClient.SiteMonitorW @SuppressLint("SetJavaScriptEnabled") @Composable - private fun TheWebView(uiState: SiteMonitorUiState) { + private fun SiteMonitorWebView(uiState: SiteMonitorUiState) { var webView: WebView? by remember { mutableStateOf(null) } if (uiState is SiteMonitorUiState.Prepared) { From 1b254adc28ed06e4266ff21e74f95c73dd573d02 Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Mon, 29 Jan 2024 20:55:04 +0300 Subject: [PATCH 084/176] 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 085/176] 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 08b7dbfd196c09d28551532e9e9fe5fef76dd4b9 Mon Sep 17 00:00:00 2001 From: Andy Valdez Date: Mon, 29 Jan 2024 13:12:16 -0500 Subject: [PATCH 086/176] [Lib] Bump Login-Flow library from 1.10 to 1.11 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 48b97e4000ad..284bcf07204d 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ ext { gutenbergMobileVersion = 'v1.112.0-alpha3' wordPressAztecVersion = 'v2.0' wordPressFluxCVersion = '2.64.0' - wordPressLoginVersion = '1.10.0' + wordPressLoginVersion = '1.11.0' wordPressPersistentEditTextVersion = '1.0.2' wordPressUtilsVersion = '3.12.0' indexosMediaForMobileVersion = '43a9026f0973a2f0a74fa813132f6a16f7499c3a' From 6ba2cc286d43a83c01fb7175358d450325e39b56 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Mon, 29 Jan 2024 14:22:12 -0500 Subject: [PATCH 087/176] Add event for OPENED_SITE_MONITORING from app link --- .../java/org/wordpress/android/analytics/AnalyticsTracker.java | 3 ++- .../wordpress/android/analytics/AnalyticsTrackerNosara.java | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) 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 766cd5e3e775..ba65e2e228ea 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 @@ -1101,7 +1101,8 @@ public enum Stat { DYNAMIC_DASHBOARD_CARD_CTA_TAPPED, DYNAMIC_DASHBOARD_CARD_HIDE_TAPPED, DEEP_LINK_FAILED, - SITE_MONITORING_SCREEN_SHOWN + SITE_MONITORING_SCREEN_SHOWN, + OPENED_SITE_MONITORING, } 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 96eb82eefa83..6a83354fe74d 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 @@ -2697,6 +2697,8 @@ public static String getEventNameForStat(AnalyticsTracker.Stat stat) { return "deep_link_failed"; case SITE_MONITORING_SCREEN_SHOWN: return "site_monitoring_screen_shown"; + case OPENED_SITE_MONITORING: + return "opened_site_monitoring"; } return null; } From a6633b00261981ac5ca022bf10046068a8ab248e Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Mon, 29 Jan 2024 14:23:19 -0500 Subject: [PATCH 088/176] Add site-monitoring app link support. Fix miss in media https scheme --- WordPress/src/main/AndroidManifest.xml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/AndroidManifest.xml b/WordPress/src/main/AndroidManifest.xml index edba81e6e442..f2186cac8386 100644 --- a/WordPress/src/main/AndroidManifest.xml +++ b/WordPress/src/main/AndroidManifest.xml @@ -482,13 +482,23 @@ + android:scheme="https" /> + + + + From 3a3247498797aabb602432850df5854986a89632 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Mon, 29 Jan 2024 14:24:00 -0500 Subject: [PATCH 089/176] Add navigation action OpenSiteMonitoringForSite and handle it --- .../wordpress/android/ui/deeplinks/DeepLinkNavigator.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/DeepLinkNavigator.kt b/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/DeepLinkNavigator.kt index 58b2598d1c40..470f6f149669 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/DeepLinkNavigator.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/DeepLinkNavigator.kt @@ -27,6 +27,7 @@ import org.wordpress.android.ui.deeplinks.DeepLinkNavigator.NavigateAction.ShowS import org.wordpress.android.ui.deeplinks.DeepLinkNavigator.NavigateAction.StartCreateSiteFlow import org.wordpress.android.ui.deeplinks.DeepLinkNavigator.NavigateAction.ViewPostInReader import org.wordpress.android.ui.sitecreation.misc.SiteCreationSource.DEEP_LINK +import org.wordpress.android.ui.sitemonitor.SiteMonitorType import org.wordpress.android.ui.stats.StatsTimeframe import org.wordpress.android.util.UriWrapper import javax.inject.Inject @@ -91,6 +92,11 @@ class DeepLinkNavigator navigateAction.site ) NavigateAction.DomainManagement -> ActivityLauncher.openDomainManagement(activity) + is NavigateAction.OpenSiteMonitoringForSite -> activityNavigator.openSiteMonitoringInNewStack( + activity, + navigateAction.site, + navigateAction.siteMonitorType + ) } if (navigateAction != LoginForResult) { activity.finish() @@ -126,5 +132,7 @@ class DeepLinkNavigator object OpenMedia : NavigateAction() data class OpenMediaPickerForSite(val site: SiteModel) : NavigateAction() object DomainManagement : NavigateAction() + data class OpenSiteMonitoringForSite(val site: SiteModel?, val siteMonitorType: SiteMonitorType) : + NavigateAction() } } From ac734290bb569751c83d450367f7427df585c5bd Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Mon, 29 Jan 2024 14:24:27 -0500 Subject: [PATCH 090/176] Add helper for open site monitoring in a new stack from app link --- .../wordpress/android/ui/ActivityNavigator.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/ActivityNavigator.kt b/WordPress/src/main/java/org/wordpress/android/ui/ActivityNavigator.kt index b37b30457c37..f4966505789d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/ActivityNavigator.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/ActivityNavigator.kt @@ -28,6 +28,7 @@ import org.wordpress.android.ui.mysite.menu.MenuActivity import org.wordpress.android.ui.mysite.personalization.PersonalizationActivity import org.wordpress.android.ui.quickstart.QuickStartEvent import org.wordpress.android.ui.sitemonitor.SiteMonitorParentActivity +import org.wordpress.android.ui.sitemonitor.SiteMonitorType import org.wordpress.android.util.ToastUtils import org.wordpress.android.util.analytics.AnalyticsUtils import javax.inject.Inject @@ -163,5 +164,23 @@ class ActivityNavigator @Inject constructor() { intent.putExtra(WordPress.SITE, site) context.startActivity(intent) } + + fun openSiteMonitoringInNewStack(context: Context, site: SiteModel?, siteMonitorType: SiteMonitorType = SiteMonitorType.METRICS) { + if (site == null) { + ToastUtils.showToast(context, R.string.site_monitoring_cannot_be_started, ToastUtils.Duration.SHORT) + return + } + val props = mutableMapOf("site_monitoring_type" to siteMonitorType.name as Any) + AnalyticsUtils.trackWithSiteDetails(AnalyticsTracker.Stat.OPENED_SITE_MONITORING, site, props) + val taskStackBuilder = TaskStackBuilder.create(context) + val mainActivityIntent = getMainActivityInNewStack(context) + val intent = Intent(context, SiteMonitorParentActivity::class.java) + intent.putExtra(WordPress.SITE, site) + intent.putExtra(SiteMonitorParentActivity.ARG_SITE_MONITOR_TYPE_KEY, siteMonitorType) + taskStackBuilder + .addNextIntent(mainActivityIntent) + .addNextIntent(intent) + .startActivities() + } } From 7650adecb8eb304ac34e53cc0d91964f259fa11c Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Mon, 29 Jan 2024 14:24:55 -0500 Subject: [PATCH 091/176] Add resource for when site monitoring can not be app linked into --- WordPress/src/main/res/values/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index d35b92bd2664..4fe2da0ac0f0 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -4857,4 +4857,5 @@ translators: %s: Select control option value e.g: "Auto, 25%". --> Metrics PHP Logs Web Server Logs + We cannot open site monitoring at the moment. Please try again later From 82e3f7cf39c3622a91cf0cba391ea02eda34e3e0 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Mon, 29 Jan 2024 14:25:30 -0500 Subject: [PATCH 092/176] Add the site monitor app link handler --- .../handlers/SiteMonitorLinkHandler.kt | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/SiteMonitorLinkHandler.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/SiteMonitorLinkHandler.kt b/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/SiteMonitorLinkHandler.kt new file mode 100644 index 000000000000..b5f329353399 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/SiteMonitorLinkHandler.kt @@ -0,0 +1,60 @@ +package org.wordpress.android.ui.deeplinks.handlers + +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.ui.deeplinks.DeepLinkNavigator +import org.wordpress.android.ui.deeplinks.DeepLinkUriUtils +import org.wordpress.android.ui.deeplinks.DeepLinkingIntentReceiverViewModel +import org.wordpress.android.ui.sitemonitor.SiteMonitorType +import org.wordpress.android.util.UriWrapper +import javax.inject.Inject + +class SiteMonitorLinkHandler +@Inject constructor(private val deepLinkUriUtils: DeepLinkUriUtils) : DeepLinkHandler { + /** + * Returns true if the URI looks like `wordpress.com/SITE_MONITORING_PATH` + */ + override fun shouldHandleUrl(uri: UriWrapper): Boolean { + return (uri.host == DeepLinkingIntentReceiverViewModel.HOST_WORDPRESS_COM && + uri.pathSegments.firstOrNull() == SITE_MONITORING_PATH) || uri.host == SITE_MONITORING_PATH + } + + override fun buildNavigateAction(uri: UriWrapper): DeepLinkNavigator.NavigateAction { + val targetHost = uri.pathSegments[1] + val site: SiteModel? = deepLinkUriUtils.hostToSite(targetHost) + val siteMonitorType = urlToType(uri.toString()) + return DeepLinkNavigator.NavigateAction.OpenSiteMonitoringForSite(site, siteMonitorType) + } + + override fun stripUrl(uri: UriWrapper): String { + return buildString { + val offset = if (uri.host == SITE_MONITORING_PATH) { + append(DeepLinkingIntentReceiverViewModel.APPLINK_SCHEME) + 0 + } else { + append("${DeepLinkingIntentReceiverViewModel.HOST_WORDPRESS_COM}/") + 1 + } + append(SITE_MONITORING_PATH) + val pathSegments = uri.pathSegments + val size = pathSegments.size + val hasSiteUrl = if (size > offset + 1) pathSegments.getOrNull(offset + 1) != null else false + if (hasSiteUrl) { + append("/${DeepLinkingIntentReceiverViewModel.SITE_DOMAIN}") + } + } + } + + private fun urlToType(url: String): SiteMonitorType { + return when { + url.contains(PHP_LOGS_PATTERN) -> SiteMonitorType.PHP_LOGS + url.contains(WEB_SERVER_LOGS_PATTERN) -> SiteMonitorType.WEB_SERVER_LOGS + else -> SiteMonitorType.METRICS + } + } + + companion object { + private const val SITE_MONITORING_PATH = "site-monitoring" + private const val PHP_LOGS_PATTERN = "/php" + private const val WEB_SERVER_LOGS_PATTERN = "/web" + } +} From 64b557993ee0e95918ea09d28b953bfbe7a8d95f Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Mon, 29 Jan 2024 14:26:11 -0500 Subject: [PATCH 093/176] Add the siteMonitorLinkHandler to the list of deepLinkHandlers and update unit test --- .../android/ui/deeplinks/handlers/DeepLinkHandlers.kt | 2 ++ .../android/ui/deeplinks/handlers/DeepLinkHandlersTest.kt | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/DeepLinkHandlers.kt b/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/DeepLinkHandlers.kt index c089152827a4..3f7313f563c3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/DeepLinkHandlers.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/DeepLinkHandlers.kt @@ -20,6 +20,7 @@ class DeepLinkHandlers mediaLinkHandler: MediaLinkHandler, domainManagementLinkHandler: DomainManagementLinkHandler, qrCodeMediaLinkHandler: QRCodeMediaLinkHandler, + siteMonitorLinkHandler: SiteMonitorLinkHandler ) { private val handlers = listOf( editorLinkHandler, @@ -33,6 +34,7 @@ class DeepLinkHandlers mediaLinkHandler, domainManagementLinkHandler, qrCodeMediaLinkHandler, + siteMonitorLinkHandler ) private val _toast by lazy { diff --git a/WordPress/src/test/java/org/wordpress/android/ui/deeplinks/handlers/DeepLinkHandlersTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/deeplinks/handlers/DeepLinkHandlersTest.kt index 224de052cc95..c8aaff5ea24d 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/deeplinks/handlers/DeepLinkHandlersTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/deeplinks/handlers/DeepLinkHandlersTest.kt @@ -48,6 +48,9 @@ class DeepLinkHandlersTest : BaseUnitTest() { @Mock lateinit var qrCodeMediaLinkHandler: QRCodeMediaLinkHandler + @Mock + lateinit var siteMonitorLinkHandler: SiteMonitorLinkHandler + @Mock lateinit var uri: UriWrapper private lateinit var deepLinkHandlers: DeepLinkHandlers @@ -67,6 +70,7 @@ class DeepLinkHandlersTest : BaseUnitTest() { mediaLinkHandler, domainManagementLinkHandler, qrCodeMediaLinkHandler, + siteMonitorLinkHandler ) initDeepLinkHandlers() } @@ -84,6 +88,7 @@ class DeepLinkHandlersTest : BaseUnitTest() { mediaLinkHandler, domainManagementLinkHandler, qrCodeMediaLinkHandler, + siteMonitorLinkHandler ) } From 32818303b0a488e6e369d5f678ae94bf79647338 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Mon, 29 Jan 2024 14:27:52 -0500 Subject: [PATCH 094/176] Refactor: add support for passing the siteMonitorType when coming from a app link scenario. --- .../ui/sitemonitor/SiteMonitorParentActivity.kt | 14 +++++++++++++- 1 file changed, 13 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 7291b52263ab..c2118117baf2 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 @@ -65,7 +65,13 @@ class SiteMonitorParentActivity: AppCompatActivity() { return requireNotNull(intent.getSerializableExtraCompat(WordPress.SITE)) as SiteModel } + private fun getInitialTab(): SiteMonitorType { + return intent?.getSerializableExtraCompat(ARG_SITE_MONITOR_TYPE_KEY) as SiteMonitorType? + ?: SiteMonitorType.METRICS + } + companion object { + const val ARG_SITE_MONITOR_TYPE_KEY = "ARG_SITE_MONITOR_TYPE_KEY" const val SAVED_STATE_CONTAINER_KEY = "ContainerKey" const val SAVED_STATE_CURRENT_TAB_KEY = "CurrentTabKey" } @@ -90,7 +96,7 @@ class SiteMonitorParentActivity: AppCompatActivity() { SiteMonitorTabNavigation(selectedTab) { selectedTab -> val item = enumValues().find { it.route == selectedTab - } ?: SiteMonitorTabItem.Metrics + } ?: initialItem(getInitialTab()) SiteMonitorFragmentContainer( modifier = Modifier.fillMaxSize(), @@ -104,6 +110,12 @@ class SiteMonitorParentActivity: AppCompatActivity() { } } + private fun initialItem(type: SiteMonitorType): SiteMonitorTabItem { + return enumValues().find { + it.siteMonitorType == type + } ?: SiteMonitorTabItem.Metrics + } + private fun getCommitFunction( fragment : Fragment, tag: String From e81dd062d36ac8864848c84d7d3f84218e3e0e3c Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Mon, 29 Jan 2024 14:55:40 -0500 Subject: [PATCH 095/176] Refactor: move extract host into its own method to expand the extraction --- .../ui/deeplinks/handlers/SiteMonitorLinkHandler.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/SiteMonitorLinkHandler.kt b/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/SiteMonitorLinkHandler.kt index b5f329353399..1461d7db8755 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/SiteMonitorLinkHandler.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/deeplinks/handlers/SiteMonitorLinkHandler.kt @@ -19,12 +19,17 @@ class SiteMonitorLinkHandler } override fun buildNavigateAction(uri: UriWrapper): DeepLinkNavigator.NavigateAction { - val targetHost = uri.pathSegments[1] + val targetHost = extractHost(uri) val site: SiteModel? = deepLinkUriUtils.hostToSite(targetHost) val siteMonitorType = urlToType(uri.toString()) return DeepLinkNavigator.NavigateAction.OpenSiteMonitoringForSite(site, siteMonitorType) } + private fun extractHost(uri: UriWrapper): String { + if (uri.pathSegments.size <= 1) return "" + return uri.pathSegments[1] + } + override fun stripUrl(uri: UriWrapper): String { return buildString { val offset = if (uri.host == SITE_MONITORING_PATH) { From bc6452d98f3b1d88132d657d2863541ab336cf05 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Mon, 29 Jan 2024 15:59:25 -0500 Subject: [PATCH 096/176] Refactor: address detekt long lines --- .../main/java/org/wordpress/android/ui/ActivityNavigator.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/ActivityNavigator.kt b/WordPress/src/main/java/org/wordpress/android/ui/ActivityNavigator.kt index f4966505789d..61cb8664470a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/ActivityNavigator.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/ActivityNavigator.kt @@ -165,7 +165,11 @@ class ActivityNavigator @Inject constructor() { context.startActivity(intent) } - fun openSiteMonitoringInNewStack(context: Context, site: SiteModel?, siteMonitorType: SiteMonitorType = SiteMonitorType.METRICS) { + fun openSiteMonitoringInNewStack( + context: Context, + site: SiteModel?, + siteMonitorType: SiteMonitorType = SiteMonitorType.METRICS + ) { if (site == null) { ToastUtils.showToast(context, R.string.site_monitoring_cannot_be_started, ToastUtils.Duration.SHORT) return From af5dc4d7bafc4deb94e3f876d67343ae13e696dc Mon Sep 17 00:00:00 2001 From: Renan Lukas <14964993+RenanLukas@users.noreply.github.com> Date: Mon, 29 Jan 2024 18:49:16 -0300 Subject: [PATCH 097/176] Fix PR comment: swipe to refresh loading never disappears --- .../wordpress/android/ui/reader/ReaderPostListFragment.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 445ac315c255..0c4639027bea 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -2323,6 +2323,9 @@ private void showLoadingProgress(boolean showProgress) { private void setIsUpdating(boolean isUpdating, UpdateAction updateAction) { if (!isAdded() || mIsUpdating == isUpdating) { + if (!isUpdating) { + mRecyclerView.setRefreshing(false); + } return; } From c144d637e4c0766cfdb496efeddeb6778224f49e Mon Sep 17 00:00:00 2001 From: Ravi Date: Tue, 30 Jan 2024 18:34:37 +1100 Subject: [PATCH 098/176] Show Today Card on Traffic tab Adds Today Card for default By day option --- .../granular/usecases/OverviewUseCase.kt | 130 +++++++++++++++++- 1 file changed, 127 insertions(+), 3 deletions(-) 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 46d2a1ce3a39..ef7b192d6ba7 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 @@ -14,6 +14,8 @@ import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.modules.UI_THREAD 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.lists.sections.BlockListItem.QuickScanItem +import org.wordpress.android.ui.stats.refresh.lists.sections.BlockListItem.QuickScanItem.Column import org.wordpress.android.ui.stats.refresh.lists.sections.BlockListItem.ValueItem import org.wordpress.android.ui.stats.refresh.lists.sections.granular.GranularUseCaseFactory import org.wordpress.android.ui.stats.refresh.lists.sections.granular.SelectedDateProvider @@ -21,12 +23,14 @@ import org.wordpress.android.ui.stats.refresh.lists.sections.granular.usecases.O 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.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 import org.wordpress.android.util.LocaleManagerWrapper import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper +import org.wordpress.android.util.config.StatsTrafficTabFeatureConfig import org.wordpress.android.viewmodel.ResourceProvider import java.util.Calendar import javax.inject.Inject @@ -48,7 +52,9 @@ class OverviewUseCase constructor( private val analyticsTracker: AnalyticsTrackerWrapper, private val statsWidgetUpdaters: StatsWidgetUpdaters, private val localeManagerWrapper: LocaleManagerWrapper, - private val resourceProvider: ResourceProvider + private val resourceProvider: ResourceProvider, + private val statsUtils: StatsUtils, + private val trafficTabFeatureConfig: StatsTrafficTabFeatureConfig ) : BaseStatsUseCase( OVERVIEW, mainDispatcher, @@ -144,6 +150,120 @@ class OverviewUseCase constructor( domainModel: VisitsAndViewsModel, uiState: UiState ): List { + return if (trafficTabFeatureConfig.isEnabled()) { + buildTrafficOverview(domainModel, uiState) + } else { + buildGranularOverview(domainModel, uiState) + } + } + + private fun buildTrafficOverview(domainModel: VisitsAndViewsModel, uiState: UiState): List { + val items = mutableListOf() + if (domainModel.dates.isNotEmpty()) { + val dateFromProvider = selectedDateProvider.getSelectedDate(statsGranularity) + val visibleBarCount = uiState.visibleBarCount ?: domainModel.dates.size + val availableDates = domainModel.dates.map { + statsDateFormatter.parseStatsDate( + statsGranularity, + it.period + ) + } + val selectedDate = dateFromProvider ?: availableDates.last() + val index = availableDates.indexOf(selectedDate) + + selectedDateProvider.selectDate( + selectedDate, + availableDates.takeLast(visibleBarCount), + statsGranularity + ) + val selectedItem = domainModel.dates.getOrNull(index) ?: domainModel.dates.last() + val previousItem = domainModel.dates.getOrNull(domainModel.dates.indexOf(selectedItem) - 1) + + if (statsGranularity == StatsGranularity.DAYS) { + buildTodayCard(selectedItem,items) + } else { + buildGranularChart(domainModel, uiState, items, selectedItem, previousItem) + } + } else { + selectedDateProvider.onDateLoadingFailed(statsGranularity) + AppLog.e(T.STATS, "There is no data to be shown in the overview block") + } + return items + } + + private fun buildTodayCard( + selectedItem: VisitsAndViewsModel.PeriodData?, + items: MutableList + ) { + val views = selectedItem?.views ?: 0 + val visitors = selectedItem?.visitors ?: 0 + val likes = selectedItem?.likes ?: 0 + val comments = selectedItem?.comments ?: 0 + + items.add(BlockListItem.Title(R.string.stats_timeframe_today)) + items.add( + QuickScanItem( + Column( + R.string.stats_views, + statsUtils.toFormattedString(views) + ), + Column( + R.string.stats_visitors, + statsUtils.toFormattedString(visitors) + ) + ) + ) + + items.add( + QuickScanItem( + Column( + R.string.stats_likes, + statsUtils.toFormattedString(likes) + ), + Column( + R.string.stats_comments, + statsUtils.toFormattedString(comments) + ) + ) + ) + } + + private fun buildGranularChart( + domainModel: VisitsAndViewsModel, + uiState: UiState, + items: MutableList, + selectedItem: VisitsAndViewsModel.PeriodData, + previousItem: VisitsAndViewsModel.PeriodData? + ) { + items.add( + overviewMapper.buildTitle( + selectedItem, + previousItem, + uiState.selectedPosition, + isLast = selectedItem == domainModel.dates.last(), + statsGranularity = statsGranularity + ) + ) + items.addAll( + overviewMapper.buildChart( + domainModel.dates, + statsGranularity, + this::onBarSelected, + this::onBarChartDrawn, + uiState.selectedPosition, + selectedItem.period + ) + ) + items.add( + overviewMapper.buildColumns( + selectedItem, + this::onColumnSelected, + uiState.selectedPosition + ) + ) + } + + private fun buildGranularOverview(domainModel: VisitsAndViewsModel, uiState: UiState): List { val items = mutableListOf() if (domainModel.dates.isNotEmpty()) { val dateFromProvider = selectedDateProvider.getSelectedDate(statsGranularity) @@ -237,7 +357,9 @@ class OverviewUseCase constructor( private val analyticsTracker: AnalyticsTrackerWrapper, private val statsWidgetUpdaters: StatsWidgetUpdaters, private val localeManagerWrapper: LocaleManagerWrapper, - private val resourceProvider: ResourceProvider + private val resourceProvider: ResourceProvider, + private val statsUtils: StatsUtils, + private val trafficTabFeatureConfig: StatsTrafficTabFeatureConfig ) : GranularUseCaseFactory { override fun build(granularity: StatsGranularity, useCaseMode: UseCaseMode) = OverviewUseCase( @@ -252,7 +374,9 @@ class OverviewUseCase constructor( analyticsTracker, statsWidgetUpdaters, localeManagerWrapper, - resourceProvider + resourceProvider, + statsUtils, + trafficTabFeatureConfig ) } } From 88429761d57a30871953018ef2e0ebff5bda0117 Mon Sep 17 00:00:00 2001 From: Ravi Date: Tue, 30 Jan 2024 18:34:41 +1100 Subject: [PATCH 099/176] Update OverviewUseCaseTest.kt --- .../granular/usecases/OverviewUseCaseTest.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/OverviewUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/OverviewUseCaseTest.kt index 3757b6c82b41..d0206175cee8 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/OverviewUseCaseTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/granular/usecases/OverviewUseCaseTest.kt @@ -35,8 +35,10 @@ import org.wordpress.android.ui.stats.refresh.lists.sections.granular.SelectedDa 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.StatsUtils import org.wordpress.android.util.LocaleManagerWrapper import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper +import org.wordpress.android.util.config.StatsTrafficTabFeatureConfig import org.wordpress.android.viewmodel.ResourceProvider import java.util.Calendar @@ -77,6 +79,13 @@ class OverviewUseCaseTest : BaseUnitTest() { @Mock lateinit var localeManagerWrapper: LocaleManagerWrapper + + @Mock + lateinit var statsUtils: StatsUtils + + @Mock + lateinit var trafficTabFeatureConfig: StatsTrafficTabFeatureConfig + private lateinit var useCase: OverviewUseCase private val site = SiteModel() private val siteId = 1L @@ -100,7 +109,9 @@ class OverviewUseCaseTest : BaseUnitTest() { analyticsTrackerWrapper, statsWidgetUpdaters, localeManagerWrapper, - resourceProvider + resourceProvider, + statsUtils, + trafficTabFeatureConfig ) site.siteId = siteId whenever(statsSiteProvider.siteModel).thenReturn(site) From 56685613756fae31f8c6ae03c6c971f00a648bf9 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Tue, 30 Jan 2024 10:03:03 +0200 Subject: [PATCH 100/176] Modify colors for site monitor tabs --- .../ui/sitemonitor/SiteMonitorTabHeader.kt | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) 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 index 1bf493f7c49d..927918afa815 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabHeader.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabHeader.kt @@ -1,9 +1,11 @@ package org.wordpress.android.ui.sitemonitor import androidx.compose.foundation.layout.Column -import androidx.compose.material3.MaterialTheme +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 @@ -11,8 +13,10 @@ 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 import androidx.compose.ui.unit.sp @Composable @@ -25,8 +29,16 @@ fun SiteMonitorTabHeader(navController: (String) -> Unit) { ) TabRow( selectedTabIndex = selectedTabIndex, - containerColor = MaterialTheme.colorScheme.surface, - contentColor = MaterialTheme.colorScheme.onSurface, + 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( From 294ac0bf4b68a4262ab86897afea4d7426303841 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Tue, 30 Jan 2024 10:03:38 +0200 Subject: [PATCH 101/176] Add analytics for site monitor tabs --- .../android/ui/sitemonitor/SiteMonitorParentActivity.kt | 9 +++++++++ .../android/ui/sitemonitor/SiteMonitorTabViewModel.kt | 1 - .../android/ui/sitemonitor/SiteMonitorUiState.kt | 8 ++++---- .../wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt | 8 +++++++- .../wordpress/android/analytics/AnalyticsTracker.java | 1 + .../android/analytics/AnalyticsTrackerNosara.java | 2 ++ 6 files changed, 23 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 c2118117baf2..9a9c52b4920b 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,15 +28,22 @@ 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.util.extensions.getSerializableExtraCompat +import javax.inject.Inject @AndroidEntryPoint class SiteMonitorParentActivity: AppCompatActivity() { + @Inject + lateinit var siteMonitorUtils: SiteMonitorUtils + private var savedStateSparseArray = SparseArray() private var currentSelectItemId = 0 @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + + siteMonitorUtils.trackActivityLaunched() + if (savedInstanceState != null) { savedStateSparseArray = savedInstanceState.getSparseParcelableArray( SAVED_STATE_CONTAINER_KEY @@ -98,6 +105,8 @@ class SiteMonitorParentActivity: AppCompatActivity() { it.route == selectedTab } ?: initialItem(getInitialTab()) + siteMonitorUtils.trackTabLoaded(item.siteMonitorType) + SiteMonitorFragmentContainer( modifier = Modifier.fillMaxSize(), commit = getCommitFunction( 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..6da26dbb7e77 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 @@ -106,7 +106,6 @@ class SiteMonitorTabViewModel @Inject constructor( } fun onUrlLoaded() { - siteMonitorUtils.trackTabLoaded(siteMonitorType) 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 50bca3c0dec8..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 @@ -51,8 +51,8 @@ data class SiteMonitorModel( val url: String, val addressToLoad: String ) -enum class SiteMonitorType { - METRICS, - PHP_LOGS, - WEB_SERVER_LOGS +enum class SiteMonitorType(val analyticsDescription: String) { + METRICS("metrics"), + PHP_LOGS("php_logs"), + WEB_SERVER_LOGS("server_logs") } 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 f4e7fe8c098d..d42bbe4c9fc6 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 @@ -21,6 +21,7 @@ class SiteMonitorUtils @Inject constructor( fun trackActivityLaunched() { + Log.i(javaClass.simpleName, "track Site Monitor screen shown") analyticsTrackerWrapper.track(AnalyticsTracker.Stat.SITE_MONITORING_SCREEN_SHOWN) } @@ -35,13 +36,18 @@ class SiteMonitorUtils @Inject constructor( } fun trackTabLoaded(siteMonitorType: SiteMonitorType) { - // todo: need to set this up properly with track events Log.i(javaClass.simpleName, "track TabLoaded with $siteMonitorType") + analyticsTrackerWrapper.track( + AnalyticsTracker.Stat.SITE_MONITORING_TAB_SHOWN, + mapOf( + TAB_TRACK_KEY to siteMonitorType + )) } companion object { const val HTTP_PATTERN = "(https?://)" const val PHP_LOGS_PATTERN = "/php" const val WEB_SERVER_LOGS_PATTERN = "/web" + const val TAB_TRACK_KEY = "tab" } } 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 ba65e2e228ea..4ecc68844c66 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 @@ -1103,6 +1103,7 @@ public enum Stat { DEEP_LINK_FAILED, SITE_MONITORING_SCREEN_SHOWN, OPENED_SITE_MONITORING, + SITE_MONITORING_TAB_SHOWN, } 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 6a83354fe74d..6bc51ec5bdbf 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 @@ -2699,6 +2699,8 @@ public static String getEventNameForStat(AnalyticsTracker.Stat stat) { return "site_monitoring_screen_shown"; case OPENED_SITE_MONITORING: return "opened_site_monitoring"; + case SITE_MONITORING_TAB_SHOWN: + return "site_monitoring_tab_shown"; } return null; } From 964fd10b6de5c0c3cd6d12484235fe190a0ab323 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Tue, 30 Jan 2024 15:02:11 +0530 Subject: [PATCH 102/176] + 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 103/176] =?UTF-8?q?=E2=86=91=20Updates:=20the=20webview=20?= =?UTF-8?q?client=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 104/176] + 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 105/176] =?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 106/176] =?UTF-8?q?=E2=86=91=20Updates:=20the=20site=20mon?= =?UTF-8?q?itor=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 107/176] =?UTF-8?q?=E2=86=91=20Updates:=20the=20fragment?= =?UTF-8?q?=20to=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 3a7b6d8efb42b5c3a68727782bc566ab0c49f7a9 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Tue, 30 Jan 2024 15:43:52 +0530 Subject: [PATCH 108/176] - Removes: redundant logging information from the code base --- .../android/ui/sitemonitor/SiteMonitorTabViewModel.kt | 2 -- .../org/wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt | 3 --- 2 files changed, 5 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 6da26dbb7e77..275c65087676 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 @@ -1,7 +1,6 @@ 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 @@ -32,7 +31,6 @@ class SiteMonitorTabViewModel @Inject constructor( val uiState: StateFlow = _uiState fun start(type: SiteMonitorType, urlTemplate: String, site: SiteModel) { - Log.i("Track", "TheViewModel start with $urlTemplate and $type") this.siteMonitorType = type this.urlTemplate = urlTemplate this.site = site 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 d42bbe4c9fc6..f4322eaf7685 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 @@ -1,6 +1,5 @@ package org.wordpress.android.ui.sitemonitor -import android.util.Log import org.wordpress.android.WordPress import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.ui.WPWebViewActivity @@ -21,7 +20,6 @@ class SiteMonitorUtils @Inject constructor( fun trackActivityLaunched() { - Log.i(javaClass.simpleName, "track Site Monitor screen shown") analyticsTrackerWrapper.track(AnalyticsTracker.Stat.SITE_MONITORING_SCREEN_SHOWN) } @@ -36,7 +34,6 @@ class SiteMonitorUtils @Inject constructor( } fun trackTabLoaded(siteMonitorType: SiteMonitorType) { - Log.i(javaClass.simpleName, "track TabLoaded with $siteMonitorType") analyticsTrackerWrapper.track( AnalyticsTracker.Stat.SITE_MONITORING_TAB_SHOWN, mapOf( From 3116c92a9bfe52eed389ead82df1ff22da3248bc Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Tue, 30 Jan 2024 15:44:18 +0530 Subject: [PATCH 109/176] + Adds: tab tracking to the analytics event --- .../org/wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f4322eaf7685..8ab932a5b86c 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 @@ -37,7 +37,7 @@ class SiteMonitorUtils @Inject constructor( analyticsTrackerWrapper.track( AnalyticsTracker.Stat.SITE_MONITORING_TAB_SHOWN, mapOf( - TAB_TRACK_KEY to siteMonitorType + TAB_TRACK_KEY to siteMonitorType.analyticsDescription )) } From 849484fa790de77ab19178cbdb771090568587d9 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Tue, 30 Jan 2024 15:44:57 +0530 Subject: [PATCH 110/176] - Removes: redundant function --- .../wordpress/android/ui/sitemonitor/SiteMonitorUtils.kt | 8 -------- 1 file changed, 8 deletions(-) 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 8ab932a5b86c..a4b25ed2a1c7 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 @@ -25,14 +25,6 @@ class SiteMonitorUtils @Inject constructor( fun sanitizeSiteUrl(url: String?) = url?.replace(Regex(HTTP_PATTERN), "") ?: "" - fun urlToType(url: String): SiteMonitorType { - return when { - url.contains(PHP_LOGS_PATTERN) -> SiteMonitorType.PHP_LOGS - url.contains(WEB_SERVER_LOGS_PATTERN) -> SiteMonitorType.WEB_SERVER_LOGS - else -> SiteMonitorType.METRICS - } - } - fun trackTabLoaded(siteMonitorType: SiteMonitorType) { analyticsTrackerWrapper.track( AnalyticsTracker.Stat.SITE_MONITORING_TAB_SHOWN, From f59c5dfd27ea847c1432ec0e71ff1358c1950901 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Tue, 30 Jan 2024 15:51:41 +0530 Subject: [PATCH 111/176] Updates: the tab title to default height --- .../wordpress/android/ui/sitemonitor/SiteMonitorTabHeader.kt | 2 -- 1 file changed, 2 deletions(-) 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 index 927918afa815..7a15059a31fc 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabHeader.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabHeader.kt @@ -17,7 +17,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp @Composable fun SiteMonitorTabHeader(navController: (String) -> Unit) { @@ -46,7 +45,6 @@ fun SiteMonitorTabHeader(navController: (String) -> Unit) { Column (horizontalAlignment = Alignment.CenterHorizontally) { Text( text = stringResource(item.title), - fontSize = 12.sp, maxLines = 1, overflow = TextOverflow.Ellipsis ) From 0a04666daf19c672b33caf416682eae748a945ed Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Tue, 30 Jan 2024 16:39:16 +0300 Subject: [PATCH 112/176] 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 113/176] 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 114/176] 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 115/176] 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 62a1ee7775b0cfc5e0e4fb310805c5a2b8525aa2 Mon Sep 17 00:00:00 2001 From: Thomas Horta Date: Tue, 30 Jan 2024 11:52:43 -0300 Subject: [PATCH 116/176] Store post update state in a Set for reliable UI representation --- .../ui/reader/ReaderPostListFragment.java | 59 ++++++++++++------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 0c4639027bea..12026cc56d21 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -146,6 +146,7 @@ import java.util.ArrayList; import java.util.EnumSet; +import java.util.HashSet; import java.util.List; import java.util.Stack; @@ -210,9 +211,9 @@ public class ReaderPostListFragment extends ViewPagerFragment private int mPostSearchAdapterPos; private int mSiteSearchAdapterPos; private int mSearchTabsPos = NO_POSITION; - private boolean mIsUpdating; private boolean mIsFilterableScreen; private boolean mIsFiltered = false; + @NonNull private final HashSet mCurrentUpdateActions = new HashSet<>(); /* * called by post adapter to load older posts when user scrolls to the last post */ @@ -1181,8 +1182,7 @@ public void onShowCustomEmptyView(EmptyViewMessageType emptyViewMsgType) { } if (savedInstanceState != null && savedInstanceState.getBoolean(ReaderConstants.KEY_IS_REFRESHING)) { - mIsUpdating = true; - mRecyclerView.setRefreshing(true); + setIsUpdating(true, UpdateAction.REQUEST_NEWER); } return rootView; @@ -1699,7 +1699,7 @@ private void setEmptyTitleDescriptionAndButton(boolean requestFailed) { setEmptyTitleAndDescriptionForBookmarksList(); return; } else if (!NetworkUtils.isNetworkAvailable(getActivity())) { - mIsUpdating = false; + clearCurrentUpdateActions(); title = getString(R.string.reader_empty_posts_no_connection); } else if (requestFailed) { if (isSearching()) { @@ -2304,7 +2304,7 @@ public void run() { } private boolean isUpdating() { - return mIsUpdating; + return mCurrentUpdateActions.size() > 0; } /* @@ -2321,30 +2321,45 @@ private void showLoadingProgress(boolean showProgress) { } } - private void setIsUpdating(boolean isUpdating, UpdateAction updateAction) { - if (!isAdded() || mIsUpdating == isUpdating) { - if (!isUpdating) { - mRecyclerView.setRefreshing(false); - } - return; - } + private void clearCurrentUpdateActions() { + if (!isAdded() || !isUpdating()) return; - if (updateAction == UpdateAction.REQUEST_OLDER) { - // show/hide progress bar at bottom if these are older posts - showLoadingProgress(isUpdating); - } else if (isUpdating) { - // show swipe-to-refresh if update started - mRecyclerView.setRefreshing(true); + mCurrentUpdateActions.clear(); + updateProgressIndicators(); + } + + private void setIsUpdating(boolean isUpdating, @NonNull UpdateAction updateAction) { + if (!isAdded()) return; + + boolean isUiUpdateNeeded; + if (isUpdating) { + isUiUpdateNeeded = mCurrentUpdateActions.add(updateAction); } else { - // hide swipe-to-refresh progress if update is complete + isUiUpdateNeeded = mCurrentUpdateActions.remove(updateAction); + } + + if (isUiUpdateNeeded) updateProgressIndicators(); + } + + private void updateProgressIndicators() { + if (!isUpdating()) { + // when there's no update in progress, hide the bottom and swipe-to-refresh progress bars + showLoadingProgress(false); mRecyclerView.setRefreshing(false); + } else if (mCurrentUpdateActions.size() == 1 && mCurrentUpdateActions.contains(UpdateAction.REQUEST_OLDER)) { + // if only older posts are being updated, show only the bottom progress bar + showLoadingProgress(true); + mRecyclerView.setRefreshing(false); + } else { + // if anything else is being updated, show only the swipe-to-refresh progress bar + showLoadingProgress(false); + mRecyclerView.setRefreshing(true); } - mIsUpdating = isUpdating; // if swipe-to-refresh isn't active, keep it disabled during an update - this prevents // doing a refresh while another update is already in progress - if (mRecyclerView != null && !mRecyclerView.isRefreshing()) { - mRecyclerView.setSwipeToRefreshEnabled(!isUpdating && isSwipeToRefreshSupported()); + if (!mRecyclerView.isRefreshing()) { + mRecyclerView.setSwipeToRefreshEnabled(!isUpdating() && isSwipeToRefreshSupported()); } } From 1e2391cc8713a2891308cce7263d736923ebb049 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Tue, 30 Jan 2024 16:04:40 +0100 Subject: [PATCH 117/176] 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 118/176] 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 119/176] 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 120/176] 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 121/176] 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 122/176] 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 dfde3f826d62e3867f29ac89ffed5d9359aa055a Mon Sep 17 00:00:00 2001 From: Thomas Horta Date: Tue, 30 Jan 2024 17:11:20 -0300 Subject: [PATCH 123/176] Replace the IS_REFRESHING bundle state with CURRENT_UPDATE_ACTIONS --- .../android/ui/reader/ReaderConstants.java | 2 +- .../android/ui/reader/ReaderPostListFragment.java | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderConstants.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderConstants.java index 504d71f1de01..c0798c5824ca 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderConstants.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderConstants.java @@ -67,7 +67,7 @@ public class ReaderConstants { static final String KEY_FIRST_LOAD = "first_load"; static final String KEY_ACTIVITY_TITLE = "activity_title"; static final String KEY_TRACKED_POSITIONS = "tracked_positions"; - static final String KEY_IS_REFRESHING = "is_refreshing"; + static final String KEY_CURRENT_UPDATE_ACTIONS = "current_update_actions"; static final String KEY_ACTIVE_SEARCH_TAB = "active_search_tab"; static final String KEY_SITE_ID = "site_id"; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 12026cc56d21..763d944c130c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -144,6 +144,7 @@ import org.wordpress.android.widgets.RecyclerItemDecoration; import org.wordpress.android.widgets.WPSnackbar; +import java.io.Serializable; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; @@ -213,7 +214,7 @@ public class ReaderPostListFragment extends ViewPagerFragment private int mSearchTabsPos = NO_POSITION; private boolean mIsFilterableScreen; private boolean mIsFiltered = false; - @NonNull private final HashSet mCurrentUpdateActions = new HashSet<>(); + @NonNull private HashSet mCurrentUpdateActions = new HashSet<>(); /* * called by post adapter to load older posts when user scrolls to the last post */ @@ -958,8 +959,8 @@ public void onSaveInstanceState(@NonNull Bundle outState) { outState.putBoolean(ReaderConstants.KEY_ALREADY_REQUESTED, mHasRequestedPosts); outState.putBoolean(ReaderConstants.KEY_ALREADY_UPDATED, mHasUpdatedPosts); outState.putBoolean(ReaderConstants.KEY_FIRST_LOAD, mFirstLoad); + outState.putSerializable(ReaderConstants.KEY_CURRENT_UPDATE_ACTIONS, mCurrentUpdateActions); if (mRecyclerView != null) { - outState.putBoolean(ReaderConstants.KEY_IS_REFRESHING, mRecyclerView.isRefreshing()); outState.putInt(ReaderConstants.KEY_RESTORE_POSITION, getCurrentPosition()); } outState.putSerializable(ReaderConstants.ARG_POST_LIST_TYPE, getPostListType()); @@ -1181,8 +1182,12 @@ public void onShowCustomEmptyView(EmptyViewMessageType emptyViewMsgType) { } } - if (savedInstanceState != null && savedInstanceState.getBoolean(ReaderConstants.KEY_IS_REFRESHING)) { - setIsUpdating(true, UpdateAction.REQUEST_NEWER); + if (savedInstanceState != null) { + Serializable actions = savedInstanceState.getSerializable(ReaderConstants.KEY_CURRENT_UPDATE_ACTIONS); + if (actions instanceof HashSet) { + mCurrentUpdateActions = (HashSet) actions; + updateProgressIndicators(); + } } return rootView; From e910a0277d11455cabcaef1f85a5464fb3bd6e10 Mon Sep 17 00:00:00 2001 From: Ravi Date: Wed, 31 Jan 2024 15:31:28 +1100 Subject: [PATCH 124/176] 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 125/176] =?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 126/176] + 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 127/176] + 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 128/176] * 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 129/176] * 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 130/176] * 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 131/176] - 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 132/176] =?UTF-8?q?=E2=86=92=20Moves:=20Site=20Monitor=20T?= =?UTF-8?q?ab=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 133/176] - 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 134/176] - 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 135/176] * 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 136/176] * 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 137/176] 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 138/176] 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 139/176] =?UTF-8?q?=E2=86=91=20Updates:=20the=20state=20re?= =?UTF-8?q?turned=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 140/176] * 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 141/176] 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 142/176] 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 143/176] 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 144/176] 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 145/176] 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 146/176] 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 147/176] * 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 148/176] 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 149/176] 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 150/176] 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 151/176] 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 152/176] 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 153/176] 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 ----- From 440ef7e3afec9de454e707c2ca223d835631d5b1 Mon Sep 17 00:00:00 2001 From: Thomas Horta Date: Wed, 31 Jan 2024 17:33:45 -0300 Subject: [PATCH 154/176] Convert scrollToTop to an Event This avoids the stale information of this field to be kept in the uiState and be consumed by the UI incorrectly multiple times. An event makes more sense here since we want the action to happen once at a very specific moment, only that event is triggered. --- .../reader/discover/ReaderDiscoverFragment.kt | 8 +-- .../discover/ReaderDiscoverViewModel.kt | 12 ++-- .../discover/ReaderDiscoverViewModelTest.kt | 56 +++++++++++++++++-- 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverFragment.kt index bea9580b298a..00918013c71e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverFragment.kt @@ -131,9 +131,6 @@ class ReaderDiscoverFragment : ViewPagerFragment(R.layout.reader_discover_fragme when (it) { is DiscoverUiState.ContentUiState -> { (recyclerView.adapter as ReaderDiscoverAdapter).update(it.cards) - if (it.scrollToTop) { - recyclerView.scrollToPosition(0) - } } is DiscoverUiState.EmptyUiState -> { uiHelpers.setTextOrHide(actionableEmptyView.title, it.titleResId) @@ -153,9 +150,10 @@ class ReaderDiscoverFragment : ViewPagerFragment(R.layout.reader_discover_fragme ptrLayout.isEnabled = it.swipeToRefreshEnabled ptrLayout.isRefreshing = it.reloadProgressVisibility } + viewModel.scrollToTopEvent.observeEvent(viewLifecycleOwner) { recyclerView.scrollToPosition(0) } viewModel.navigationEvents.observeEvent(viewLifecycleOwner) { handleNavigation(it) } - viewModel.snackbarEvents.observeEvent(viewLifecycleOwner, { it.showSnackbar() }) - viewModel.preloadPostEvents.observeEvent(viewLifecycleOwner, { it.addWebViewCachingFragment() }) + viewModel.snackbarEvents.observeEvent(viewLifecycleOwner) { it.showSnackbar() } + viewModel.preloadPostEvents.observeEvent(viewLifecycleOwner) { it.addWebViewCachingFragment() } viewModel.start(parentViewModel) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModel.kt index d9b5091f88a2..c9b02681ea84 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModel.kt @@ -2,6 +2,7 @@ package org.wordpress.android.ui.reader.discover import androidx.lifecycle.LiveData import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Observer import androidx.lifecycle.viewModelScope import kotlinx.coroutines.CoroutineDispatcher @@ -79,6 +80,9 @@ class ReaderDiscoverViewModel @Inject constructor( private val _preloadPostEvents = MediatorLiveData>() val preloadPostEvents: LiveData> = _preloadPostEvents + private val _scrollToTopEvent = MutableLiveData>() + val scrollToTopEvent: LiveData> = _scrollToTopEvent + /** * Post which is about to be reblogged after the user selects a target site. */ @@ -155,9 +159,11 @@ class ReaderDiscoverViewModel @Inject constructor( convertCardsToUiStates(posts), reloadProgressVisibility = false, loadMoreProgressVisibility = false, - scrollToTop = swipeToRefreshTriggered ) - swipeToRefreshTriggered = false + if (swipeToRefreshTriggered) { + _scrollToTopEvent.postValue(Event(Unit)) + swipeToRefreshTriggered = false + } } else { _uiState.value = DiscoverUiState.EmptyUiState.ShowNoPostsUiState { _navigationEvents.value = Event(ShowReaderSubs) @@ -523,7 +529,6 @@ class ReaderDiscoverViewModel @Inject constructor( val fullscreenProgressVisibility: Boolean = false, val swipeToRefreshEnabled: Boolean = false, open val fullscreenEmptyVisibility: Boolean = false, - open val scrollToTop: Boolean = false ) { open val reloadProgressVisibility: Boolean = false open val loadMoreProgressVisibility: Boolean = false @@ -532,7 +537,6 @@ class ReaderDiscoverViewModel @Inject constructor( val cards: List, override val reloadProgressVisibility: Boolean, override val loadMoreProgressVisibility: Boolean, - override val scrollToTop: Boolean ) : DiscoverUiState(contentVisiblity = true, swipeToRefreshEnabled = true) object LoadingUiState : DiscoverUiState(fullscreenProgressVisibility = true) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModelTest.kt index d3d7227e6465..1db7219634ec 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModelTest.kt @@ -608,18 +608,19 @@ class ReaderDiscoverViewModelTest : BaseUnitTest() { @Test fun `Scroll to top is triggered when discover feed is updated after swipe to refresh`() = test { // Arrange - val uiStates = init().uiStates + val scrollToTopCounter = init().scrollToTopCounter + // Act viewModel.swipeToRefresh() fakeDiscoverFeed.value = createDummyReaderCardsList() // Assert - assertThat(uiStates.last().scrollToTop).isTrue + assertThat(scrollToTopCounter.count).isEqualTo(1) } @Test fun `Scroll to top is not triggered when discover feed is updated after load more action`() = test { // Arrange - val uiStates = init().uiStates + val scrollToTopCounter = init().scrollToTopCounter val closeToEndIndex = NUMBER_OF_ITEMS.toInt() - INITIATE_LOAD_MORE_OFFSET init() // Act @@ -628,7 +629,34 @@ class ReaderDiscoverViewModelTest : BaseUnitTest() { } fakeDiscoverFeed.value = createDummyReaderCardsList() // Assert - assertThat(uiStates.last().scrollToTop).isFalse + assertThat(scrollToTopCounter.count).isZero() + } + + @Test + fun `Scroll to top is triggered only once when discover feed is updated with load more after swipe to refresh`() = + test { + // Arrange + val scrollToTopCounter = init().scrollToTopCounter + val closeToEndIndex = NUMBER_OF_ITEMS.toInt() - INITIATE_LOAD_MORE_OFFSET + + // Act for swipe to refresh + viewModel.swipeToRefresh() + fakeDiscoverFeed.value = createDummyReaderCardsList() + + // Assert for swipe to refresh + assertThat(scrollToTopCounter.count).isEqualTo(1) + + // Arrange for load more + scrollToTopCounter.reset() + + // Act for load more + ((viewModel.uiState.value as ContentUiState).cards[closeToEndIndex] as ReaderPostUiState).let { + it.onItemRendered.invoke(it) + } + fakeDiscoverFeed.value = createDummyReaderCardsList() + + // Assert for load more + assertThat(scrollToTopCounter.count).isZero() } @Test @@ -679,11 +707,15 @@ class ReaderDiscoverViewModelTest : BaseUnitTest() { viewModel.snackbarEvents.observeForever { msgs.add(it) } + val scrollToTop = SimpleCounter() + viewModel.scrollToTopEvent.observeForever { + scrollToTop.increment() + } viewModel.start(parentViewModel) if (autoUpdateFeed) { fakeDiscoverFeed.value = createDummyReaderCardsList() } - return Observers(uiStates, navigation, msgs) + return Observers(uiStates, navigation, msgs, scrollToTop) } // since we are adding an InterestsYouMayLikeCard we remove one item from the numberOfItems since it counts as 1. @@ -881,6 +913,18 @@ class ReaderDiscoverViewModelTest : BaseUnitTest() { private data class Observers( val uiStates: List, val navigation: List>, - val snackbarMsgs: List> + val snackbarMsgs: List>, + val scrollToTopCounter: SimpleCounter, // number of calls to this event ) + + private class SimpleCounter { + var count: Int = 0 + private set + + fun increment() = count++ + + fun reset() { + count = 0 + } + } } From e3f312114f00b44bccec7897c72de74ba52ff892 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Thu, 1 Feb 2024 09:13:37 +0530 Subject: [PATCH 155/176] =?UTF-8?q?=E2=86=92=20Moves:=20the=20Lazy=20Colum?= =?UTF-8?q?n=20to=20wrap=20only=20the=20webview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sitemonitor/SiteMonitorParentActivity.kt | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 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 c1773d48c83e..8fe069c90640 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 @@ -221,17 +221,14 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. val uiState by remember(key1 = tabType) { siteMonitorParentViewModel.getUiState(tabType) } - 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) - } - } + 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 fun LoadingState(modifier: Modifier = Modifier) { Box( @@ -299,12 +296,14 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. if (uiState is SiteMonitorUiState.Prepared) { LoadingState() } else { - webView.let { theWebView -> - AndroidView( - factory = { theWebView }, - update = { webView = it }, - modifier = Modifier.fillMaxWidth() - ) + LazyColumn(modifier = modifier.fillMaxHeight()) { + item { + AndroidView( + factory = { webView }, + update = { webView = it }, + modifier = Modifier.fillMaxWidth() + ) + } } } } From 6f4ff65c517801cf6c369bbab9c1cf7d85d2efbf Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Thu, 1 Feb 2024 10:01:53 +0530 Subject: [PATCH 156/176] =?UTF-8?q?=E2=86=91=20Updates:=20the=20Webview=20?= =?UTF-8?q?Content=20composable=20grouping=20with=20ui=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sitemonitor/SiteMonitorParentActivity.kt | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 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 8fe069c90640..3c015c61d3be 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 @@ -224,7 +224,8 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. when (uiState) { is SiteMonitorUiState.Preparing -> LoadingState(modifier) is SiteMonitorUiState.Prepared, is SiteMonitorUiState.Loaded -> - SiteMonitorWebView(uiState, tabType, modifier) + SiteMonitorWebViewContent(uiState, tabType, modifier) + is SiteMonitorUiState.Error -> SiteMonitorError(uiState as SiteMonitorUiState.Error, modifier) } } @@ -273,37 +274,47 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. @SuppressLint("SetJavaScriptEnabled") @Composable - private fun SiteMonitorWebView( + private fun SiteMonitorWebViewContent( uiState: SiteMonitorUiState, tabType: SiteMonitorType, modifier: Modifier = Modifier ) { // retrieve the webview from the actvity - var webView = when (tabType) { + val webView = when (tabType) { SiteMonitorType.METRICS -> metricsWebView SiteMonitorType.PHP_LOGS -> phpLogsWebView SiteMonitorType.WEB_SERVER_LOGS -> webServerLogsWebView } - if (uiState is SiteMonitorUiState.Prepared) { - webView.postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, uiState.model.addressToLoad.toByteArray()) + when(uiState) { + is SiteMonitorUiState.Prepared -> { + webView.postUrl(WPWebViewActivity.WPCOM_LOGIN_URL, uiState.model.addressToLoad.toByteArray()) + LoadingState() + } + is SiteMonitorUiState.Loaded -> { + SiteMonitorWebView(webView, modifier) + } + else -> {} } + } + @Composable + private fun SiteMonitorWebView(tabWebView: WebView, modifier: Modifier = Modifier) { + // the webview is retrieved from the activity, so we need to use a mutable variable + // to assign to android view + + var webView = tabWebView Box( - modifier = modifier.fillMaxSize(), - contentAlignment = Alignment.Center + modifier = modifier + .fillMaxSize() ) { - if (uiState is SiteMonitorUiState.Prepared) { - LoadingState() - } else { - LazyColumn(modifier = modifier.fillMaxHeight()) { - item { - AndroidView( - factory = { webView }, - update = { webView = it }, - modifier = Modifier.fillMaxWidth() - ) - } + LazyColumn(modifier = Modifier.fillMaxHeight()) { + item { + AndroidView( + factory = { webView }, + update = { webView = it }, + modifier = Modifier.fillMaxWidth() + ) } } } From bed7304e7ac09a96bbccdcbafc339ec7a602b563 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Thu, 1 Feb 2024 11:22:32 +0530 Subject: [PATCH 157/176] + Adds: the logic to refresh data in viewmodel slice --- .../ui/sitemonitor/SiteMonitorTabViewModelSlice.kt | 9 +++++++++ 1 file changed, 9 insertions(+) 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 45ec9a56d76f..425149c514b2 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 @@ -28,6 +28,9 @@ class SiteMonitorTabViewModelSlice @Inject constructor( private val _uiState = mutableStateOf(SiteMonitorUiState.Preparing) val uiState: State = _uiState + private val _isRefreshing = mutableStateOf(false) + val isRefreshing: State = _isRefreshing + fun initialize(scope: CoroutineScope) { this.scope = scope } @@ -50,6 +53,12 @@ class SiteMonitorTabViewModelSlice @Inject constructor( assembleAndShowSiteMonitor() } + fun refreshData() { + _isRefreshing.value = true + loadView() + _isRefreshing.value = false + } + private fun checkForInternetConnectivityAndPostErrorIfNeeded() : Boolean { if (networkUtilsWrapper.isNetworkAvailable()) return true postUiState(mapper.toNoNetworkError(::loadView)) From f62071b818a0255244430edbcd5aa3d30d31f0bf Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Thu, 1 Feb 2024 11:23:09 +0530 Subject: [PATCH 158/176] + Adds: the refresh data and refresh ui state get function in vm --- .../sitemonitor/SiteMonitorParentViewModel.kt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) 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 2a18f07e1fb2..104800214320 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 @@ -92,4 +92,36 @@ class SiteMonitorParentViewModel @Inject constructor( phpLogViewModel.onCleared() webServerViewModel.onCleared() } + + fun getRefreshState(siteMonitorType: SiteMonitorType): State { + return when (siteMonitorType) { + SiteMonitorType.METRICS -> { + metricsViewModel.isRefreshing + } + + SiteMonitorType.PHP_LOGS -> { + phpLogViewModel.isRefreshing + } + + SiteMonitorType.WEB_SERVER_LOGS -> { + webServerViewModel.isRefreshing + } + } + } + + fun refreshData(siteMonitorType: SiteMonitorType) { + when(siteMonitorType) { + SiteMonitorType.METRICS -> { + metricsViewModel.refreshData() + } + + SiteMonitorType.PHP_LOGS -> { + phpLogViewModel.refreshData() + } + + SiteMonitorType.WEB_SERVER_LOGS -> { + webServerViewModel.refreshData() + } + } + } } From 636b0a4f5ef635bfbf66a2de24308c0b2c85f17d Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Thu, 1 Feb 2024 11:23:41 +0530 Subject: [PATCH 159/176] + Adds: pull to refresh logic to the view in SiteMonitorParentActivity --- .../sitemonitor/SiteMonitorParentActivity.kt | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 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 3c015c61d3be..97278d29fc62 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,9 +19,13 @@ 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.ExperimentalMaterialApi import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold import androidx.compose.material.Text +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Surface import androidx.compose.material3.Tab @@ -292,21 +296,30 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. LoadingState() } is SiteMonitorUiState.Loaded -> { - SiteMonitorWebView(webView, modifier) + SiteMonitorWebView(webView, tabType, modifier) } else -> {} } } + @OptIn(ExperimentalMaterialApi::class) @Composable - private fun SiteMonitorWebView(tabWebView: WebView, modifier: Modifier = Modifier) { + private fun SiteMonitorWebView(tabWebView: WebView, tabType: SiteMonitorType, modifier: Modifier = Modifier) { // the webview is retrieved from the activity, so we need to use a mutable variable // to assign to android view - var webView = tabWebView + + val refreshState = siteMonitorParentViewModel.getRefreshState(tabType) + + val pullRefreshState = rememberPullRefreshState( + refreshing = refreshState.value, + onRefresh = { siteMonitorParentViewModel.refreshData(tabType) } + ) + Box( modifier = modifier .fillMaxSize() + .pullRefresh(pullRefreshState) ) { LazyColumn(modifier = Modifier.fillMaxHeight()) { item { @@ -317,6 +330,12 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. ) } } + PullRefreshIndicator( + refreshing = refreshState.value, + state = pullRefreshState, + modifier = Modifier.align(Alignment.TopCenter), + contentColor = MaterialTheme.colors.primaryVariant, + ) } } From 7beddb845039529d070c00eade475b023daf62d9 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Thu, 1 Feb 2024 12:20:14 +0530 Subject: [PATCH 160/176] =?UTF-8?q?=E2=86=92=20Moves:=20the=20logic=20of?= =?UTF-8?q?=20preparing=20address=20to=20background=20dispatcher?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/sitemonitor/SiteMonitorTabViewModelSlice.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) 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 425149c514b2..881f8d039cd7 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 @@ -3,22 +3,26 @@ package org.wordpress.android.ui.sitemonitor import android.text.TextUtils import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf +import kotlinx.coroutines.CoroutineDispatcher 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 javax.inject.Inject +import javax.inject.Named class SiteMonitorTabViewModelSlice @Inject constructor( + @param:Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, private val networkUtilsWrapper: NetworkUtilsWrapper, private val accountStore: AccountStore, private val mapper: SiteMonitorMapper, private val siteMonitorUtils: SiteMonitorUtils, private val siteStore: SiteStore, -){ +) { private lateinit var scope: CoroutineScope private lateinit var site: SiteModel @@ -77,8 +81,10 @@ class SiteMonitorTabViewModelSlice @Inject constructor( val sanitizedUrl = siteMonitorUtils.sanitizeSiteUrl(site.url) val url = urlTemplate.replace("{blog}", sanitizedUrl) - val addressToLoad = prepareAddressToLoad(url) - postUiState(mapper.toPrepared(url, addressToLoad, siteMonitorType)) + scope.launch(bgDispatcher) { + val addressToLoad = prepareAddressToLoad(url) + postUiState(mapper.toPrepared(url, addressToLoad, siteMonitorType)) + } } private fun prepareAddressToLoad(url: String): String { @@ -115,7 +121,7 @@ class SiteMonitorTabViewModelSlice @Inject constructor( } fun onUrlLoaded() { - if (uiState.value is SiteMonitorUiState.Prepared){ + if (uiState.value is SiteMonitorUiState.Prepared) { postUiState(SiteMonitorUiState.Loaded) } } From 61c2d9651814b5c3a62c22b991951b51c8bdd24e Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Thu, 1 Feb 2024 12:21:08 +0530 Subject: [PATCH 161/176] * Fixes: formatting --- .../android/ui/sitemonitor/SiteMonitorTabViewModelSlice.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 881f8d039cd7..ac55867fb678 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 @@ -32,7 +32,7 @@ class SiteMonitorTabViewModelSlice @Inject constructor( private val _uiState = mutableStateOf(SiteMonitorUiState.Preparing) val uiState: State = _uiState - private val _isRefreshing = mutableStateOf(false) + private val _isRefreshing = mutableStateOf(false) val isRefreshing: State = _isRefreshing fun initialize(scope: CoroutineScope) { @@ -63,7 +63,7 @@ class SiteMonitorTabViewModelSlice @Inject constructor( _isRefreshing.value = false } - private fun checkForInternetConnectivityAndPostErrorIfNeeded() : Boolean { + private fun checkForInternetConnectivityAndPostErrorIfNeeded(): Boolean { if (networkUtilsWrapper.isNetworkAvailable()) return true postUiState(mapper.toNoNetworkError(::loadView)) return false @@ -110,7 +110,7 @@ class SiteMonitorTabViewModelSlice @Inject constructor( addressToLoad, username, "", - accessToken?:"" + accessToken ?: "" ) } From 9a5f65dd7784d61c327966e182f6774003365bcc Mon Sep 17 00:00:00 2001 From: Derek Blank Date: Thu, 1 Feb 2024 17:03:32 +1000 Subject: [PATCH 162/176] Release script: Update build.gradle gutenbergMobileVersion to ref --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 949cd82ae741..76a7cd265046 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-alpha5' + gutenbergMobileVersion = '6597-5d9a47fd0849cc6f47a035704101ed9d2097f26e' wordPressAztecVersion = 'v2.0' wordPressFluxCVersion = '2.64.0' wordPressLoginVersion = '1.11.0' From 45e9be700b7eab674cfdaff54507ffc65b36e701 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Thu, 1 Feb 2024 12:59:13 +0530 Subject: [PATCH 163/176] + Adds: test for refresh logic in viewmodel --- .../SiteMonitorParentViewModelTest.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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 index 411f72a9a442..98d3ddf0e3a1 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorParentViewModelTest.kt @@ -167,4 +167,25 @@ class SiteMonitorParentViewModelTest: BaseUnitTest(){ verify(webServerViewModel).onWebViewError() } + + @Test + fun `given metrics, when refresh is invoked, then metric vm slice refresh is invoked`() { + viewModel.refreshData(SiteMonitorType.METRICS) + + verify(metricsViewModel).refreshData() + } + + @Test + fun `given php logs, when refresh is invoked, then php logs vm slice refresh is invoked`() { + viewModel.refreshData(SiteMonitorType.PHP_LOGS) + + verify(phpLogViewModel).refreshData() + } + + @Test + fun `given webserver logs, when refresh is invoked, then webserver vm slice refresh is invoked`() { + viewModel.refreshData(SiteMonitorType.WEB_SERVER_LOGS) + + verify(webServerViewModel).refreshData() + } } From 1859174c8a7d964a2f813fd3608dd219e0cdcd97 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Thu, 1 Feb 2024 13:11:46 +0530 Subject: [PATCH 164/176] =?UTF-8?q?=E2=86=92=20Fixes:=20incorrect=20depend?= =?UTF-8?q?ency=20in=20test=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../android/ui/sitemonitor/SiteMonitorTabViewModelSliceTest.kt | 1 + 1 file changed, 1 insertion(+) 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 index 3fe113c67fb7..830aca21dd4e 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSliceTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSliceTest.kt @@ -34,6 +34,7 @@ class SiteMonitorTabViewModelSliceTest : BaseUnitTest() { @Before fun setUp() = test { viewModel = SiteMonitorTabViewModelSlice( + testDispatcher(), networkUtilsWrapper, accountStore, mapper, From 34b6d4a5d86ec638724dcc2aba27879e1b59e5c0 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Thu, 1 Feb 2024 15:30:10 +0530 Subject: [PATCH 165/176] + Adds: a delay for the refresh --- .../sitemonitor/SiteMonitorTabViewModelSlice.kt | 15 ++++++++++++--- .../SiteMonitorTabViewModelSliceTest.kt | 15 +++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) 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 ac55867fb678..91dea1294b59 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 @@ -6,6 +6,7 @@ import androidx.compose.runtime.mutableStateOf import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.AccountStore @@ -15,6 +16,8 @@ import org.wordpress.android.util.NetworkUtilsWrapper import javax.inject.Inject import javax.inject.Named +const val REFRESH_DELAY = 500L + class SiteMonitorTabViewModelSlice @Inject constructor( @param:Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher, private val networkUtilsWrapper: NetworkUtilsWrapper, @@ -58,9 +61,15 @@ class SiteMonitorTabViewModelSlice @Inject constructor( } fun refreshData() { - _isRefreshing.value = true - loadView() - _isRefreshing.value = false + scope.launch { + _isRefreshing.value = true + // this delay is to prevent the refresh from being too fast + // so that the user can see the refresh animation + // also this would fix the unit tests + delay(REFRESH_DELAY) + loadView() + _isRefreshing.value = false + } } private fun checkForInternetConnectivityAndPostErrorIfNeeded(): Boolean { 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 index 830aca21dd4e..02eb59f3a157 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSliceTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/sitemonitor/SiteMonitorTabViewModelSliceTest.kt @@ -31,6 +31,8 @@ class SiteMonitorTabViewModelSliceTest : BaseUnitTest() { val site = mock() + val refreshStates = mutableListOf() + @Before fun setUp() = test { viewModel = SiteMonitorTabViewModelSlice( @@ -120,6 +122,19 @@ class SiteMonitorTabViewModelSliceTest : BaseUnitTest() { assertThat(viewModel.uiState.value).isInstanceOf(SiteMonitorUiState.GenericError::class.java) } + @Test + fun `given loaded state, when refresh is invoked, then uiState loaded is posted`() = test { + viewModel.start(SiteMonitorType.METRICS, SiteMonitorTabItem.Metrics.urlTemplate, site) + advanceUntilIdle() + viewModel.onUrlLoaded() + viewModel.refreshData() + + assertThat(viewModel.isRefreshing.value).isTrue() + advanceUntilIdle() + assertThat(viewModel.uiState.value).isInstanceOf(SiteMonitorUiState.Prepared::class.java) + assertThat(viewModel.isRefreshing.value).isFalse() + } + companion object { const val USER_NAME = "user_name" const val ACCESS_TOKEN = "access_token" From e9085533946d86d1b1ae97a774620dbc7aba7f04 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Thu, 1 Feb 2024 12:36:28 +0200 Subject: [PATCH 166/176] Modify color of progress indicator in site monitor screen --- .../android/ui/sitemonitor/SiteMonitorParentActivity.kt | 4 +++- 1 file changed, 3 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 3c015c61d3be..aaf7705baf21 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 @@ -236,7 +236,9 @@ class SiteMonitorParentActivity : AppCompatActivity(), SiteMonitorWebViewClient. contentAlignment = Alignment.Center, modifier = modifier.fillMaxSize() ) { - CircularProgressIndicator() + CircularProgressIndicator( + color = MaterialTheme.colors.onSurface + ) } } From 4d423dfcc55eb23f10ac86d3c14c1db2bd29489d Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Thu, 1 Feb 2024 08:24:12 -0500 Subject: [PATCH 167/176] Refactor: move the site monitoring row after the manage rows --- .../android/ui/mysite/items/listitem/SiteItemsBuilder.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteItemsBuilder.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteItemsBuilder.kt index fb3fcc0fdad5..2727c43d1e2a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteItemsBuilder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/items/listitem/SiteItemsBuilder.kt @@ -91,8 +91,8 @@ class SiteItemsBuilder @Inject constructor( private fun getManageSiteItems( params: SiteItemsBuilderParams ): List { - val siteMonitoring = buildSiteMonitoringOptionsIfNeeded(params) val manageSiteItems = buildManageSiteItems(params) + val siteMonitoring = buildSiteMonitoringOptionsIfNeeded(params) val emptyHeaderItem1 = CategoryEmptyHeaderItem(UiString.UiStringText("")) val jetpackConfiguration = buildJetpackDependantConfigurationItemsIfNeeded(params) @@ -102,8 +102,8 @@ class SiteItemsBuilder @Inject constructor( val emptyHeaderItem2 = CategoryEmptyHeaderItem(UiString.UiStringText("")) val admin = siteListItemBuilder.buildAdminItemIfAvailable(params.site, params.onClick) return listOf(manageHeader) + - siteMonitoring + manageSiteItems + + siteMonitoring + emptyHeaderItem1 + jetpackConfiguration + lookAndFeel + From f612aacbf7dbbe9542c14a0832d680942771b7f3 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Thu, 1 Feb 2024 08:24:31 -0500 Subject: [PATCH 168/176] Update tests to align with the site monitor row position change --- .../ui/mysite/items/SiteItemsBuilderTest.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/SiteItemsBuilderTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/SiteItemsBuilderTest.kt index 073277c6f50e..7c51b34c2978 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/SiteItemsBuilderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/mysite/items/SiteItemsBuilderTest.kt @@ -76,8 +76,8 @@ class SiteItemsBuilderTest { @Test fun `adds all the items in the correct order`() { setupHeaders( - addSiteMonitoringItem = true, addActivityLogItem = true, + addSiteMonitoringItem = true, addPlanItem = false, addPagesItem = true, addAdminItem = true, @@ -107,10 +107,10 @@ class SiteItemsBuilderTest { TRAFFIC_HEADER, STATS_ITEM, MANAGE_HEADER, - SITE_MONITORING_ITEM, ACTIVITY_ITEM, BACKUP_ITEM, SCAN_ITEM, + SITE_MONITORING_ITEM, EMPTY_HEADER, PEOPLE_ITEM, PLUGINS_ITEM, @@ -231,8 +231,8 @@ class SiteItemsBuilderTest { @Suppress("ComplexMethod", "LongMethod") private fun setupHeaders( - addSiteMonitoringItem: Boolean = false, addActivityLogItem: Boolean = false, + addSiteMonitoringItem: Boolean = false, addPlanItem: Boolean = false, addPagesItem: Boolean = false, addAdminItem: Boolean = false, @@ -258,11 +258,6 @@ class SiteItemsBuilderTest { PLAN_ITEM.copy(showFocusPoint = showPlansFocusPoint) ) } - if (addSiteMonitoringItem) { - whenever(siteListItemBuilder.buildSiteMonitoringItemIfAvailable(siteModel, SITE_ITEM_ACTION)).thenReturn( - SITE_MONITORING_ITEM - ) - } if (addActivityLogItem) { whenever(siteListItemBuilder.buildActivityLogItemIfAvailable(siteModel, SITE_ITEM_ACTION)).thenReturn( ACTIVITY_ITEM @@ -278,6 +273,11 @@ class SiteItemsBuilderTest { SCAN_ITEM ) } + if (addSiteMonitoringItem) { + whenever(siteListItemBuilder.buildSiteMonitoringItemIfAvailable(siteModel, SITE_ITEM_ACTION)).thenReturn( + SITE_MONITORING_ITEM + ) + } if (addPagesItem) { whenever( siteListItemBuilder.buildPagesItemIfAvailable( From 9f161252db5ceb852da7cb6e537bdf8058b95d4e Mon Sep 17 00:00:00 2001 From: Irfan Omur Date: Thu, 1 Feb 2024 20:34:21 +0300 Subject: [PATCH 169/176] Upgrade Login lib version to 1.12.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b909a47e97fc..0d488480c475 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ ext { gutenbergMobileVersion = 'v1.112.0-alpha5' wordPressAztecVersion = 'v2.0' wordPressFluxCVersion = '2.64.0' - wordPressLoginVersion = '1.11.0' + wordPressLoginVersion = '1.12.0' wordPressPersistentEditTextVersion = '1.0.2' wordPressUtilsVersion = '3.12.0' indexosMediaForMobileVersion = '43a9026f0973a2f0a74fa813132f6a16f7499c3a' From e27b845e775e105a82b51a79d88121f3a3178200 Mon Sep 17 00:00:00 2001 From: Thomas Horta Date: Thu, 1 Feb 2024 16:28:41 -0300 Subject: [PATCH 170/176] Update the onboarding screen title to say "Interests" --- .../src/main/res/layout/reader_interests_fragment_layout.xml | 2 +- WordPress/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/res/layout/reader_interests_fragment_layout.xml b/WordPress/src/main/res/layout/reader_interests_fragment_layout.xml index 22d0129f84ce..519613821ede 100644 --- a/WordPress/src/main/res/layout/reader_interests_fragment_layout.xml +++ b/WordPress/src/main/res/layout/reader_interests_fragment_layout.xml @@ -66,7 +66,7 @@ More from %s More on WordPress.com Visit site - Choose your topics + Choose your interests View comments Welcome to Reader. Discover millions of blogs at your fingertips. Back From 2ce97ec71e2b3317ed2bc3c115c32647f2eb759d Mon Sep 17 00:00:00 2001 From: Thomas Horta Date: Thu, 1 Feb 2024 16:30:12 -0300 Subject: [PATCH 171/176] Show Discover Welcome state if only following dailyprompt tag --- .../discover/ReaderDiscoverViewModel.kt | 6 +++- .../interests/ReaderInterestsViewModel.kt | 5 ++- .../discover/ReaderDiscoverViewModelTest.kt | 24 ++++++++++++++ .../interests/ReaderInterestsViewModelTest.kt | 33 +++++++++++++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModel.kt index c9b02681ea84..2e7c7b954b95 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModel.kt @@ -16,6 +16,7 @@ import org.wordpress.android.models.discover.ReaderDiscoverCard.ReaderRecommende import org.wordpress.android.models.discover.ReaderDiscoverCards import org.wordpress.android.modules.IO_THREAD import org.wordpress.android.modules.UI_THREAD +import org.wordpress.android.ui.bloggingprompts.BloggingPromptsPostTagProvider.Companion.BLOGGING_PROMPT_TAG import org.wordpress.android.ui.pages.SnackbarMessageHolder import org.wordpress.android.ui.reader.ReaderTypes.ReaderPostListType.TAG_FOLLOWED import org.wordpress.android.ui.reader.discover.ReaderCardUiState.ReaderPostNewUiState @@ -149,7 +150,10 @@ class ReaderDiscoverViewModel @Inject constructor( _uiState.addSource(readerDiscoverDataProvider.discoverFeed) { posts -> launch { val userTags = getFollowedTagsUseCase.get() - if (userTags.isEmpty()) { + + // since new users have the dailyprompt tag followed by default, we need to ignore them when + // checking if the user has any tags followed, so we show the onboarding state (ShowNoFollowedTags) + if (userTags.filterNot { it.tagSlug == BLOGGING_PROMPT_TAG }.isEmpty()) { _uiState.value = DiscoverUiState.EmptyUiState.ShowNoFollowedTagsUiState { parentViewModel.onShowReaderInterests() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/interests/ReaderInterestsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/interests/ReaderInterestsViewModel.kt index fc06dca994c3..67be5e9cd0ec 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/interests/ReaderInterestsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/discover/interests/ReaderInterestsViewModel.kt @@ -11,6 +11,7 @@ import org.wordpress.android.R import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.models.ReaderTag import org.wordpress.android.models.ReaderTagList +import org.wordpress.android.ui.bloggingprompts.BloggingPromptsPostTagProvider.Companion.BLOGGING_PROMPT_TAG import org.wordpress.android.ui.pages.SnackbarMessageHolder import org.wordpress.android.ui.reader.discover.interests.ReaderInterestsFragment.EntryPoint import org.wordpress.android.ui.reader.discover.interests.ReaderInterestsViewModel.DoneButtonUiState.DoneButtonDisabledUiState @@ -92,7 +93,9 @@ class ReaderInterestsViewModel @Inject constructor( } private fun checkAndLoadInterests(userTags: ReaderTagList) { - if (userTags.isEmpty()) { + // since new users have the dailyprompt tag followed by default, we need to ignore them when + // checking if the user has any tags followed, so we show the onboarding state (ShowNoFollowedTags) + if (userTags.filterNot { it.tagSlug == BLOGGING_PROMPT_TAG }.isEmpty()) { loadInterests(userTags) } else { parentViewModel?.onCloseReaderInterests() diff --git a/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModelTest.kt index 1db7219634ec..064409261b3c 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/ReaderDiscoverViewModelTest.kt @@ -24,6 +24,7 @@ import org.wordpress.android.models.ReaderBlog import org.wordpress.android.models.ReaderPost import org.wordpress.android.models.ReaderTag import org.wordpress.android.models.ReaderTagList +import org.wordpress.android.models.ReaderTagType import org.wordpress.android.models.discover.ReaderDiscoverCard.InterestsYouMayLikeCard import org.wordpress.android.models.discover.ReaderDiscoverCard.ReaderPostCard import org.wordpress.android.models.discover.ReaderDiscoverCard.ReaderRecommendedBlogsCard @@ -292,6 +293,29 @@ class ReaderDiscoverViewModelTest : BaseUnitTest() { assertThat(uiStates[1]).isInstanceOf(ShowNoFollowedTagsUiState::class.java) } + @Test + fun `ShowFollowInterestsEmptyUiState is shown when the user follows only the daily prompt tag`() = test { + // Arrange + val tagsWithDailyPrompt = ReaderTagList().apply { + add( + ReaderTag( + "dailyprompt", + "dailyprompt", + "dailyprompt", + "https://public-api.wordpress.com/rest/v1.2/read/tags/dailyprompt/posts", + ReaderTagType.DEFAULT + ) + ) + } + whenever(getFollowedTagsUseCase.get()).thenReturn(tagsWithDailyPrompt) + val uiStates = init().uiStates + // Act + viewModel.start(parentViewModel) + // Assert + assertThat(uiStates.size).isEqualTo(2) + assertThat(uiStates[1]).isInstanceOf(ShowNoFollowedTagsUiState::class.java) + } + @Test fun `ShowNoPostsUiState is shown when the discoverFeed does not contain any posts`() = test { // Arrange diff --git a/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/interests/ReaderInterestsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/interests/ReaderInterestsViewModelTest.kt index 4b3451b7141c..1943a6a2f15a 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/interests/ReaderInterestsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/reader/discover/interests/ReaderInterestsViewModelTest.kt @@ -87,6 +87,20 @@ class ReaderInterestsViewModelTest : BaseUnitTest() { verify(readerTagRepository, times(1)).getInterests() } + @Test + fun `getInterests invoked if only daily prompt user tag received from repo`() = + testWithDailyPromptUserTag { + // Given + val interests = getInterests() + whenever(readerTagRepository.getInterests()).thenReturn(SuccessWithData(interests)) + + // When + initViewModel() + + // Then + verify(readerTagRepository, times(1)).getInterests() + } + @Test fun `discover close reader screen triggered if non empty user tags are received from repo`() = testWithNonEmptyUserTags { @@ -602,6 +616,25 @@ class ReaderInterestsViewModelTest : BaseUnitTest() { } } + private fun testWithDailyPromptUserTag(block: suspend CoroutineScope.() -> T) { + test { + val tagsWithDailyPrompt = ReaderTagList().apply { + add( + ReaderTag( + "dailyprompt", + "dailyprompt", + "dailyprompt", + "https://public-api.wordpress.com/rest/v1.2/read/tags/dailyprompt/posts", + ReaderTagType.DEFAULT + ) + ) + } + + whenever(readerTagRepository.getUserTags()).thenReturn(SuccessWithData(tagsWithDailyPrompt)) + block() + } + } + private fun testWithFailedUserTags(block: suspend CoroutineScope.() -> T) { test { whenever(readerTagRepository.getUserTags()).thenReturn(NetworkUnavailable) From ab48882c6450e3fc229609dd77cb7624d70f9503 Mon Sep 17 00:00:00 2001 From: Thomas Horta Date: Thu, 1 Feb 2024 18:44:45 -0300 Subject: [PATCH 172/176] Only initialize reader content fragment if it actually changed --- .../java/org/wordpress/android/ui/reader/ReaderFragment.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt index b0bd2a03f7d6..254244188d6f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt @@ -232,6 +232,11 @@ class ReaderFragment : Fragment(R.layout.reader_fragment_layout), MenuProvider, if (uiState.selectedReaderTag == null) { return } + + // only initialize the fragment if it's not already initialized + val currentFragmentTag = childFragmentManager.findFragmentById(R.id.container)?.tag + if (currentFragmentTag == uiState.selectedReaderTag.tagSlug) return + childFragmentManager.beginTransaction().apply { val fragment = if (uiState.selectedReaderTag.isDiscover()) { ReaderDiscoverFragment() @@ -243,7 +248,7 @@ class ReaderFragment : Fragment(R.layout.reader_fragment_layout), MenuProvider, uiState.selectedReaderTag.isFilterable ) } - replace(R.id.container, fragment) + replace(R.id.container, fragment, uiState.selectedReaderTag.tagSlug) commit() } viewModel.uiState.value?.let { From 8b4a630205f5ab8e563d9c0d6168bcc87d4dafad Mon Sep 17 00:00:00 2001 From: Derek Blank Date: Fri, 2 Feb 2024 10:11:56 +1000 Subject: [PATCH 173/176] Release script: Update build.gradle gutenbergMobileVersion to ref --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 76a7cd265046..00dfbf4acc4a 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 = '6597-5d9a47fd0849cc6f47a035704101ed9d2097f26e' + gutenbergMobileVersion = 'v1.112.0' wordPressAztecVersion = 'v2.0' wordPressFluxCVersion = '2.64.0' wordPressLoginVersion = '1.11.0' From 9aaa1d4410fd2094ae8f1b82128f0a8ac28e603b Mon Sep 17 00:00:00 2001 From: Derek Blank Date: Fri, 2 Feb 2024 11:39:55 +1000 Subject: [PATCH 174/176] Update RELEASE-NOTES for 24.2 --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index e2e517ec71ba..29d99a781ffb 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -4,6 +4,7 @@ ----- * [**] 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] +* [**] Prevent images from temporarily disappearing when uploading media [https://github.com/WordPress/gutenberg/pull/57869] 24.1 ----- From d1cdbf156b0a79aa094245c9d763a68ec0ea1f81 Mon Sep 17 00:00:00 2001 From: Ajesh R Pai Date: Fri, 2 Feb 2024 13:50:03 +0530 Subject: [PATCH 175/176] * Fixes: the crash by checking if the site is nulll --- .../campaignlisting/CampaignListingFragment.kt | 3 +++ .../campaignlisting/CampaignListingViewModel.kt | 12 ++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/blaze/blazecampaigns/campaignlisting/CampaignListingFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/blaze/blazecampaigns/campaignlisting/CampaignListingFragment.kt index 504bbcbb3762..50fd4a712e83 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/blaze/blazecampaigns/campaignlisting/CampaignListingFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/blaze/blazecampaigns/campaignlisting/CampaignListingFragment.kt @@ -118,6 +118,9 @@ class CampaignListingFragment : Fragment() { } } } + viewModel.onSelectedSiteMissing.observe(viewLifecycleOwner) { + requireActivity().finish() + } } private fun getPageSource(): CampaignListingPageSource { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/blaze/blazecampaigns/campaignlisting/CampaignListingViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/blaze/blazecampaigns/campaignlisting/CampaignListingViewModel.kt index c3fc182097ba..182a29884a17 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/blaze/blazecampaigns/campaignlisting/CampaignListingViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/blaze/blazecampaigns/campaignlisting/CampaignListingViewModel.kt @@ -7,8 +7,8 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow -import org.wordpress.android.Result import org.wordpress.android.R +import org.wordpress.android.Result import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.modules.BG_THREAD import org.wordpress.android.ui.blaze.BlazeFeatureUtils @@ -47,12 +47,20 @@ class CampaignListingViewModel @Inject constructor( private val _snackbar = MutableSharedFlow() val snackBar = _snackbar.asSharedFlow() + private val _onSelectedSiteMissing = MutableLiveData() + val onSelectedSiteMissing = _onSelectedSiteMissing as LiveData + private var page = 1 private var limitPerPage: Int = 10 private var isLastPage: Boolean = false fun start(campaignListingPageSource: CampaignListingPageSource) { - this.site = selectedSiteRepository.getSelectedSite()!! + val site = selectedSiteRepository.getSelectedSite() + if (site == null) { + _onSelectedSiteMissing.value = Unit + return + } + this.site = site blazeFeatureUtils.trackCampaignListingPageShown(campaignListingPageSource) loadCampaigns() } From c90f4ae6242415ec45c00025c2caa365ec04cca3 Mon Sep 17 00:00:00 2001 From: Thomas Horta Date: Fri, 2 Feb 2024 09:48:29 -0300 Subject: [PATCH 176/176] Refactor to avoid multiple return calls --- .../org/wordpress/android/ui/reader/ReaderFragment.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt index 254244188d6f..f11743b16f17 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt @@ -229,16 +229,14 @@ class ReaderFragment : Fragment(R.layout.reader_fragment_layout), MenuProvider, } private fun initContentContainer(uiState: ContentUiState) { - if (uiState.selectedReaderTag == null) { + // only initialize the fragment if there's one selected and it's not already initialized + val currentFragmentTag = childFragmentManager.findFragmentById(R.id.container)?.tag + if (uiState.selectedReaderTag == null || uiState.selectedReaderTag.tagSlug == currentFragmentTag) { return } - // only initialize the fragment if it's not already initialized - val currentFragmentTag = childFragmentManager.findFragmentById(R.id.container)?.tag - if (currentFragmentTag == uiState.selectedReaderTag.tagSlug) return - childFragmentManager.beginTransaction().apply { - val fragment = if (uiState.selectedReaderTag.isDiscover()) { + val fragment = if (uiState.selectedReaderTag.isDiscover) { ReaderDiscoverFragment() } else { ReaderPostListFragment.newInstanceForTag(