From 577ae45adf0ec8167a055765c7e863f887ac6ab5 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Tue, 27 Feb 2024 17:25:33 +0200 Subject: [PATCH 1/9] Use development FluxC version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5c37ad7f85b7..d1166836c069 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ ext { automatticTracksVersion = '3.4.0' gutenbergMobileVersion = 'v1.114.0' wordPressAztecVersion = 'v2.0' - wordPressFluxCVersion = '2.70.0' + wordPressFluxCVersion = '2957-64735ca1008922a05c7cd0501b01b511784f87f1' wordPressLoginVersion = '1.14.1' wordPressPersistentEditTextVersion = '1.0.2' wordPressUtilsVersion = '3.13.0' From 8d570ed87664d261d6aed113dcb8b2755adf3dc4 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Tue, 27 Feb 2024 17:27:00 +0200 Subject: [PATCH 2/9] Add PostFreshnessChecker --- .../wordpress/android/modules/PostModule.kt | 15 +++++++ .../android/ui/posts/IPostFreshnessChecker.kt | 16 ++++++++ .../ui/posts/PostFreshnessCheckerImpl.kt | 25 ++++++++++++ .../android/ui/posts/PostUtilsWrapper.kt | 9 ++++- .../ui/posts/PostFreshnessCheckerImplTest.kt | 39 +++++++++++++++++++ .../android/ui/posts/PostSettingsUtilsTest.kt | 4 +- 6 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 WordPress/src/main/java/org/wordpress/android/modules/PostModule.kt create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/posts/IPostFreshnessChecker.kt create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/posts/PostFreshnessCheckerImpl.kt create mode 100644 WordPress/src/test/java/org/wordpress/android/ui/posts/PostFreshnessCheckerImplTest.kt diff --git a/WordPress/src/main/java/org/wordpress/android/modules/PostModule.kt b/WordPress/src/main/java/org/wordpress/android/modules/PostModule.kt new file mode 100644 index 000000000000..1ad6deb78848 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/modules/PostModule.kt @@ -0,0 +1,15 @@ +package org.wordpress.android.modules + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import org.wordpress.android.ui.posts.IPostFreshnessChecker +import org.wordpress.android.ui.posts.PostFreshnessCheckerImpl + +@InstallIn(SingletonComponent::class) +@Module +class PostModule { + @Provides + fun providePostFreshnessChecker(): IPostFreshnessChecker = PostFreshnessCheckerImpl() +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/IPostFreshnessChecker.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/IPostFreshnessChecker.kt new file mode 100644 index 000000000000..0b97fd520f47 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/IPostFreshnessChecker.kt @@ -0,0 +1,16 @@ +package org.wordpress.android.ui.posts + +import org.wordpress.android.fluxc.model.PostImmutableModel + +/** + * This interface is implemented by a component that determines if a post + * is "fresh" or we need to refetch it from the backend. + */ +interface IPostFreshnessChecker { + fun shouldRefreshPost(post: PostImmutableModel): Boolean +} + +interface TimeProvider { + fun currentTimeMillis(): Long +} + diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/PostFreshnessCheckerImpl.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/PostFreshnessCheckerImpl.kt new file mode 100644 index 000000000000..26f1643b1770 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/PostFreshnessCheckerImpl.kt @@ -0,0 +1,25 @@ +package org.wordpress.android.ui.posts + +import org.wordpress.android.fluxc.model.PostImmutableModel + +class PostFreshnessCheckerImpl( + private val timeProvider: TimeProvider = SystemTimeProvider() +) : IPostFreshnessChecker { + override fun shouldRefreshPost(post: PostImmutableModel): Boolean { + return postNeedsRefresh(post) + } + + private fun postNeedsRefresh(post: PostImmutableModel) : Boolean { + return timeProvider.currentTimeMillis() - post.dbTimestamp > CACHE_VALIDITY_MILLIS + } + + companion object { + // Todo turn this into a remote config value + const val CACHE_VALIDITY_MILLIS = 20000 + } +} + +class SystemTimeProvider : TimeProvider { + override fun currentTimeMillis(): Long = System.currentTimeMillis() +} + diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/PostUtilsWrapper.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/PostUtilsWrapper.kt index 8c622c138a56..bcc2226d08c2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/PostUtilsWrapper.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/PostUtilsWrapper.kt @@ -16,7 +16,11 @@ import javax.inject.Inject * */ @Reusable -class PostUtilsWrapper @Inject constructor(private val dateProvider: DateProvider) { +class PostUtilsWrapper +@Inject constructor( + private val dateProvider: DateProvider, + private val postFreshnessChecker: IPostFreshnessChecker +) { fun isPublishable(post: PostImmutableModel) = PostUtils.isPublishable(post) fun isPostInConflictWithRemote(post: PostImmutableModel) = @@ -51,4 +55,7 @@ class PostUtilsWrapper @Inject constructor(private val dateProvider: DateProvide fun shouldPublishImmediatelyOptionBeAvailable(status: PostStatus?) = PostUtils.shouldPublishImmediatelyOptionBeAvailable(status) + + fun shouldRefreshPost(post: PostImmutableModel) : Boolean = + postFreshnessChecker.shouldRefreshPost(post) } diff --git a/WordPress/src/test/java/org/wordpress/android/ui/posts/PostFreshnessCheckerImplTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/posts/PostFreshnessCheckerImplTest.kt new file mode 100644 index 000000000000..639c3312cdcd --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/posts/PostFreshnessCheckerImplTest.kt @@ -0,0 +1,39 @@ +package org.wordpress.android.ui.posts + +import org.junit.Test +import org.mockito.kotlin.mock +import org.wordpress.android.fluxc.model.PostImmutableModel +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class PostFreshnessCheckerImplTest { + private val fixedCurrentTimeMillis = 100_000L // Example current time in milliseconds + private val timeProvider = object : TimeProvider { + override fun currentTimeMillis() = fixedCurrentTimeMillis + } + + private val postFreshnessChecker = PostFreshnessCheckerImpl(timeProvider) + + @Test + fun `should refresh post when post is older than cache validity`() { + // Post timestamp is set to simulate being older than the cache validity + val postTimestamp = fixedCurrentTimeMillis - PostFreshnessCheckerImpl.CACHE_VALIDITY_MILLIS - 1 + val post = mock { + on { dbTimestamp }.thenReturn(postTimestamp) + } + + // Adjust the system time or post creation time as needed to reflect the scenario being tested + assertTrue(postFreshnessChecker.shouldRefreshPost(post)) + } + + @Test + fun `should not refresh post when post is within cache validity`() { + // Post timestamp is set to simulate being within the cache validity period + val postTimestamp = fixedCurrentTimeMillis - PostFreshnessCheckerImpl.CACHE_VALIDITY_MILLIS + 1 + val post = mock { + on { dbTimestamp }.thenReturn(postTimestamp) + } + + assertFalse(postFreshnessChecker.shouldRefreshPost(post)) + } +} diff --git a/WordPress/src/test/java/org/wordpress/android/ui/posts/PostSettingsUtilsTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/posts/PostSettingsUtilsTest.kt index 3fb8fa7fe09c..1dca48152310 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/posts/PostSettingsUtilsTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/posts/PostSettingsUtilsTest.kt @@ -27,6 +27,8 @@ class PostSettingsUtilsTest : BaseUnitTest() { @Mock lateinit var dateProvider: DateProvider + @Mock + lateinit var postFreshnessCheckerImpl: IPostFreshnessChecker private lateinit var postSettingsUtils: PostSettingsUtils private lateinit var postUtilsWrapper: PostUtilsWrapper @@ -37,7 +39,7 @@ class PostSettingsUtilsTest : BaseUnitTest() { @Before fun setUp() { - postUtilsWrapper = PostUtilsWrapper(dateProvider) + postUtilsWrapper = PostUtilsWrapper(dateProvider, postFreshnessCheckerImpl) postSettingsUtils = PostSettingsUtils(resourceProvider, mStatsDateUtils, postUtilsWrapper) whenever(mStatsDateUtils.formatDateTime(any())).thenReturn(formattedDate) whenever(dateProvider.getCurrentDate()).thenReturn(DateTimeUtils.dateUTCFromIso8601(currentDate)) From ab91a45ff3425a1e91d2a2bf96dabe10e9290f29 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Tue, 27 Feb 2024 17:27:40 +0200 Subject: [PATCH 3/9] Check post freshness before editing --- .../android/ui/posts/EditPostActivity.java | 41 ++++++++++++++++++- .../ui/posts/editor/StorePostViewModel.kt | 35 ++++++++++++++++ .../res/layout/new_edit_post_activity.xml | 38 +++++++++++++++++ WordPress/src/main/res/values/colors.xml | 4 ++ WordPress/src/main/res/values/strings.xml | 2 + 5 files changed, 119 insertions(+), 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 20d861c576fd..a36829037fa5 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 @@ -17,6 +17,7 @@ import android.view.View; import android.view.ViewGroup; import android.webkit.MimeTypeMap; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.Toast; @@ -382,6 +383,8 @@ enum RestartEditorOptions { private boolean mHtmlModeMenuStateOn = false; + private FrameLayout mUpdatingPostArea; + @Inject Dispatcher mDispatcher; @Inject AccountStore mAccountStore; @Inject SiteStore mSiteStore; @@ -558,12 +561,15 @@ public void handleOnBackPressed() { getOnBackPressedDispatcher().addCallback(this, callback); mDispatcher.register(this); + + // initialise ViewModels mViewModel = new ViewModelProvider(this, mViewModelFactory).get(StorePostViewModel.class); mStorageUtilsViewModel = new ViewModelProvider(this, mViewModelFactory).get(StorageUtilsViewModel.class); mEditorBloggingPromptsViewModel = new ViewModelProvider(this, mViewModelFactory) .get(EditorBloggingPromptsViewModel.class); mEditorJetpackSocialViewModel = new ViewModelProvider(this, mViewModelFactory) .get(EditorJetpackSocialViewModel.class); + setContentView(R.layout.new_edit_post_activity); createEditShareMessageActivityResultLauncher(); @@ -615,7 +621,6 @@ public void handleOnBackPressed() { mToolbar = findViewById(R.id.toolbar_main); setSupportActionBar(mToolbar); - final ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(false); @@ -797,6 +802,19 @@ public void handleOnBackPressed() { mEditorJetpackSocialViewModel.start(mSite, mEditPostRepository); customizeToolbar(); + + mUpdatingPostArea = findViewById(R.id.updating); + + // check if post content needs updating + mViewModel.checkIfUpdatedPostVersionExists(mEditPostRepository, mSite); + } + + private void showUpdatingPostArea() { + mUpdatingPostArea.setVisibility(View.VISIBLE); + } + + private void hideUpdatingPostArea() { + mUpdatingPostArea.setVisibility(View.GONE); } private void customizeToolbar() { @@ -1013,6 +1031,27 @@ private void startObserving() { ); } }); + + mViewModel.getOnPostUpdateUiVisible().observe(this, isVisible -> { + if (isVisible) { + showUpdatingPostArea(); + } else { + hideUpdatingPostArea(); + } + }); + + mViewModel.getOnPostUpdateResult().observe(this, isSuccess -> { + if (isSuccess) { + mEditPostRepository.loadPostByLocalPostId(mEditPostRepository.getId()); + refreshEditorContent(); + } else { + ToastUtils.showToast( + EditPostActivity.this, + getString(R.string.editor_updating_post_failed), + ToastUtils.Duration.SHORT + ); + } + }); } private void initializePostObject() { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/StorePostViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/StorePostViewModel.kt index 5aa35762de68..3b1fe994920c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/StorePostViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/StorePostViewModel.kt @@ -12,11 +12,14 @@ import org.wordpress.android.editor.gutenberg.DialogVisibility.Hidden import org.wordpress.android.editor.gutenberg.DialogVisibility.Showing import org.wordpress.android.editor.gutenberg.DialogVisibilityProvider import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.generated.PostActionBuilder +import org.wordpress.android.fluxc.model.CauseOfOnPostChanged import org.wordpress.android.fluxc.model.PostImmutableModel import org.wordpress.android.fluxc.model.PostModel import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.PostStore.OnPostChanged import org.wordpress.android.fluxc.store.PostStore.OnPostUploaded +import org.wordpress.android.fluxc.store.PostStore.RemotePostPayload import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.posts.EditPostRepository @@ -64,6 +67,12 @@ class StorePostViewModel } override val savingInProgressDialogVisibility: LiveData = _savingProgressDialogVisibility + private val _onPostUpdateUiVisible = MutableLiveData() + val onPostUpdateUiVisible: LiveData = _onPostUpdateUiVisible + + private val _onPostUpdateResult = MutableLiveData() + val onPostUpdateResult: LiveData = _onPostUpdateResult + init { dispatcher.register(this) } @@ -190,6 +199,21 @@ class StorePostViewModel _onFinish.postValue(Event(state)) } + fun checkIfUpdatedPostVersionExists( + editPostRepository: EditPostRepository, + site: SiteModel + ) { + editPostRepository.getPost()?.let { postModel -> + if (!postModel.isLocalDraft + && !postModel.isLocallyChanged + && postUtils.shouldRefreshPost(postModel)) { + _onPostUpdateUiVisible.postValue(true) + val payload = RemotePostPayload(editPostRepository.getEditablePost(), site) + dispatcher.dispatch(PostActionBuilder.newFetchPostAction(payload)) + } + } + } + @Suppress("unused", "UNUSED_PARAMETER") @Subscribe fun onPostUploaded(event: OnPostUploaded) { @@ -200,6 +224,17 @@ class StorePostViewModel @Subscribe fun onPostChanged(event: OnPostChanged) { hideSavingProgressDialog() + + // Refresh post content if needed + (event.causeOfChange as? CauseOfOnPostChanged.UpdatePost)?.let { updatePost -> + // if post update is only local do nothing + if (!updatePost.isLocalUpdate) { + // Post the result based on `event.isError` + _onPostUpdateResult.postValue(!event.isError) + // Hide updating post area + _onPostUpdateUiVisible.postValue(false) + } + } } sealed class UpdateResult { diff --git a/WordPress/src/main/res/layout/new_edit_post_activity.xml b/WordPress/src/main/res/layout/new_edit_post_activity.xml index b619e8b65803..d65437835efa 100644 --- a/WordPress/src/main/res/layout/new_edit_post_activity.xml +++ b/WordPress/src/main/res/layout/new_edit_post_activity.xml @@ -65,6 +65,44 @@ tools:context=".ui.photopicker.PhotoPickerFragment" tools:visibility="visible" /> + + + + + + + + + + + + diff --git a/WordPress/src/main/res/values/colors.xml b/WordPress/src/main/res/values/colors.xml index c75fad414336..8e803301f886 100644 --- a/WordPress/src/main/res/values/colors.xml +++ b/WordPress/src/main/res/values/colors.xml @@ -158,4 +158,8 @@ #F2F2F7 #2C2C2E + + + #EDD6C5 + diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 82adbf31dd1d..6bf4ac88c16d 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -1720,6 +1720,8 @@ Your draft is uploading Post converted back to draft Failed to insert media.\nPlease tap to retry. + Updating post content + Failed to update post content Post settings From 01e5ff994f101cdce0b06920464004513353e53d Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Tue, 5 Mar 2024 12:53:27 +0200 Subject: [PATCH 4/9] Adds: Sync publishing feature flag --- WordPress/build.gradle | 1 + .../util/config/SyncPublishingFeatureConfig.kt | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/util/config/SyncPublishingFeatureConfig.kt diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 6329c75f8e74..77528c64ece0 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -158,6 +158,7 @@ android { buildConfigField "boolean", "BLAZE_MANAGE_CAMPAIGNS", "false" buildConfigField "boolean", "DASHBOARD_PERSONALIZATION", "false" buildConfigField "boolean", "ENABLE_SITE_MONITORING", "false" + buildConfigField "boolean", "SYNC_PUBLISHING", "false" manifestPlaceholders = [magicLinkScheme:"wordpress"] } diff --git a/WordPress/src/main/java/org/wordpress/android/util/config/SyncPublishingFeatureConfig.kt b/WordPress/src/main/java/org/wordpress/android/util/config/SyncPublishingFeatureConfig.kt new file mode 100644 index 000000000000..e1a4580e3b20 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/util/config/SyncPublishingFeatureConfig.kt @@ -0,0 +1,16 @@ +package org.wordpress.android.util.config + +import org.wordpress.android.BuildConfig +import org.wordpress.android.annotation.Feature +import javax.inject.Inject + +private const val SYNC_PUBLISHING_FEATURE_REMOTE_FIELD = "sync_publishing" + +@Feature(SYNC_PUBLISHING_FEATURE_REMOTE_FIELD, false) +class SyncPublishingFeatureConfig @Inject constructor( + appConfig: AppConfig +) : FeatureConfig( + appConfig, + BuildConfig.SYNC_PUBLISHING, + SYNC_PUBLISHING_FEATURE_REMOTE_FIELD +) From 93529139df77f0e4fdc63a7ac0e3022f321a7864 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Tue, 5 Mar 2024 12:54:13 +0200 Subject: [PATCH 5/9] Use sync publishing FF in EditPostActivity --- .../org/wordpress/android/ui/posts/EditPostActivity.java | 6 +++++- 1 file changed, 5 insertions(+), 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 a36829037fa5..63feb69da7f7 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 @@ -222,6 +222,7 @@ import org.wordpress.android.util.analytics.AnalyticsUtils.BlockEditorEnabledSource; import org.wordpress.android.util.config.ContactSupportFeatureConfig; import org.wordpress.android.util.config.GlobalStyleSupportFeatureConfig; +import org.wordpress.android.util.config.SyncPublishingFeatureConfig; import org.wordpress.android.util.extensions.AppBarLayoutExtensionsKt; import org.wordpress.android.util.helpers.MediaFile; import org.wordpress.android.util.helpers.MediaGallery; @@ -426,6 +427,7 @@ enum RestartEditorOptions { @Inject BloggingPromptsStore mBloggingPromptsStore; @Inject JetpackFeatureRemovalPhaseHelper mJetpackFeatureRemovalPhaseHelper; @Inject ContactSupportFeatureConfig mContactSupportFeatureConfig; + @Inject SyncPublishingFeatureConfig mSyncPublishingFeatureConfig; private StorePostViewModel mViewModel; private StorageUtilsViewModel mStorageUtilsViewModel; @@ -806,7 +808,9 @@ public void handleOnBackPressed() { mUpdatingPostArea = findViewById(R.id.updating); // check if post content needs updating - mViewModel.checkIfUpdatedPostVersionExists(mEditPostRepository, mSite); + if (mSyncPublishingFeatureConfig.isEnabled()) { + mViewModel.checkIfUpdatedPostVersionExists(mEditPostRepository, mSite); + } } private void showUpdatingPostArea() { From 016e63cd83bc90b244fdfdbc4d44a9eb1afdbb75 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Tue, 5 Mar 2024 12:54:30 +0200 Subject: [PATCH 6/9] Update FluxC lib version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d1166836c069..a536cc19a0c8 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ ext { automatticTracksVersion = '3.4.0' gutenbergMobileVersion = 'v1.114.0' wordPressAztecVersion = 'v2.0' - wordPressFluxCVersion = '2957-64735ca1008922a05c7cd0501b01b511784f87f1' + wordPressFluxCVersion = '2957-9f88cce9e2e2b9d57389ba574bd549392b3eab65' wordPressLoginVersion = '1.14.1' wordPressPersistentEditTextVersion = '1.0.2' wordPressUtilsVersion = '3.13.0' From 0001bc5a209c34ead902fcbc12ee9234d310f80c Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Wed, 6 Mar 2024 15:55:09 +0200 Subject: [PATCH 7/9] Adds: minimum display time for updating post message --- .../android/ui/posts/EditPostActivity.java | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 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 63feb69da7f7..f3802a04d743 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 @@ -442,6 +442,11 @@ enum RestartEditorOptions { private ActivityResultLauncher mEditShareMessageActivityResultLauncher; + private final Handler mHideUpdatingPostAreaHandler = new Handler(Looper.getMainLooper()); + private Runnable mHideUpdatingPostAreaRunnable; + private long mUpdatingPostStartTime = 0L; + private static final long MIN_UPDATING_POST_DISPLAY_TIME = 2000L; // Minimum display time in milliseconds + public static boolean checkToRestart(@NonNull Intent data) { return data.hasExtra(EXTRA_RESTART_EDITOR) && RestartEditorOptions.valueOf(data.getStringExtra(EXTRA_RESTART_EDITOR)) @@ -812,13 +817,38 @@ public void handleOnBackPressed() { mViewModel.checkIfUpdatedPostVersionExists(mEditPostRepository, mSite); } } - private void showUpdatingPostArea() { mUpdatingPostArea.setVisibility(View.VISIBLE); + mUpdatingPostStartTime = System.currentTimeMillis(); + // Cancel any pending hide operations to avoid conflicts + if (mHideUpdatingPostAreaRunnable != null) { + mHideUpdatingPostAreaHandler.removeCallbacks(mHideUpdatingPostAreaRunnable); + } } private void hideUpdatingPostArea() { - mUpdatingPostArea.setVisibility(View.GONE); + long elapsedTime = System.currentTimeMillis() - mUpdatingPostStartTime; + long delay = MIN_UPDATING_POST_DISPLAY_TIME - elapsedTime; + + if (delay > 0) { + // Delay hiding the view if the elapsed time is less than the minimum display time + hideUpdatingPostAreaWithDelay(delay); + } else { + // Hide the view immediately if the minimum display time has been met or exceeded + mUpdatingPostArea.setVisibility(View.GONE); + } + } + + private void hideUpdatingPostAreaWithDelay(long delay) { + // Define the runnable only once or ensure it's the same instance if it's already defined + if (mHideUpdatingPostAreaRunnable == null) { + mHideUpdatingPostAreaRunnable = () -> { + if (mUpdatingPostArea != null) { + mUpdatingPostArea.setVisibility(View.GONE); + } + }; + } + mHideUpdatingPostAreaHandler.postDelayed(mHideUpdatingPostAreaRunnable, delay); } private void customizeToolbar() { @@ -1137,6 +1167,10 @@ protected void onPause() { if (mShowPrepublishingBottomSheetHandler != null && mShowPrepublishingBottomSheetRunnable != null) { mShowPrepublishingBottomSheetHandler.removeCallbacks(mShowPrepublishingBottomSheetRunnable); } + + if (mHideUpdatingPostAreaHandler != null && mHideUpdatingPostAreaRunnable != null) { + mHideUpdatingPostAreaHandler.removeCallbacks(mHideUpdatingPostAreaRunnable); + } } @Override From e52022d1a18a08e27fcee025feb69157f7f22323 Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Thu, 7 Mar 2024 16:39:46 +0200 Subject: [PATCH 8/9] Updates: wordPressFluxCVersion --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a536cc19a0c8..808ceb27a90c 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ ext { automatticTracksVersion = '3.4.0' gutenbergMobileVersion = 'v1.114.0' wordPressAztecVersion = 'v2.0' - wordPressFluxCVersion = '2957-9f88cce9e2e2b9d57389ba574bd549392b3eab65' + wordPressFluxCVersion = 'trunk-ae15f6b0b21c0ee9e0f97741ea2e16545358eac3' wordPressLoginVersion = '1.14.1' wordPressPersistentEditTextVersion = '1.0.2' wordPressUtilsVersion = '3.13.0' From 9abd2ca8ef263b37b5f2f14dc68d33649a4489dc Mon Sep 17 00:00:00 2001 From: Pantelis Stampoulis Date: Thu, 7 Mar 2024 16:48:17 +0200 Subject: [PATCH 9/9] Modifies: postFreshnessChecker place of injection --- .../main/java/org/wordpress/android/modules/PostModule.kt | 2 ++ .../org/wordpress/android/ui/posts/PostUtilsWrapper.kt | 6 +----- .../android/ui/posts/editor/StorePostViewModel.kt | 6 ++++-- .../wordpress/android/ui/posts/PostSettingsUtilsTest.kt | 4 +--- .../android/ui/posts/editor/StorePostViewModelTest.kt | 7 ++++++- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/modules/PostModule.kt b/WordPress/src/main/java/org/wordpress/android/modules/PostModule.kt index 1ad6deb78848..14d034b274b5 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/PostModule.kt +++ b/WordPress/src/main/java/org/wordpress/android/modules/PostModule.kt @@ -6,10 +6,12 @@ import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import org.wordpress.android.ui.posts.IPostFreshnessChecker import org.wordpress.android.ui.posts.PostFreshnessCheckerImpl +import javax.inject.Singleton @InstallIn(SingletonComponent::class) @Module class PostModule { + @Singleton @Provides fun providePostFreshnessChecker(): IPostFreshnessChecker = PostFreshnessCheckerImpl() } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/PostUtilsWrapper.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/PostUtilsWrapper.kt index bcc2226d08c2..9e62b2c8a917 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/PostUtilsWrapper.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/PostUtilsWrapper.kt @@ -18,8 +18,7 @@ import javax.inject.Inject @Reusable class PostUtilsWrapper @Inject constructor( - private val dateProvider: DateProvider, - private val postFreshnessChecker: IPostFreshnessChecker + private val dateProvider: DateProvider ) { fun isPublishable(post: PostImmutableModel) = PostUtils.isPublishable(post) @@ -55,7 +54,4 @@ class PostUtilsWrapper fun shouldPublishImmediatelyOptionBeAvailable(status: PostStatus?) = PostUtils.shouldPublishImmediatelyOptionBeAvailable(status) - - fun shouldRefreshPost(post: PostImmutableModel) : Boolean = - postFreshnessChecker.shouldRefreshPost(post) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/StorePostViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/StorePostViewModel.kt index 3b1fe994920c..684285199203 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/StorePostViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/StorePostViewModel.kt @@ -24,6 +24,7 @@ import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.ui.posts.EditPostRepository import org.wordpress.android.ui.posts.EditPostRepository.UpdatePostResult +import org.wordpress.android.ui.posts.IPostFreshnessChecker import org.wordpress.android.ui.posts.PostUtilsWrapper import org.wordpress.android.ui.posts.SavePostToDbUseCase import org.wordpress.android.ui.posts.editor.StorePostViewModel.ActivityFinishState.SAVED_LOCALLY @@ -49,7 +50,8 @@ class StorePostViewModel private val uploadService: UploadServiceFacade, private val savePostToDbUseCase: SavePostToDbUseCase, private val networkUtils: NetworkUtilsWrapper, - private val dispatcher: Dispatcher + private val dispatcher: Dispatcher, + private val postFreshnessChecker: IPostFreshnessChecker ) : ScopedViewModel(uiCoroutineDispatcher), DialogVisibilityProvider { private var debounceCounter = 0 private var saveJob: Job? = null @@ -206,7 +208,7 @@ class StorePostViewModel editPostRepository.getPost()?.let { postModel -> if (!postModel.isLocalDraft && !postModel.isLocallyChanged - && postUtils.shouldRefreshPost(postModel)) { + && postFreshnessChecker.shouldRefreshPost(postModel)) { _onPostUpdateUiVisible.postValue(true) val payload = RemotePostPayload(editPostRepository.getEditablePost(), site) dispatcher.dispatch(PostActionBuilder.newFetchPostAction(payload)) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/posts/PostSettingsUtilsTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/posts/PostSettingsUtilsTest.kt index 1dca48152310..3fb8fa7fe09c 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/posts/PostSettingsUtilsTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/posts/PostSettingsUtilsTest.kt @@ -27,8 +27,6 @@ class PostSettingsUtilsTest : BaseUnitTest() { @Mock lateinit var dateProvider: DateProvider - @Mock - lateinit var postFreshnessCheckerImpl: IPostFreshnessChecker private lateinit var postSettingsUtils: PostSettingsUtils private lateinit var postUtilsWrapper: PostUtilsWrapper @@ -39,7 +37,7 @@ class PostSettingsUtilsTest : BaseUnitTest() { @Before fun setUp() { - postUtilsWrapper = PostUtilsWrapper(dateProvider, postFreshnessCheckerImpl) + postUtilsWrapper = PostUtilsWrapper(dateProvider) postSettingsUtils = PostSettingsUtils(resourceProvider, mStatsDateUtils, postUtilsWrapper) whenever(mStatsDateUtils.formatDateTime(any())).thenReturn(formattedDate) whenever(dateProvider.getCurrentDate()).thenReturn(DateTimeUtils.dateUTCFromIso8601(currentDate)) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/StorePostViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/StorePostViewModelTest.kt index c4ca4d62a19b..2d5a52692ea0 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/StorePostViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/StorePostViewModelTest.kt @@ -23,6 +23,7 @@ import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.ui.posts.EditPostRepository import org.wordpress.android.ui.posts.EditPostRepository.UpdatePostResult +import org.wordpress.android.ui.posts.IPostFreshnessChecker import org.wordpress.android.ui.posts.PostUtilsWrapper import org.wordpress.android.ui.posts.SavePostToDbUseCase import org.wordpress.android.ui.posts.editor.StorePostViewModel.ActivityFinishState.SAVED_LOCALLY @@ -59,6 +60,9 @@ class StorePostViewModelTest : BaseUnitTest() { @Mock lateinit var context: Context + @Mock + lateinit var postFreshnessChecker: IPostFreshnessChecker + private lateinit var viewModel: StorePostViewModel private val title = "title" private val updatedTitle = "updatedTitle" @@ -79,7 +83,8 @@ class StorePostViewModelTest : BaseUnitTest() { uploadService, savePostToDbUseCase, networkUtils, - dispatcher + dispatcher, + postFreshnessChecker ) postModel.setId(postId) postModel.setTitle(title)