diff --git a/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerActivity.java index bdccb881bb0c..c2d20a8a8446 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerActivity.java @@ -276,7 +276,7 @@ private void doMediaUrisSelected(@NonNull List mediaUris, @NonNul final String mimeType = getContentResolver().getType(mediaUri); mFeaturedImageHelper.trackFeaturedImageEvent( - FeaturedImageHelper.TrackableEvent.IMAGE_PICKED, + FeaturedImageHelper.TrackableEvent.IMAGE_PICKED_POST_SETTINGS, mLocalPostId ); @@ -330,7 +330,7 @@ private void doMediaIdsSelected(ArrayList mediaIds, @NonNull PhotoPickerMe // if user chose a featured image, track image picked event if (mBrowserType == MediaBrowserType.FEATURED_IMAGE_PICKER) { mFeaturedImageHelper.trackFeaturedImageEvent( - FeaturedImageHelper.TrackableEvent.IMAGE_PICKED, + FeaturedImageHelper.TrackableEvent.IMAGE_PICKED_POST_SETTINGS, mLocalPostId ); } 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 80853a1a1b35..18d93ebfaa3a 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 @@ -239,6 +239,7 @@ import static org.wordpress.android.analytics.AnalyticsTracker.Stat.APP_REVIEWS_EVENT_INCREMENTED_BY_PUBLISHING_POST_OR_PAGE; import static org.wordpress.android.imageeditor.preview.PreviewImageFragment.PREVIEW_IMAGE_REDUCED_SIZE_FACTOR; import static org.wordpress.android.ui.history.HistoryDetailContainerFragment.KEY_REVISION; +import static org.wordpress.android.editor.gutenberg.GutenbergEditorFragment.MEDIA_ID_NO_FEATURED_IMAGE_SET; import kotlin.Unit; import kotlin.jvm.functions.Function0; @@ -403,6 +404,7 @@ enum RestartEditorOptions { @Inject StoriesPrefs mStoriesPrefs; @Inject StoriesEventListener mStoriesEventListener; @Inject ContactInfoBlockFeatureConfig mContactInfoBlockFeatureConfig; + @Inject UpdateFeaturedImageUseCase mUpdateFeaturedImageUseCase; private StorePostViewModel mViewModel; private StorageUtilsViewModel mStorageUtilsViewModel; @@ -1673,7 +1675,7 @@ private void onUploadSuccess(MediaModel media) { } } else if (media.getMarkedLocallyAsFeatured() && media.getLocalPostId() == mEditPostRepository .getId()) { - setFeaturedImageId(media.getMediaId(), false); + setFeaturedImageId(media.getMediaId(), false, false); } } } @@ -2302,9 +2304,7 @@ private GutenbergPropsBuilder getGutenbergPropsBuilder() { enableXPosts, isUnsupportedBlockEditorEnabled, unsupportedBlockEditorSwitch, - !isFreeWPCom, // Disable audio block until it's usable on free sites via "Insert from URL" capability - // Only enable reusable block in WP.com sites until the issue - // (https://github.com/wordpress-mobile/gutenberg-mobile/issues/3457) in self-hosted sites is fixed + !isFreeWPCom, isWPComSite, wpcomLocaleSlug, postType, @@ -2484,12 +2484,32 @@ protected void setPostContentFromShareAction() { } } - private void setFeaturedImageId(final long mediaId, final boolean imagePicked) { - if (mEditPostSettingsFragment != null) { - mEditPostSettingsFragment.updateFeaturedImage(mediaId, imagePicked); - if (mEditorFragment instanceof GutenbergEditorFragment) { - ((GutenbergEditorFragment) mEditorFragment).sendToJSFeaturedImageId((int) mediaId); + private void setFeaturedImageId(final long mediaId, final boolean imagePicked, final boolean isGutenbergEditor) { + if (isGutenbergEditor) { + EditPostRepository postRepository = getEditPostRepository(); + if (postRepository == null) { + return; } + + int postId = getEditPostRepository().getId(); + if (mediaId == MEDIA_ID_NO_FEATURED_IMAGE_SET) { + mFeaturedImageHelper.trackFeaturedImageEvent( + FeaturedImageHelper.TrackableEvent.IMAGE_REMOVED_GUTENBERG_EDITOR, + postId + ); + } else { + mFeaturedImageHelper.trackFeaturedImageEvent( + FeaturedImageHelper.TrackableEvent.IMAGE_PICKED_GUTENBERG_EDITOR, + postId + ); + } + mUpdateFeaturedImageUseCase.updateFeaturedImage(mediaId, postRepository, + postModel -> null); + } else if (mEditPostSettingsFragment != null) { + mEditPostSettingsFragment.updateFeaturedImage(mediaId, imagePicked); + } + if (mEditorFragment instanceof GutenbergEditorFragment) { + ((GutenbergEditorFragment) mEditorFragment).sendToJSFeaturedImageId((int) mediaId); } } @@ -2600,13 +2620,13 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { // user chose a featured image if (data.hasExtra(MediaPickerConstants.EXTRA_MEDIA_ID)) { long mediaId = data.getLongExtra(MediaPickerConstants.EXTRA_MEDIA_ID, 0); - setFeaturedImageId(mediaId, true); + setFeaturedImageId(mediaId, true, false); } else if (data.hasExtra(MediaPickerConstants.EXTRA_MEDIA_QUEUED_URIS)) { List uris = convertStringArrayIntoUrisList( data.getStringArrayExtra(MediaPickerConstants.EXTRA_MEDIA_QUEUED_URIS)); int postId = getImmutablePost().getId(); mFeaturedImageHelper.trackFeaturedImageEvent( - FeaturedImageHelper.TrackableEvent.IMAGE_PICKED, + FeaturedImageHelper.TrackableEvent.IMAGE_PICKED_POST_SETTINGS, postId ); for (Uri mediaUri : uris) { @@ -2894,6 +2914,11 @@ public void onEditPostPublishedSettingsClick() { } } + @Override + public void updateFeaturedImage(final long mediaId, final boolean imagePicked) { + setFeaturedImageId(mediaId, imagePicked, true); + } + @Override public void onAddMediaClicked() { if (mEditorPhotoPicker.isPhotoPickerShowing()) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostSettingsFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostSettingsFragment.java index aaf155a037bb..f1add7b4561b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostSettingsFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostSettingsFragment.java @@ -134,6 +134,7 @@ public class EditPostSettingsFragment extends Fragment { @Inject AnalyticsTrackerWrapper mAnalyticsTrackerWrapper; @Inject UpdatePostStatusUseCase mUpdatePostStatusUseCase; @Inject MediaPickerLauncher mMediaPickerLauncher; + @Inject UpdateFeaturedImageUseCase mUpdateFeaturedImageUseCase; @Inject ViewModelProvider.Factory mViewModelFactory; private EditPostPublishSettingsViewModel mPublishedViewModel; @@ -1000,23 +1001,21 @@ public void updateFeaturedImage(long featuredImageId, boolean imagePicked) { if (isAdded() && imagePicked) { int postId = getEditPostRepository().getId(); mFeaturedImageHelper.trackFeaturedImageEvent( - TrackableEvent.IMAGE_PICKED, + TrackableEvent.IMAGE_PICKED_POST_SETTINGS, postId ); } + EditPostRepository postRepository = getEditPostRepository(); if (postRepository == null) { return; } - postRepository.updateAsync(postModel -> { - postModel.setFeaturedImageId(featuredImageId); - return true; - }, (postModel, result) -> { - if (result == UpdatePostResult.Updated.INSTANCE) { - updateFeaturedImageView(postModel); - } - return null; - }); + + mUpdateFeaturedImageUseCase.updateFeaturedImage(featuredImageId, postRepository, + postModel -> { + updateFeaturedImageView(postModel); + return null; + }); } private void clearFeaturedImage() { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/FeaturedImageHelper.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/FeaturedImageHelper.kt index 0b6fd2e1613d..7304aa7ca34a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/FeaturedImageHelper.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/FeaturedImageHelper.kt @@ -201,7 +201,9 @@ class FeaturedImageHelper @Inject constructor( enum class TrackableEvent(val label: Stat) { IMAGE_SET_CLICKED(Stat.FEATURED_IMAGE_SET_CLICKED_POST_SETTINGS), - IMAGE_PICKED(Stat.FEATURED_IMAGE_PICKED_POST_SETTINGS), + IMAGE_PICKED_POST_SETTINGS(Stat.FEATURED_IMAGE_PICKED_POST_SETTINGS), + IMAGE_PICKED_GUTENBERG_EDITOR(Stat.FEATURED_IMAGE_PICKED_GUTENBERG_EDITOR), + IMAGE_REMOVED_GUTENBERG_EDITOR(Stat.FEATURED_IMAGE_REMOVED_GUTENBERG_EDITOR), IMAGE_UPLOAD_CANCELED(Stat.FEATURED_IMAGE_UPLOAD_CANCELED_POST_SETTINGS), IMAGE_UPLOAD_RETRY_CLICKED(Stat.FEATURED_IMAGE_UPLOAD_RETRY_CLICKED_POST_SETTINGS), IMAGE_REMOVE_CLICKED(Stat.FEATURED_IMAGE_REMOVE_CLICKED_POST_SETTINGS) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/UpdateFeaturedImageUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/UpdateFeaturedImageUseCase.kt new file mode 100644 index 000000000000..1335dcdeed77 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/UpdateFeaturedImageUseCase.kt @@ -0,0 +1,24 @@ +package org.wordpress.android.ui.posts + +import org.wordpress.android.fluxc.model.PostImmutableModel +import org.wordpress.android.fluxc.model.PostModel +import org.wordpress.android.ui.posts.EditPostRepository.UpdatePostResult +import org.wordpress.android.ui.posts.EditPostRepository.UpdatePostResult.Updated +import javax.inject.Inject + +class UpdateFeaturedImageUseCase @Inject constructor() { + fun updateFeaturedImage( + featuredImageId: Long, + editPostRepository: EditPostRepository, + onPostFeaturedImageUpdated: (PostImmutableModel) -> Unit + ) { + editPostRepository.updateAsync({ postModel: PostModel -> + postModel.setFeaturedImageId(featuredImageId) + true + }) { postModel: PostImmutableModel, result: UpdatePostResult -> + if (result === Updated) { + onPostFeaturedImageUpdated.invoke(postModel) + } + } + } +} diff --git a/build.gradle b/build.gradle index 23c3b7fe8eea..88d9fa47ff63 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { ext.kotlin_ktx_version = '1.2.0' ext.wordPressUtilsVersion = 'develop-bb54ee34c5fec5fa7375ce90a356adb5adbdcae0' ext.detektVersion = '1.15.0' - ext.gutenbergMobileVersion = 'v1.54.0' + ext.gutenbergMobileVersion = 'develop-b316b2b49f57f08426f1a33418f28480cdc8787b' repositories { google() diff --git a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java index a8b7875c0f27..0847212d08eb 100644 --- a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java +++ b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java @@ -691,6 +691,8 @@ public enum Stat { WELCOME_NO_SITES_INTERSTITIAL_DISMISSED, FEATURED_IMAGE_SET_CLICKED_POST_SETTINGS, FEATURED_IMAGE_PICKED_POST_SETTINGS, + FEATURED_IMAGE_PICKED_GUTENBERG_EDITOR, + FEATURED_IMAGE_REMOVED_GUTENBERG_EDITOR, FEATURED_IMAGE_UPLOAD_CANCELED_POST_SETTINGS, FEATURED_IMAGE_UPLOAD_RETRY_CLICKED_POST_SETTINGS, FEATURED_IMAGE_REMOVE_CLICKED_POST_SETTINGS, diff --git a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java index f47de494fe1c..2cb04dd62ff3 100644 --- a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java +++ b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java @@ -1890,6 +1890,10 @@ public static String getEventNameForStat(AnalyticsTracker.Stat stat) { return "featured_image_set_clicked_post_settings"; case FEATURED_IMAGE_PICKED_POST_SETTINGS: return "featured_image_picked_post_settings"; + case FEATURED_IMAGE_PICKED_GUTENBERG_EDITOR: + return "featured_image_picked_gutenberg_editor"; + case FEATURED_IMAGE_REMOVED_GUTENBERG_EDITOR: + return "featured_image_removed_gutenberg_editor"; case FEATURED_IMAGE_UPLOAD_CANCELED_POST_SETTINGS: return "featured_image_upload_canceled_post_settings"; case FEATURED_IMAGE_UPLOAD_RETRY_CLICKED_POST_SETTINGS: diff --git a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java index 473f9163136e..51c713c0f88a 100644 --- a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java +++ b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/EditorFragmentAbstract.java @@ -178,6 +178,7 @@ public static MediaType getEditorMimeType(MediaFile mediaFile) { public interface EditorFragmentListener extends DialogVisibilityProvider { void onEditorFragmentInitialized(); void onEditorFragmentContentReady(ArrayList unsupportedBlocks, boolean replaceBlockActionWaiting); + void updateFeaturedImage(long mediaId, boolean imagePicked); void onAddMediaClicked(); void onAddMediaImageClicked(boolean allowMultipleSelection); void onAddMediaVideoClicked(boolean allowMultipleSelection); diff --git a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergContainerFragment.java b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergContainerFragment.java index d9c4b6f2f806..aa34ad3cf1c2 100644 --- a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergContainerFragment.java +++ b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergContainerFragment.java @@ -29,6 +29,7 @@ import org.wordpress.mobile.WPAndroidGlue.WPAndroidGlueCode.OnMediaEditorListener; import org.wordpress.mobile.WPAndroidGlue.WPAndroidGlueCode.OnMediaLibraryButtonListener; import org.wordpress.mobile.WPAndroidGlue.WPAndroidGlueCode.OnMediaFilesCollectionBasedBlockEditorListener; +import org.wordpress.mobile.WPAndroidGlue.WPAndroidGlueCode.OnSetFeaturedImageListener; import java.util.ArrayList; @@ -56,6 +57,7 @@ public boolean hasReceivedAnyContent() { public void attachToContainer(ViewGroup viewGroup, OnMediaLibraryButtonListener onMediaLibraryButtonListener, OnReattachMediaUploadQueryListener onReattachQueryListener, OnReattachMediaSavingQueryListener onStorySavingReattachQueryListener, + OnSetFeaturedImageListener onSetFeaturedImageListener, OnEditorMountListener onEditorMountListener, OnEditorAutosaveListener onEditorAutosaveListener, OnAuthHeaderRequestedListener onAuthHeaderRequestedListener, @@ -76,6 +78,7 @@ public void attachToContainer(ViewGroup viewGroup, OnMediaLibraryButtonListener onMediaLibraryButtonListener, onReattachQueryListener, onStorySavingReattachQueryListener, + onSetFeaturedImageListener, onEditorMountListener, onEditorAutosaveListener, onAuthHeaderRequestedListener, diff --git a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergDialogFragment.kt b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergDialogFragment.kt new file mode 100644 index 000000000000..1ef39f81f298 --- /dev/null +++ b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergDialogFragment.kt @@ -0,0 +1,133 @@ +package org.wordpress.android.editor.gutenberg + +import android.app.Dialog +import android.content.Context +import android.content.DialogInterface +import android.os.Bundle +import androidx.appcompat.app.AppCompatDialogFragment +import androidx.fragment.app.Fragment +import com.google.android.material.dialog.MaterialAlertDialogBuilder + +class GutenbergDialogFragment() : AppCompatDialogFragment() { + private lateinit var mTag: String + private lateinit var mMessage: CharSequence + private lateinit var mPositiveButtonLabel: CharSequence + private var mTitle: CharSequence? = null + private var mNegativeButtonLabel: CharSequence? = null + private var mId: Int = 0 + private var dismissedByPositiveButton = false + private var dismissedByNegativeButton = false + + interface GutenbergDialogPositiveClickInterface { + fun onGutenbergDialogPositiveClicked(instanceTag: String, id: Int) + } + + interface GutenbergDialogNegativeClickInterface { + fun onGutenbergDialogNegativeClicked(instanceTag: String) + } + + interface GutenbergDialogOnDismissByOutsideTouchInterface { + fun onDismissByOutsideTouch(instanceTag: String) + } + + fun initialize( + tag: String, + title: CharSequence?, + message: CharSequence, + positiveButtonLabel: CharSequence, + negativeButtonLabel: CharSequence? = null, + id: Int + ) { + mTag = tag + mTitle = title + mMessage = message + mPositiveButtonLabel = positiveButtonLabel + mNegativeButtonLabel = negativeButtonLabel + mId = id + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.isCancelable = true + val theme = 0 + setStyle(STYLE_NORMAL, theme) + + if (savedInstanceState != null) { + mTag = requireNotNull(savedInstanceState.getString(STATE_KEY_TAG)) + mTitle = savedInstanceState.getCharSequence(STATE_KEY_TITLE) + mMessage = requireNotNull(savedInstanceState.getCharSequence(STATE_KEY_MESSAGE)) + mPositiveButtonLabel = requireNotNull(savedInstanceState.getCharSequence(STATE_KEY_POSITIVE_BUTTON_LABEL)) + mNegativeButtonLabel = savedInstanceState.getCharSequence(STATE_KEY_NEGATIVE_BUTTON_LABEL) + mId = savedInstanceState.getInt(STATE_KEY_ID) + } + } + + override fun onSaveInstanceState(outState: Bundle) { + outState.putString(STATE_KEY_TAG, mTag) + outState.putCharSequence(STATE_KEY_TITLE, mTitle) + outState.putCharSequence(STATE_KEY_MESSAGE, mMessage) + outState.putCharSequence(STATE_KEY_POSITIVE_BUTTON_LABEL, mPositiveButtonLabel) + outState.putCharSequence(STATE_KEY_NEGATIVE_BUTTON_LABEL, mNegativeButtonLabel) + outState.putInt(STATE_KEY_ID, mId) + super.onSaveInstanceState(outState) + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val builder = MaterialAlertDialogBuilder(requireActivity()) + builder.setMessage(mMessage) + + mTitle?.let { + builder.setTitle(mTitle) + } + + mPositiveButtonLabel?.let { + builder.setPositiveButton(mPositiveButtonLabel) { _, _ -> + dismissedByPositiveButton = true + (parentFragment as? GutenbergDialogPositiveClickInterface)?.let { + it.onGutenbergDialogPositiveClicked(mTag, mId) + } + }.setCancelable(true) + } + + mNegativeButtonLabel?.let { + builder.setNegativeButton(mNegativeButtonLabel) { _, _ -> + dismissedByNegativeButton = true + (parentFragment as? GutenbergDialogNegativeClickInterface)?.let { + it.onGutenbergDialogNegativeClicked(mTag) + } + } + } + + return builder.create() + } + + override fun onAttach(context: Context) { + super.onAttach(context) + val parentFragment: Fragment? = parentFragment + if (parentFragment !is GutenbergDialogPositiveClickInterface) { + throw RuntimeException("Parent fragment must implement GutenbergDialogPositiveClickInterface") + } + if (mNegativeButtonLabel != null && parentFragment !is GutenbergDialogNegativeClickInterface) { + throw RuntimeException("Parent fragment must implement GutenbergDialogNegativeClickInterface") + } + } + + override fun onDismiss(dialog: DialogInterface) { + // Only handle the event if it wasn't triggered by a button + if (!dismissedByPositiveButton && !dismissedByNegativeButton) { + (parentFragment as? GutenbergDialogOnDismissByOutsideTouchInterface)?.let { + it.onDismissByOutsideTouch(mTag) + } + } + super.onDismiss(dialog) + } + + companion object { + private const val STATE_KEY_TAG = "state_key_tag" + private const val STATE_KEY_TITLE = "state_key_title" + private const val STATE_KEY_MESSAGE = "state_key_message" + private const val STATE_KEY_POSITIVE_BUTTON_LABEL = "state_key_positive_button_label" + private const val STATE_KEY_NEGATIVE_BUTTON_LABEL = "state_key_negative_button_label" + private const val STATE_KEY_ID = "state_key_id" + } +} diff --git a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergEditorFragment.java b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergEditorFragment.java index a1d2f56de720..afa77f8e9c6a 100644 --- a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergEditorFragment.java +++ b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergEditorFragment.java @@ -34,6 +34,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.gson.Gson; +import org.jetbrains.annotations.NotNull; import org.wordpress.android.editor.BuildConfig; import org.wordpress.android.editor.EditorEditMediaListener; import org.wordpress.android.editor.EditorFragmentAbstract; @@ -44,6 +45,8 @@ import org.wordpress.android.editor.LiveTextWatcher; import org.wordpress.android.editor.R; import org.wordpress.android.editor.WPGutenbergWebViewActivity; +import org.wordpress.android.editor.gutenberg.GutenbergDialogFragment.GutenbergDialogPositiveClickInterface; +import org.wordpress.android.editor.gutenberg.GutenbergDialogFragment.GutenbergDialogNegativeClickInterface; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.AppLog.T; import org.wordpress.android.util.DateTimeUtils; @@ -68,6 +71,7 @@ import org.wordpress.mobile.WPAndroidGlue.WPAndroidGlueCode.OnMediaLibraryButtonListener; import org.wordpress.mobile.WPAndroidGlue.WPAndroidGlueCode.OnReattachMediaSavingQueryListener; import org.wordpress.mobile.WPAndroidGlue.WPAndroidGlueCode.OnReattachMediaUploadQueryListener; +import org.wordpress.mobile.WPAndroidGlue.WPAndroidGlueCode.OnSetFeaturedImageListener; import java.util.ArrayList; import java.util.Date; @@ -83,7 +87,9 @@ public class GutenbergEditorFragment extends EditorFragmentAbstract implements EditorMediaUploadListener, IHistoryListener, EditorThemeUpdateListener, - StorySaveMediaListener { + StorySaveMediaListener, + GutenbergDialogPositiveClickInterface, + GutenbergDialogNegativeClickInterface { private static final String GUTENBERG_EDITOR_NAME = "gutenberg"; private static final String KEY_HTML_MODE_ENABLED = "KEY_HTML_MODE_ENABLED"; private static final String KEY_EDITOR_DID_MOUNT = "KEY_EDITOR_DID_MOUNT"; @@ -95,6 +101,7 @@ public class GutenbergEditorFragment extends EditorFragmentAbstract implements public static final String ARG_STORY_BLOCK_UPDATED_CONTENT = "story_block_updated_content"; public static final String ARG_STORY_BLOCK_EXTERNALLY_EDITED_ORIGINAL_HASH = "story_block_original_hash"; public static final String ARG_FAILED_MEDIAS = "arg_failed_medias"; + public static final String ARG_FEATURED_IMAGE_ID = "featured_image_id"; private static final int CAPTURE_PHOTO_PERMISSION_REQUEST_CODE = 101; private static final int CAPTURE_VIDEO_PERMISSION_REQUEST_CODE = 102; @@ -108,6 +115,10 @@ public class GutenbergEditorFragment extends EditorFragmentAbstract implements private static final int UNSUPPORTED_BLOCK_REQUEST_CODE = 1001; + private static final String TAG_REPLACE_FEATURED_DIALOG = "REPLACE_FEATURED_DIALOG"; + + public static final int MEDIA_ID_NO_FEATURED_IMAGE_SET = 0; + private boolean mHtmlModeEnabled; private Handler mInvalidateOptionsHandler; @@ -197,6 +208,7 @@ public void onCreate(Bundle savedInstanceState) { mExternallyEditedBlockOriginalHash = savedInstanceState.getString( ARG_STORY_BLOCK_EXTERNALLY_EDITED_ORIGINAL_HASH); mFailedMediaIds = (HashSet) savedInstanceState.getSerializable(ARG_FAILED_MEDIAS); + mFeaturedImageId = savedInstanceState.getLong(ARG_FEATURED_IMAGE_ID); } } @@ -333,6 +345,30 @@ public void onQueryCurrentProgressForUploadingMedia() { updateMediaProgress(); } }, + new OnSetFeaturedImageListener() { + @Override + public void onSetFeaturedImageButtonClicked(int mediaId) { + if (mediaId == mFeaturedImageId) { + // nothing special to do, trying to set the image that's already set as featured + return; + } + + if (mediaId == MEDIA_ID_NO_FEATURED_IMAGE_SET) { + // user tries to clear the featured image setting + setFeaturedImage(mediaId); + return; + } + + if (mFeaturedImageId == MEDIA_ID_NO_FEATURED_IMAGE_SET) { + // current featured image is not set so, go ahead and set it to the provided one + setFeaturedImage(mediaId); + return; + } + + // ask the user to confirm changing the featured image since there's already one set + showFeaturedImageConfirmationDialog(mediaId); + } + }, new OnEditorMountListener() { @Override public void onEditorDidMount(ArrayList unsupportedBlocks) { @@ -774,6 +810,31 @@ public void onClick(DialogInterface dialog, int id) { dialog.show(); } + public void showFeaturedImageConfirmationDialog(final int mediaId) { + GutenbergDialogFragment dialog = new GutenbergDialogFragment(); + dialog.initialize( + TAG_REPLACE_FEATURED_DIALOG, + getString(R.string.featured_image_replace_dialog_title), + getString(R.string.featured_image_replace_dialog_description), + getString(R.string.featured_image_replace_dialog_confirm), + getString(R.string.featured_image_replace_dialog_cancel), + mediaId + ); + + dialog.show(getChildFragmentManager(), TAG_REPLACE_FEATURED_DIALOG); + } + + private void setFeaturedImage(int mediaId) { + mEditorFragmentListener.updateFeaturedImage(mediaId, false); + setFeaturedImageId(mediaId); + + if (mediaId == MEDIA_ID_NO_FEATURED_IMAGE_SET) { + showNotice(getString(R.string.featured_image_removed_notice)); + } else { + showNotice(getString(R.string.featured_image_confirmation_notice)); + } + } + public void sendToJSFeaturedImageId(int mediaId) { getGutenbergContainerFragment().sendToJSFeaturedImageId(mediaId); } @@ -882,6 +943,7 @@ public void onSaveInstanceState(Bundle outState) { outState.putBoolean(KEY_EDITOR_DID_MOUNT, mEditorDidMount); outState.putString(ARG_STORY_BLOCK_EXTERNALLY_EDITED_ORIGINAL_HASH, mExternallyEditedBlockOriginalHash); outState.putSerializable(ARG_FAILED_MEDIAS, mFailedMediaIds); + outState.putLong(ARG_FEATURED_IMAGE_ID, mFeaturedImageId); } @Override @@ -1334,4 +1396,22 @@ public void onEditorThemeUpdated(Bundle editorTheme) { public void showNotice(String message) { getGutenbergContainerFragment().showNotice(message); } + + @Override + public void onGutenbergDialogPositiveClicked(@NotNull String instanceTag, int mediaId) { + switch (instanceTag) { + case TAG_REPLACE_FEATURED_DIALOG: + setFeaturedImage(mediaId); + break; + } + } + + @Override + public void onGutenbergDialogNegativeClicked(@NotNull String instanceTag) { + switch (instanceTag) { + case TAG_REPLACE_FEATURED_DIALOG: + // Dismiss dialog with no action. + break; + } + } } diff --git a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt index e1040eb7c8ba..05e40d8ca33f 100644 --- a/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt +++ b/libs/editor/WordPressEditor/src/main/java/org/wordpress/android/editor/gutenberg/GutenbergPropsBuilder.kt @@ -14,7 +14,7 @@ data class GutenbergPropsBuilder( private val enableXPosts: Boolean, private val enableUnsupportedBlockEditor: Boolean, private val unsupportedBlockEditorSwitch: Boolean, - private val enableAudioBlock: Boolean, + private val isAudioBlockMediaUploadEnabled: Boolean, private val enableReusableBlock: Boolean, private val localeSlug: String, private val postType: String, @@ -29,7 +29,7 @@ data class GutenbergPropsBuilder( enableXPosts = enableXPosts, enableUnsupportedBlockEditor = enableUnsupportedBlockEditor, canEnableUnsupportedBlockEditor = unsupportedBlockEditorSwitch, - enableAudioBlock = enableAudioBlock, + isAudioBlockMediaUploadEnabled = isAudioBlockMediaUploadEnabled, enableReusableBlock = enableReusableBlock, localeSlug = localeSlug, postType = postType, diff --git a/libs/editor/WordPressEditor/src/main/res/values/strings.xml b/libs/editor/WordPressEditor/src/main/res/values/strings.xml index 136f2d1dc7e1..fcb8f125cce7 100644 --- a/libs/editor/WordPressEditor/src/main/res/values/strings.xml +++ b/libs/editor/WordPressEditor/src/main/res/values/strings.xml @@ -154,6 +154,13 @@ We’ll be removing the classic editor for new posts soon, but this won’t affect editing any of your existing posts or pages. Get a head start by enabling the Block Editor now in site settings. Dismiss - + + Featured Image Already Set + You already have a featured image set. Do you want to replace it? + Replace + Cancel + + Set as featured image + Removed as featured image