Skip to content

Revert "Implement GutenbergKit ViewModel Architecture (#22087)" #22127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@
import org.wordpress.android.ui.posts.EditPostActivity;
import org.wordpress.android.ui.posts.EditPostPublishSettingsFragment;
import org.wordpress.android.ui.posts.EditPostSettingsFragment;
import org.wordpress.android.ui.posts.editor.GutenbergKitEditorFragment;
import org.wordpress.android.ui.posts.HistoryListFragment;
import org.wordpress.android.ui.posts.PostDatePickerDialogFragment;
import org.wordpress.android.ui.posts.PostListFragment;
Expand Down Expand Up @@ -273,8 +272,6 @@ public interface AppComponent {

void inject(EditPostSettingsFragment object);

void inject(GutenbergKitEditorFragment object);

void inject(PostSettingsListDialogFragment object);

void inject(PostsListActivity object);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import org.wordpress.android.ui.posts.EditPostPublishSettingsViewModel;
import org.wordpress.android.ui.posts.EditorBloggingPromptsViewModel;
import org.wordpress.android.ui.posts.EditorJetpackSocialViewModel;
import org.wordpress.android.ui.posts.GutenbergKitViewModel;
import org.wordpress.android.ui.posts.navigation.EditPostNavigationViewModel;
import org.wordpress.android.ui.posts.EditPostSettingsViewModel;
import org.wordpress.android.ui.posts.PostListMainViewModel;
Expand Down Expand Up @@ -308,11 +307,6 @@ abstract class ViewModelModule {
@ViewModelKey(EditPostSettingsViewModel.class)
abstract ViewModel editPostSettingsViewModel(EditPostSettingsViewModel viewModel);

@Binds
@IntoMap
@ViewModelKey(GutenbergKitViewModel.class)
abstract ViewModel gutenbergKitViewModel(GutenbergKitViewModel viewModel);

@Binds
@IntoMap
@ViewModelKey(ReaderCommentListViewModel.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,6 @@ class EditPostActivity : BaseAppCompatActivity(), EditorFragmentActivity, Editor
private lateinit var editPostSettingsViewModel: EditPostSettingsViewModel
private lateinit var prepublishingViewModel: PrepublishingViewModel
private lateinit var editPostAuthViewModel: EditPostAuthViewModel
private lateinit var gutenbergKitViewModel: GutenbergKitViewModel

private lateinit var siteModel: SiteModel

Expand Down Expand Up @@ -646,7 +645,6 @@ class EditPostActivity : BaseAppCompatActivity(), EditorFragmentActivity, Editor
editPostSettingsViewModel = ViewModelProvider(this, viewModelFactory)[EditPostSettingsViewModel::class.java]
prepublishingViewModel = ViewModelProvider(this, viewModelFactory)[PrepublishingViewModel::class.java]
editPostAuthViewModel = ViewModelProvider(this, viewModelFactory)[EditPostAuthViewModel::class.java]
gutenbergKitViewModel = ViewModelProvider(this, viewModelFactory)[GutenbergKitViewModel::class.java]
}

private fun initializeSiteModel(savedInstanceState: Bundle?): Boolean {
Expand Down Expand Up @@ -2608,17 +2606,13 @@ class EditPostActivity : BaseAppCompatActivity(), EditorFragmentActivity, Editor
val gutenbergWebViewAuthorizationData = createGutenbergWebViewAuthorizationData(isWpCom)
val settings = createGutenbergKitSettings(isWpCom)

val fragment = GutenbergKitEditorFragment.newInstance(
return GutenbergKitEditorFragment.newInstance(
getContext(),
isNewPost,
gutenbergWebViewAuthorizationData,
jetpackFeatureRemovalPhaseHelper.shouldShowJetpackPoweredEditorFeatures(),
settings
)

// Set settings in ViewModel for fragment to observe
gutenbergKitViewModel.updateEditorSettings(settings)

return fragment
}

private fun createGutenbergWebViewAuthorizationData(isWpCom: Boolean): GutenbergWebViewAuthorizationData {
Expand All @@ -2638,35 +2632,36 @@ class EditPostActivity : BaseAppCompatActivity(), EditorFragmentActivity, Editor
)
}

private fun createGutenbergKitSettings(isWpCom: Boolean): GutenbergKitSettings {
private fun createGutenbergKitSettings(isWpCom: Boolean): MutableMap<String, Any?> {
val postType = if (editPostRepository.isPage) "page" else "post"
val siteURL = siteModel.url
val siteApiRoot = if (isWpCom) "https://public-api.wordpress.com/"
else siteModel.wpApiRestUrl ?: "$siteURL/wp-json/"
// Use the application password for self-hosted sites when available
val authHeader = if (isWpCom) "Bearer ${accountStore.accessToken}" else "Basic "
val siteApiNamespace = if (isWpCom)
listOf("sites/${site.siteId}/", "sites/${UrlUtils.removeScheme(siteURL)}/")
else emptyList()
arrayOf("sites/${site.siteId}/", "sites/${UrlUtils.removeScheme(siteURL)}/")
else arrayOf()

val languageString = perAppLocaleManager.getCurrentLocaleLanguageCode()
val wpcomLocaleSlug = languageString.replace("_", "-").lowercase()

return GutenbergKitSettings(
postId = editPostRepository.getPost()?.remotePostId?.toInt(),
postType = postType,
postTitle = editPostRepository.getPost()?.title,
postContent = editPostRepository.getPost()?.content,
siteURL = siteURL,
siteApiRoot = siteApiRoot,
namespaceExcludedPaths = listOf("/wpcom/v2/following/recommendations", "/wpcom/v2/following/mine"),
authHeader = authHeader,
siteApiNamespace = siteApiNamespace,
themeStyles = experimentalFeatures.isEnabled(Feature.EXPERIMENTAL_BLOCK_EDITOR_THEME_STYLES),
plugins = gutenbergKitPluginsFeature.isEnabled() && site.isWPCom,
locale = wpcomLocaleSlug,
cookies = editPostAuthViewModel.getCookiesForPrivateSites(site, privateAtomicCookie),
webViewGlobals = listOf(
return mutableMapOf(
"postId" to editPostRepository.getPost()?.remotePostId?.toInt(),
"postType" to postType,
"postTitle" to editPostRepository.getPost()?.title,
"postContent" to editPostRepository.getPost()?.content,
"siteURL" to siteURL,
"siteApiRoot" to siteApiRoot,
"namespaceExcludedPaths" to arrayOf("/wpcom/v2/following/recommendations", "/wpcom/v2/following/mine"),
"authHeader" to authHeader,
"siteApiNamespace" to siteApiNamespace,
"themeStyles" to experimentalFeatures.isEnabled(Feature.EXPERIMENTAL_BLOCK_EDITOR_THEME_STYLES),
// Limited to Simple sites until application passwords are supported
"plugins" to (gutenbergKitPluginsFeature.isEnabled() && site.isWPCom),
"locale" to wpcomLocaleSlug,
"cookies" to editPostAuthViewModel.getCookiesForPrivateSites(site, privateAtomicCookie),
"webViewGlobals" to listOf(
WebViewGlobal(
"_currentSiteType",
when {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,13 @@ import org.wordpress.gutenberg.GutenbergView.TitleAndContentCallback
import org.wordpress.gutenberg.GutenbergWebViewPool.getPreloadedWebView
import org.wordpress.gutenberg.GutenbergWebViewPool.recycleWebView
import org.wordpress.gutenberg.Media
import org.wordpress.gutenberg.WebViewGlobal
import java.io.Serializable
import java.util.concurrent.CountDownLatch
import androidx.lifecycle.ViewModelProvider
import org.wordpress.android.ui.posts.GutenbergKitSettings
import org.wordpress.android.ui.posts.GutenbergKitViewModel
import org.wordpress.android.WordPress
import javax.inject.Inject

class GutenbergKitEditorFragment : EditorFragmentAbstract(), EditorMediaUploadListener, IHistoryListener,
EditorThemeUpdateListener, GutenbergDialogPositiveClickInterface, GutenbergDialogNegativeClickInterface,
GutenbergNetworkConnectionListener {
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
private lateinit var gutenbergKitViewModel: GutenbergKitViewModel

private var gutenbergView: GutenbergView? = null
private var isHtmlModeEnabled = false

Expand All @@ -76,29 +70,12 @@ class GutenbergKitEditorFragment : EditorFragmentAbstract(), EditorMediaUploadLi
private var isEditorDidMount = false
private var rootView: View? = null

// Access settings through ViewModel
private val settings: GutenbergKitSettings?
get() = if (::gutenbergKitViewModel.isInitialized) {
gutenbergKitViewModel.editorSettings.value
} else {
null
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

ProfilingUtils.start("Visual Editor Startup")
ProfilingUtils.split("EditorFragment.onCreate")

// Trigger dependency injection
(requireActivity().applicationContext as WordPress).component().inject(this)

// Initialize shared ViewModel (same scope as Activity) - after DI is complete
gutenbergKitViewModel = ViewModelProvider(
requireActivity(),
viewModelFactory
)[GutenbergKitViewModel::class.java]

if (savedInstanceState != null) {
isHtmlModeEnabled = savedInstanceState.getBoolean(KEY_HTML_MODE_ENABLED)
isEditorStarted = savedInstanceState.getBoolean(KEY_EDITOR_STARTED)
Expand All @@ -110,6 +87,11 @@ class GutenbergKitEditorFragment : EditorFragmentAbstract(), EditorMediaUploadLi
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
if (arguments != null) {
@Suppress("UNCHECKED_CAST", "DEPRECATION")
settings = requireArguments().getSerializable(ARG_GUTENBERG_KIT_SETTINGS) as Map<String, Any?>?
}

// request dependency injection. Do this after setting min/max dimensions
if (activity is EditorFragmentActivity) {
(activity as EditorFragmentActivity).initializeEditorFragment()
Expand Down Expand Up @@ -235,6 +217,17 @@ class GutenbergKitEditorFragment : EditorFragmentAbstract(), EditorMediaUploadLi
}
}

// Type-safe settings accessors
private inline fun <reified T> Map<String, Any?>.getSetting(key: String): T? = this[key] as? T
private inline fun <reified T> Map<String, Any?>.getSettingOrDefault(key: String, default: T): T =
getSetting(key) ?: default

private fun Map<String, Any?>.getStringArray(key: String): Array<String> =
getSetting<Array<String?>>(key)?.asSequence()?.filterNotNull()?.toList()?.toTypedArray() ?: emptyArray()

private fun Map<String, Any?>.getWebViewGlobals(key: String): List<WebViewGlobal> =
getSetting<List<WebViewGlobal>>(key) ?: emptyList()

// View extension functions
private fun View?.setVisibleOrGone(visible: Boolean) {
this?.visibility = if (visible) View.VISIBLE else View.GONE
Expand Down Expand Up @@ -524,31 +517,39 @@ class GutenbergKitEditorFragment : EditorFragmentAbstract(), EditorMediaUploadLi
}

private fun buildEditorConfiguration(editorSettings: String): EditorConfiguration {
val kitSettings = settings!!

val postId = kitSettings.postId?.let { if (it == 0) -1 else it }
val firstNamespace = kitSettings.siteApiNamespace.firstOrNull() ?: ""
val editorAssetsEndpoint = "${kitSettings.siteApiRoot}wpcom/v2/${firstNamespace}editor-assets"

return EditorConfiguration.Builder()
.setTitle(kitSettings.postTitle ?: "")
.setContent(kitSettings.postContent ?: "")
.setPostId(postId)
.setPostType(kitSettings.postType)
.setThemeStyles(kitSettings.themeStyles)
.setPlugins(kitSettings.plugins)
.setSiteApiRoot(kitSettings.siteApiRoot)
.setSiteApiNamespace(kitSettings.siteApiNamespace.toTypedArray())
.setNamespaceExcludedPaths(kitSettings.namespaceExcludedPaths.toTypedArray())
.setAuthHeader(kitSettings.authHeader)
.setWebViewGlobals(kitSettings.webViewGlobals)
.setEditorSettings(editorSettings)
.setLocale(kitSettings.locale)
.setEditorAssetsEndpoint(editorAssetsEndpoint)
.setCachedAssetHosts(setOf("s0.wp.com", UrlUtils.getHost(kitSettings.siteURL)))
.setEnableAssetCaching(true)
.setCookies(kitSettings.cookies)
.build()
val settingsMap = settings!!

return settingsMap.run {
val postId = getSetting<Int>("postId").let { if (it == 0) -1 else it }
val siteURL = getSetting<String>("siteURL")
val siteApiRoot = getSetting<String>("siteApiRoot")
val siteApiNamespace = getStringArray("siteApiNamespace")
val firstNamespace = siteApiNamespace.firstOrNull() ?: ""
val editorAssetsEndpoint = "${siteApiRoot}wpcom/v2/${firstNamespace}editor-assets"
val cookies = getSetting<Map<String, String>>("cookies") ?: emptyMap()
val namespaceExcludedPaths = getStringArray("namespaceExcludedPaths")
val webViewGlobals = getWebViewGlobals("webViewGlobals")

EditorConfiguration.Builder()
.setTitle(getSetting<String>("postTitle") ?: "")
.setContent(getSetting<String>("postContent") ?: "")
.setPostId(postId)
.setPostType(getSetting<String>("postType"))
.setThemeStyles(getSettingOrDefault("themeStyles", false))
.setPlugins(getSettingOrDefault("plugins", false))
.setSiteApiRoot(getSetting<String>("siteApiRoot") ?: "")
.setSiteApiNamespace(siteApiNamespace)
.setNamespaceExcludedPaths(namespaceExcludedPaths)
.setAuthHeader(getSetting<String>("authHeader") ?: "")
.setWebViewGlobals(webViewGlobals)
.setEditorSettings(editorSettings)
.setLocale(getSetting<String>("locale"))
.setEditorAssetsEndpoint(editorAssetsEndpoint)
.setCachedAssetHosts(setOf("s0.wp.com", UrlUtils.getHost(siteURL)))
.setEnableAssetCaching(true)
.setCookies(cookies)
.build()
}
}

override fun showNotice(message: String?) {
Expand Down Expand Up @@ -588,22 +589,28 @@ class GutenbergKitEditorFragment : EditorFragmentAbstract(), EditorMediaUploadLi
private const val ARG_GUTENBERG_WEB_VIEW_AUTH_DATA = "param_gutenberg_web_view_auth_data"
const val ARG_FEATURED_IMAGE_ID: String = "featured_image_id"
const val ARG_JETPACK_FEATURES_ENABLED: String = "jetpack_features_enabled"
const val ARG_GUTENBERG_KIT_SETTINGS: String = "gutenberg_kit_settings"

private const val CAPTURE_PHOTO_PERMISSION_REQUEST_CODE = 101
private const val CAPTURE_VIDEO_PERMISSION_REQUEST_CODE = 102

private var settings: Map<String, Any?>? = null

fun newInstance(
context: Context,
isNewPost: Boolean,
webViewAuthorizationData: GutenbergWebViewAuthorizationData?,
jetpackFeaturesEnabled: Boolean,
settings: Map<String, Any?>?
): GutenbergKitEditorFragment {
val fragment = GutenbergKitEditorFragment()
val args = Bundle()
args.putBoolean(ARG_IS_NEW_POST, isNewPost)
args.putBoolean(ARG_JETPACK_FEATURES_ENABLED, jetpackFeaturesEnabled)
args.putSerializable(ARG_GUTENBERG_KIT_SETTINGS, settings as Serializable?)
fragment.setArguments(args)
val db = getDatabase(context)
GutenbergKitEditorFragment.settings = settings
db?.addParcel(ARG_GUTENBERG_WEB_VIEW_AUTH_DATA, webViewAuthorizationData)
return fragment
}
Expand Down

This file was deleted.