From 3f4aeed8719bc42bdfe30cd0b1122ff3ac3c9c66 Mon Sep 17 00:00:00 2001 From: David Calhoun Date: Fri, 16 Jan 2026 17:01:42 -0500 Subject: [PATCH 1/3] feat: Send GutenbergKit the latest content when requested Allow GutenbergKit to retrieve the latest content persisted in the host app as needed. This is important for allowing GutenbergKit to display the latest content after the WebView reloads or re-initializes from memory pressure or backgrounding. --- .../android/ui/posts/GutenbergKitActivity.kt | 4 ++++ .../ui/posts/editor/GutenbergKitEditorFragment.kt | 13 +++++++++++++ .../editor/GutenbergKitEditorFragmentBase.java | 12 ++++++++++++ 3 files changed, 29 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/GutenbergKitActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/GutenbergKitActivity.kt index 313886a505db..6c6ee25e5a86 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/GutenbergKitActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/GutenbergKitActivity.kt @@ -2950,6 +2950,10 @@ class GutenbergKitActivity : BaseAppCompatActivity(), EditorImageSettingsListene Handler(Looper.getMainLooper()).post { invalidateOptionsMenu() } } + override fun getPersistedTitle(): String = editPostRepository.title + + override fun getPersistedContent(): String = editPostRepository.content + // FluxC events @Suppress("unused", "CyclomaticComplexMethod") @Subscribe(threadMode = ThreadMode.MAIN) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/GutenbergKitEditorFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/GutenbergKitEditorFragment.kt index d980673bb13f..8a7ecb59ac84 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/GutenbergKitEditorFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/GutenbergKitEditorFragment.kt @@ -201,6 +201,19 @@ class GutenbergKitEditorFragment : GutenbergKitEditorFragmentBase() { gutenbergView::setNetworkRequestListener ) + // Set up content provider for WebView refresh recovery + gutenbergView.setLatestContentProvider( + object : GutenbergView.LatestContentProvider { + override fun getLatestContent(): GutenbergView.LatestContent { + return GutenbergView.LatestContent( + mEditorFragmentListener.persistedTitle, + mEditorFragmentListener.persistedContent + ) + } + } + ) + + // Set up autocomplete listener for user mentions and cross-post suggestions gutenbergView.setAutocompleterTriggeredListener( object : GutenbergView.AutocompleterTriggeredListener { override fun onAutocompleterTriggered(type: String) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/GutenbergKitEditorFragmentBase.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/GutenbergKitEditorFragmentBase.java index 1aa193d65885..2f7520dbb76b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/GutenbergKitEditorFragmentBase.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/GutenbergKitEditorFragmentBase.java @@ -151,5 +151,17 @@ public interface EditorFragmentListener extends DialogVisibilityProvider { void onOpenMediaLibraryRequested(org.wordpress.gutenberg.GutenbergView.OpenMediaLibraryConfig config); void onModalDialogOpened(String dialogType); void onModalDialogClosed(String dialogType); + + /** + * Returns the persisted post title for content recovery after WebView refresh. + * @return The most recently persisted title from autosave. + */ + String getPersistedTitle(); + + /** + * Returns the persisted post content for content recovery after WebView refresh. + * @return The most recently persisted content from autosave. + */ + String getPersistedContent(); } } From 8e919cc97b721cdf14828f94a11744f3641294b3 Mon Sep 17 00:00:00 2001 From: David Calhoun Date: Wed, 21 Jan 2026 11:33:26 -0500 Subject: [PATCH 2/3] feat: Set GutenbergKit post status --- .../ui/posts/EditorConfigurationBuilder.kt | 1 + .../ui/posts/GutenbergKitSettingsBuilder.kt | 7 ++-- .../posts/GutenbergKitSettingsBuilderTest.kt | 36 ++++++++++++++++--- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditorConfigurationBuilder.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditorConfigurationBuilder.kt index 5f0f414ae5b9..089ce48c41e5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditorConfigurationBuilder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditorConfigurationBuilder.kt @@ -27,6 +27,7 @@ object EditorConfigurationBuilder { setTitle(settings.getSetting("postTitle") ?: "") setContent(settings.getSetting("postContent") ?: "") setPostId(postId) + setPostStatus(settings.getSetting("status") ?: "draft") setSiteApiNamespace(siteApiNamespace) setNamespaceExcludedPaths( diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/GutenbergKitSettingsBuilder.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/GutenbergKitSettingsBuilder.kt index 8e43e1eb2891..c268fff930e7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/GutenbergKitSettingsBuilder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/GutenbergKitSettingsBuilder.kt @@ -54,7 +54,8 @@ object GutenbergKitSettingsBuilder { val remotePostId: Long?, val isPage: Boolean, val title: String?, - val content: String? + val content: String?, + val status: String? ) { companion object { fun fromPostModel(postModel: PostImmutableModel?): PostConfig { @@ -62,7 +63,8 @@ object GutenbergKitSettingsBuilder { remotePostId = postModel?.remotePostId, isPage = postModel?.isPage ?: false, title = postModel?.title, - content = postModel?.content + content = postModel?.content, + status = postModel?.status ) } } @@ -127,6 +129,7 @@ object GutenbergKitSettingsBuilder { return mutableMapOf( "postId" to postConfig.remotePostId?.toInt(), "postType" to if (postConfig.isPage) "page" else "post", + "status" to postConfig.status, "postTitle" to postConfig.title, "postContent" to postConfig.content, "siteURL" to siteConfig.url, diff --git a/WordPress/src/test/java/org/wordpress/android/ui/posts/GutenbergKitSettingsBuilderTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/posts/GutenbergKitSettingsBuilderTest.kt index 3f63e25fcfa3..05217a8e858e 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/posts/GutenbergKitSettingsBuilderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/posts/GutenbergKitSettingsBuilderTest.kt @@ -409,7 +409,8 @@ class GutenbergKitSettingsBuilderTest { remotePostId = 456L, isPage = false, title = "Test Post", - content = "Test Content" + content = "Test Content", + status = "publish" ) val settings = GutenbergKitSettingsBuilder.buildSettings( @@ -461,7 +462,8 @@ class GutenbergKitSettingsBuilderTest { remotePostId = 100L, isPage = true, title = "Test Page", - content = "Page Content" + content = "Page Content", + status = "draft" ) val settings = GutenbergKitSettingsBuilder.buildSettings( @@ -579,7 +581,8 @@ class GutenbergKitSettingsBuilderTest { remotePostId = null, isPage = false, title = null, - content = null + content = null, + status = null ) val settings = GutenbergKitSettingsBuilder.buildSettings( @@ -594,9 +597,30 @@ class GutenbergKitSettingsBuilderTest { assertThat(settings["postId"]).isNull() assertThat(settings["postTitle"]).isNull() assertThat(settings["postContent"]).isNull() + assertThat(settings["status"]).isNull() assertThat(settings["postType"]).isEqualTo("post") // Still defaults to post } + @Test + fun `post status is included in settings`() { + val testCases = listOf("draft", "publish", "pending", "private", "future", "trash") + + testCases.forEach { status -> + val postConfig = createPostConfig(status = status) + + val settings = GutenbergKitSettingsBuilder.buildSettings( + siteConfig = createSiteConfig(), + postConfig = postConfig, + appConfig = createAppConfig(), + featureConfig = createFeatureConfig() + ) + + assertThat(settings["status"]) + .withFailMessage("Expected status=$status in settings") + .isEqualTo(status) + } + } + // ===== Helper Methods ===== private fun createFeatureConfig( @@ -651,11 +675,13 @@ class GutenbergKitSettingsBuilderTest { remotePostId: Long? = 1L, isPage: Boolean = false, title: String? = "Test", - content: String? = "Content" + content: String? = "Content", + status: String? = "draft" ) = GutenbergKitSettingsBuilder.PostConfig( remotePostId = remotePostId, isPage = isPage, title = title, - content = content + content = content, + status = status ) } From 700d23b4928c295b1fa6e76f1ebe499db384de98 Mon Sep 17 00:00:00 2001 From: David Calhoun Date: Wed, 8 Apr 2026 10:20:07 -0400 Subject: [PATCH 3/3] build: Update GutenbergKit version Integrate an unrelated content loss fix that is necessary for testing this branch's focus on content preservation. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 611ffde1a9b5..340347669fec 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -73,7 +73,7 @@ google-play-review = '2.0.2' google-services = '4.4.4' gravatar = '2.5.0' greenrobot-eventbus = '3.3.1' -gutenberg-kit = 'v0.15.0' +gutenberg-kit = '432-944fbfce704642cfe725dc69c03b3cf6d5018854' gutenberg-mobile = 'v1.121.0' indexos-media-for-mobile = '43a9026f0973a2f0a74fa813132f6a16f7499c3a' jackson-databind = '2.12.7.1'