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 8f95c2c44ab5..389e388e31d8 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 @@ -1,6 +1,7 @@ @file:Suppress("DEPRECATION") package org.wordpress.android.ui.posts +import android.annotation.SuppressLint import android.app.ProgressDialog import android.content.Intent import android.content.res.Configuration @@ -230,6 +231,7 @@ import java.util.regex.Matcher import java.util.regex.Pattern import javax.inject.Inject import kotlin.math.max +import androidx.core.view.isNotEmpty // ViewPager configuration constants private const val VIEW_PAGER_PAGE_CONTENT = 0 @@ -239,6 +241,7 @@ private const val VIEW_PAGER_PAGE_HISTORY = 3 private const val VIEW_PAGER_OFFSCREEN_PAGE_LIMIT = 4 private const val MEDIA_ID_NO_FEATURED_IMAGE_SET = 0 +private const val DISABLED_ALPHA = 0.5f @Suppress("LargeClass") class GutenbergKitActivity : BaseAppCompatActivity(), EditorImageSettingsListener, @@ -285,6 +288,9 @@ class GutenbergKitActivity : BaseAppCompatActivity(), EditorImageSettingsListene private var toolbar: Toolbar? = null private var menuHasUndo: Boolean = false private var menuHasRedo: Boolean = false + private var isModalDialogOpen: Boolean = false + private var backPressedCallback: OnBackPressedCallback? = null + private var closeButton: View? = null private var showPrepublishingBottomSheetHandler: Handler? = null private var showPrepublishingBottomSheetRunnable: Runnable? = null private var htmlModeMenuStateOn: Boolean = false @@ -484,12 +490,16 @@ class GutenbergKitActivity : BaseAppCompatActivity(), EditorImageSettingsListene } setContentView(R.layout.new_edit_post_activity) - val callback: OnBackPressedCallback = object : OnBackPressedCallback(true) { + backPressedCallback = object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { - handleBackPressed() + if (isModalDialogOpen) { + editorFragment?.dismissTopModal() + } else { + handleBackPressed() + } } } - onBackPressedDispatcher.addCallback(this, callback) + onBackPressedDispatcher.addCallback(this, backPressedCallback!!) dispatcher.register(this) createEditShareMessageActivityResultLauncher() @@ -833,8 +843,8 @@ class GutenbergKitActivity : BaseAppCompatActivity(), EditorImageSettingsListene it.overflowIcon = overflowIcon // Custom close button - val closeHeader: View = it.findViewById(R.id.edit_post_header) - closeHeader.setOnClickListener { handleBackPressed() } + closeButton = it.findViewById(R.id.edit_post_header) + closeButton?.setOnClickListener { handleBackPressed() } // Update site icon if mSite is available, if not it will use the placeholder. val siteIconUrl = SiteUtils.getSiteIconUrl( siteModel, @@ -852,6 +862,40 @@ class GutenbergKitActivity : BaseAppCompatActivity(), EditorImageSettingsListene } } + private fun setOverflowMenuEnabled(enabled: Boolean) { + val currentToolbar = toolbar ?: return + val overflowButton = findOverflowButton(currentToolbar) + overflowButton?.let { + it.isEnabled = enabled + it.alpha = if (enabled) 1.0f else DISABLED_ALPHA + } + } + + private fun findOverflowButton(toolbar: Toolbar): View? { + // Try multiple ways to find the overflow menu button + @SuppressLint("DiscouragedApi") + return toolbar.findViewById( + resources.getIdentifier("action_overflow_menu_button", "id", "android") + ) ?: toolbar.findViewById( + resources.getIdentifier("overflow_button", "id", packageName) + ) ?: findOverflowButtonInChildren(toolbar) + } + + private fun findOverflowButtonInChildren(toolbar: Toolbar): View? { + // Find it by iterating through toolbar children + for (i in 0 until toolbar.childCount) { + val child = toolbar.getChildAt(i) + if (child.javaClass.simpleName == "ActionMenuView") { + val actionMenuView = child as? android.view.ViewGroup + // The overflow button is typically the last child of ActionMenuView + if (actionMenuView != null && actionMenuView.isNotEmpty()) { + return actionMenuView.getChildAt(actionMenuView.childCount - 1) + } + } + } + return null + } + private fun fetchSiteSettings() { siteSettings?.init(true) } @@ -1425,11 +1469,11 @@ class GutenbergKitActivity : BaseAppCompatActivity(), EditorImageSettingsListene val sendFeedbackItem = menu.findItem(R.id.menu_editor_send_feedback) if (undoItem != null) { - undoItem.setEnabled(menuHasUndo) + undoItem.setEnabled(menuHasUndo && !isModalDialogOpen) undoItem.setVisible(!htmlModeMenuStateOn) } if (redoItem != null) { - redoItem.setEnabled(menuHasRedo) + redoItem.setEnabled(menuHasRedo && !isModalDialogOpen) redoItem.setVisible(!htmlModeMenuStateOn) } if (secondaryAction != null && editPostRepository.hasPost()) { @@ -1460,6 +1504,7 @@ class GutenbergKitActivity : BaseAppCompatActivity(), EditorImageSettingsListene currentDestination != EditPostDestination.History && currentDestination != EditPostDestination.PublishSettings ) + primaryAction.setEnabled(!isModalDialogOpen) } } // Note: This menu is shared with EditPostActivity. The following items are not needed @@ -2941,6 +2986,26 @@ class GutenbergKitActivity : BaseAppCompatActivity(), EditorImageSettingsListene Handler(Looper.getMainLooper()).post { invalidateOptionsMenu() } } + override fun onModalDialogOpened(dialogType: String) { + isModalDialogOpen = true + closeButton?.let { + it.isEnabled = false + it.alpha = DISABLED_ALPHA + } + setOverflowMenuEnabled(false) + Handler(Looper.getMainLooper()).post { invalidateOptionsMenu() } + } + + override fun onModalDialogClosed(dialogType: String) { + isModalDialogOpen = false + closeButton?.let { + it.isEnabled = true + it.alpha = 1.0f + } + setOverflowMenuEnabled(true) + Handler(Looper.getMainLooper()).post { invalidateOptionsMenu() } + } + // 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 80f19f2eaa84..48dd2d57273f 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 @@ -52,6 +52,7 @@ class GutenbergKitEditorFragment : GutenbergKitEditorFragmentBase() { private var featuredImageChangeListener: FeaturedImageChangeListener? = null private var openMediaLibraryListener: OpenMediaLibraryListener? = null private var onLogJsExceptionListener: LogJsExceptionListener? = null + private var modalDialogStateListener: GutenbergView.ModalDialogStateListener? = null private var editorStarted = false private var isEditorDidMount = false @@ -126,6 +127,17 @@ class GutenbergKitEditorFragment : GutenbergKitEditorFragmentBase() { mEditorFragmentListener.onLogJsException(jsException, callback) } } + + // Set up modal dialog state listener + modalDialogStateListener = object : GutenbergView.ModalDialogStateListener { + override fun onModalDialogOpened(dialogType: String) { + mEditorFragmentListener.onModalDialogOpened(dialogType) + } + + override fun onModalDialogClosed(dialogType: String) { + mEditorFragmentListener.onModalDialogClosed(dialogType) + } + } } override fun onCreateView( @@ -163,6 +175,7 @@ class GutenbergKitEditorFragment : GutenbergKitEditorFragmentBase() { featuredImageChangeListener?.let(gutenbergView::setFeaturedImageChangeListener) openMediaLibraryListener?.let(gutenbergView::setOpenMediaLibraryListener) onLogJsExceptionListener?.let(gutenbergView::setLogJsExceptionListener) + modalDialogStateListener?.let(gutenbergView::setModalDialogStateListener) // Set up autocomplete listener for user mentions and cross-post suggestions gutenbergView.setAutocompleterTriggeredListener(object : GutenbergView.AutocompleterTriggeredListener { @@ -472,6 +485,10 @@ class GutenbergKitEditorFragment : GutenbergKitEditorFragmentBase() { gutenbergView?.redo() } + fun dismissTopModal() { + gutenbergView?.dismissTopModal() + } + companion object { private const val GUTENBERG_EDITOR_NAME = "gutenberg" private const val KEY_HTML_MODE_ENABLED = "KEY_HTML_MODE_ENABLED" 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 1b85f997ab08..1aa193d65885 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 @@ -149,5 +149,7 @@ public interface EditorFragmentListener extends DialogVisibilityProvider { void onLogJsException(JsException jsException, JsExceptionCallback onSendJsException); void onFeaturedImageIdChanged(long mediaID, boolean isGutenbergEditor); void onOpenMediaLibraryRequested(org.wordpress.gutenberg.GutenbergView.OpenMediaLibraryConfig config); + void onModalDialogOpened(String dialogType); + void onModalDialogClosed(String dialogType); } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 73b6fb38daf5..7f075f94c6ec 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -73,7 +73,7 @@ google-play-services-auth = '20.4.1' google-services = '4.4.3' gravatar = '2.5.0' greenrobot-eventbus = '3.3.1' -gutenberg-kit = 'v0.8.1' +gutenberg-kit = 'v0.9.0' gutenberg-mobile = 'v1.121.0' indexos-media-for-mobile = '43a9026f0973a2f0a74fa813132f6a16f7499c3a' jackson-databind = '2.12.7.1'