From 7411092f61a621b22454cb15a2c45f24d6003109 Mon Sep 17 00:00:00 2001 From: Marko Savic Date: Tue, 29 Oct 2019 20:32:45 +0100 Subject: [PATCH] 720-Add support for giphy and pexel images (#1469) --- RELEASE-NOTES.txt | 1 + .../java/com/gutenberg/MainApplication.java | 14 ++++- gutenberg | 2 +- .../android/build.gradle | 3 + .../GutenbergBridgeJS2Parent.java | 15 +++-- .../RNReactNativeGutenbergBridgeModule.java | 38 +++++++----- .../mobile/WPAndroidGlue/MediaOption.java | 33 ++++++++++ .../WPAndroidGlue/WPAndroidGlueCode.java | 62 ++++++++----------- react-native-gutenberg-bridge/index.js | 8 +++ .../ios/RNReactNativeGutenbergBridge.m | 2 + .../ios/RNReactNativeGutenbergBridge.swift | 10 +++ 11 files changed, 130 insertions(+), 58 deletions(-) create mode 100644 react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/MediaOption.java diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index edc401cbc4914..a7d5db3402cb0 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,5 +1,6 @@ 1.16.0 ------ +* Add support for pexels images * Add left, center, and right image alignment controls 1.15.0 diff --git a/android/app/src/main/java/com/gutenberg/MainApplication.java b/android/app/src/main/java/com/gutenberg/MainApplication.java index 52fa841ad0fcb..5cf8ab94cd3d4 100644 --- a/android/app/src/main/java/com/gutenberg/MainApplication.java +++ b/android/app/src/main/java/com/gutenberg/MainApplication.java @@ -37,7 +37,7 @@ public void responseHtml(String title, String html, boolean changed) { } @Override - public void requestMediaImport(String url, MediaSelectedCallback mediaSelectedCallback) { + public void requestMediaImport(String url, MediaUploadCallback mediaUploadCallback) { } @Override @@ -49,7 +49,7 @@ public void requestMediaPickFromDeviceLibrary(MediaUploadCallback mediaUploadCal } @Override - public void requestMediaPickFromMediaLibrary(MediaSelectedCallback mediaSelectedCallback, Boolean allowMultipleSelection, MediaType mediaType) { + public void requestMediaPickFromMediaLibrary(MediaUploadCallback mediaUploadCallback, Boolean allowMultipleSelection, MediaType mediaType) { } @@ -77,6 +77,16 @@ public void editorDidMount(ReadableArray unsupportedBlockNames) { public void editorDidAutosave() { } + @Override + public void getOtherMediaPickerOptions(OtherMediaOptionsReceivedCallback otherMediaOptionsReceivedCallback, MediaType mediaType) { + + } + + @Override + public void requestMediaPickFrom(String mediaSource, MediaUploadCallback mediaUploadCallback, Boolean allowMultipleSelection) { + + } + @Override public void editorDidEmitLog(String message, LogLevel logLevel) { switch (logLevel) { diff --git a/gutenberg b/gutenberg index 7aabe961f4a8b..bc8a136c9b048 160000 --- a/gutenberg +++ b/gutenberg @@ -1 +1 @@ -Subproject commit 7aabe961f4a8bfa5cfd280b2bd820c0fccf441b5 +Subproject commit bc8a136c9b0480ec76d278b3150165e8db5898b6 diff --git a/react-native-gutenberg-bridge/android/build.gradle b/react-native-gutenberg-bridge/android/build.gradle index 205593cfec447..12a3f38eb8601 100644 --- a/react-native-gutenberg-bridge/android/build.gradle +++ b/react-native-gutenberg-bridge/android/build.gradle @@ -117,6 +117,9 @@ dependencies { implementation "org.webkit:android-jsc:r241213" implementation project(':react-native-aztec') + // For animated GIF support + implementation 'com.facebook.fresco:animated-gif:2.0.0' + if (rootProject.ext.buildGutenbergFromSource) { println "using gutenberg from source" implementation project(':react-native-svg') diff --git a/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java b/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java index 856661273ccdd..d2a10ab4fb4fc 100644 --- a/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java +++ b/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java @@ -3,6 +3,9 @@ import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.WritableMap; +import org.wordpress.mobile.WPAndroidGlue.MediaOption; + +import java.util.ArrayList; import java.util.List; public interface GutenbergBridgeJS2Parent { @@ -17,8 +20,8 @@ interface RNMedia { void editorDidMount(ReadableArray unsupportedBlockNames); - interface MediaSelectedCallback { - void onMediaSelected(List mediaList); + interface OtherMediaOptionsReceivedCallback { + void onOtherMediaOptionsReceived(ArrayList mediaList); } interface MediaUploadCallback { @@ -76,13 +79,13 @@ public static MediaType getEnum(String value) { } } - void requestMediaPickFromMediaLibrary(MediaSelectedCallback mediaSelectedCallback, Boolean allowMultipleSelection, MediaType mediaType); + void requestMediaPickFromMediaLibrary(MediaUploadCallback mediaUploadCallback, Boolean allowMultipleSelection, MediaType mediaType); void requestMediaPickFromDeviceLibrary(MediaUploadCallback mediaUploadCallback, Boolean allowMultipleSelection, MediaType mediaType); void requestMediaPickerFromDeviceCamera(MediaUploadCallback mediaUploadCallback, MediaType mediaType); - void requestMediaImport(String url, MediaSelectedCallback mediaSelectedCallback); + void requestMediaImport(String url, MediaUploadCallback mediaUploadCallback); void mediaUploadSync(MediaUploadCallback mediaUploadCallback); @@ -95,4 +98,8 @@ public static MediaType getEnum(String value) { void editorDidEmitLog(String message, LogLevel logLevel); void editorDidAutosave(); + + void getOtherMediaPickerOptions(OtherMediaOptionsReceivedCallback otherMediaOptionsReceivedCallback, MediaType mediaType); + + void requestMediaPickFrom(String mediaSource, MediaUploadCallback mediaUploadCallback, Boolean allowMultipleSelection); } diff --git a/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java b/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java index 4ef6fb00c280d..c0d4ea2730d6a 100644 --- a/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java +++ b/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java @@ -13,10 +13,12 @@ import com.facebook.react.bridge.WritableNativeMap; import com.facebook.react.modules.core.DeviceEventManagerModule; -import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.MediaSelectedCallback; import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.MediaType; +import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.OtherMediaOptionsReceivedCallback; import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.RNMedia; +import org.wordpress.mobile.WPAndroidGlue.MediaOption; +import java.util.ArrayList; import java.util.List; public class RNReactNativeGutenbergBridgeModule extends ReactContextBaseJavaModule { @@ -110,7 +112,7 @@ public void editorDidMount(ReadableArray unsupportedBlockNames) { public void requestMediaPickFrom(String mediaSource, ReadableArray filter, Boolean allowMultipleSelection, final Callback onUploadMediaSelected) { MediaType mediaType = getMediaTypeFromFilter(filter); if (mediaSource.equals(MEDIA_SOURCE_MEDIA_LIBRARY)) { - mGutenbergBridgeJS2Parent.requestMediaPickFromMediaLibrary(getNewMediaSelectedCallback(allowMultipleSelection, onUploadMediaSelected), allowMultipleSelection, mediaType); + mGutenbergBridgeJS2Parent.requestMediaPickFromMediaLibrary(getNewUploadMediaCallback(allowMultipleSelection, onUploadMediaSelected), allowMultipleSelection, mediaType); } else if (mediaSource.equals(MEDIA_SOURCE_DEVICE_LIBRARY)) { mGutenbergBridgeJS2Parent.requestMediaPickFromDeviceLibrary(getNewUploadMediaCallback(allowMultipleSelection, onUploadMediaSelected), allowMultipleSelection, mediaType); } else if (mediaSource.equals(MEDIA_SOURCE_DEVICE_CAMERA)) { @@ -118,6 +120,11 @@ public void requestMediaPickFrom(String mediaSource, ReadableArray filter, Boole } } + @ReactMethod + public void requestOtherMediaPickFrom(String mediaSource, Boolean allowMultipleSelection, final Callback onUploadMediaSelected) { + mGutenbergBridgeJS2Parent.requestMediaPickFrom(mediaSource, getNewUploadMediaCallback(allowMultipleSelection, onUploadMediaSelected), allowMultipleSelection); + } + private MediaType getMediaTypeFromFilter(ReadableArray filter) { switch (filter.size()) { case 1: @@ -137,7 +144,7 @@ private MediaType getMediaTypeFromFilter(ReadableArray filter) { @ReactMethod public void requestMediaImport(String url, final Callback onUploadMediaSelected) { - mGutenbergBridgeJS2Parent.requestMediaImport(url, getNewMediaSelectedCallback(false, onUploadMediaSelected)); + mGutenbergBridgeJS2Parent.requestMediaImport(url, getNewUploadMediaCallback(false, onUploadMediaSelected)); } @ReactMethod @@ -170,18 +177,21 @@ public void editorDidAutosave() { mGutenbergBridgeJS2Parent.editorDidAutosave(); } - private MediaSelectedCallback getNewMediaSelectedCallback(final Boolean allowMultipleSelection, final Callback jsCallback) { - return new MediaSelectedCallback() { - @Override public void onMediaSelected(List mediaList) { - if(allowMultipleSelection) { - WritableArray writableArray = new WritableNativeArray(); - for (RNMedia media : mediaList) { - writableArray.pushMap(media.toMap()); - } - jsCallback.invoke(writableArray); - } else { - jsCallback.invoke(mediaList.get(0).toMap()); + @ReactMethod + public void getOtherMediaOptions(ReadableArray filter, final Callback jsCallback) { + OtherMediaOptionsReceivedCallback otherMediaOptionsReceivedCallback = getNewOtherMediaReceivedCallback(jsCallback); + MediaType mediaType = getMediaTypeFromFilter(filter); + mGutenbergBridgeJS2Parent.getOtherMediaPickerOptions(otherMediaOptionsReceivedCallback, mediaType); + } + + private OtherMediaOptionsReceivedCallback getNewOtherMediaReceivedCallback(final Callback jsCallback) { + return new OtherMediaOptionsReceivedCallback() { + @Override public void onOtherMediaOptionsReceived(ArrayList mediaOptions) { + WritableArray writableArray = new WritableNativeArray(); + for (MediaOption mediaOption : mediaOptions) { + writableArray.pushMap(mediaOption.toMap()); } + jsCallback.invoke(writableArray); } }; } diff --git a/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/MediaOption.java b/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/MediaOption.java new file mode 100644 index 0000000000000..188513dd5f988 --- /dev/null +++ b/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/MediaOption.java @@ -0,0 +1,33 @@ +package org.wordpress.mobile.WPAndroidGlue; + +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.WritableNativeMap; + +public class MediaOption { + + private static final String KEY_VALUE = "value"; + private static final String KEY_LABEL = "label"; + + private String mId; + private String mName; + + public MediaOption(String id, String name) { + mId = id; + mName = name; + } + + public String getId() { + return mId; + } + + public String getName() { + return mName; + } + + public WritableMap toMap() { + WritableMap map = new WritableNativeMap(); + map.putString(KEY_VALUE, mId); + map.putString(KEY_LABEL, mName); + return map; + } +} diff --git a/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java b/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java index 1201eb56c24a4..1965d5f7152b7 100644 --- a/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java +++ b/react-native-gutenberg-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java @@ -35,7 +35,6 @@ import org.wordpress.android.util.AppLog; import org.wordpress.mobile.ReactNativeAztec.ReactAztecPackage; import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent; -import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.MediaSelectedCallback; import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.MediaUploadCallback; import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.RNMedia; import org.wordpress.mobile.ReactNativeGutenbergBridge.RNReactNativeGutenbergBridgePackage; @@ -59,7 +58,6 @@ public class WPAndroidGlueCode { private ReactInstanceManager mReactInstanceManager; private ReactContext mReactContext; private RNReactNativeGutenbergBridgePackage mRnReactNativeGutenbergBridgePackage; - private MediaSelectedCallback mPendingMediaSelectedCallback; private MediaUploadCallback mPendingMediaUploadCallback; private boolean mMediaPickedByUserOnBlock; @@ -116,6 +114,8 @@ public interface OnMediaLibraryButtonListener { void onRetryUploadForMediaClicked(int mediaId); void onCancelUploadForMediaClicked(int mediaId); void onCancelUploadForMediaDueToDeletedBlock(int mediaId); + ArrayList onGetOtherMediaImageOptions(); + void onOtherMediaButtonClicked(String mediaSource, boolean allowMultipleSelection); } public interface OnReattachQueryListener { @@ -153,9 +153,9 @@ public void responseHtml(String title, String html, boolean changed) { } @Override - public void requestMediaPickFromMediaLibrary(MediaSelectedCallback mediaSelectedCallback, Boolean allowMultipleSelection, MediaType mediaType) { + public void requestMediaPickFromMediaLibrary(MediaUploadCallback mediaSelectedCallback, Boolean allowMultipleSelection, MediaType mediaType) { mMediaPickedByUserOnBlock = true; - mPendingMediaSelectedCallback = mediaSelectedCallback; + mPendingMediaUploadCallback = mediaSelectedCallback; if (mediaType == MediaType.IMAGE) { mOnMediaLibraryButtonListener.onMediaLibraryImageButtonClicked(allowMultipleSelection); } else if (mediaType == MediaType.VIDEO) { @@ -190,7 +190,7 @@ public void requestMediaPickerFromDeviceCamera(MediaUploadCallback mediaUploadCa } @Override - public void requestMediaImport(String url, MediaSelectedCallback mediaSelectedCallback) { + public void requestMediaImport(String url, MediaUploadCallback mediaSelectedCallback) { // no op - we don't need to paste images on Android, but the method needs to exist // to match the iOS counterpart } @@ -252,6 +252,26 @@ public void editorDidEmitLog(String message, LogLevel logLevel) { break; } } + + @Override + public void getOtherMediaPickerOptions(OtherMediaOptionsReceivedCallback otherMediaOptionsReceivedCallback, + MediaType mediaType) { + if (mediaType == MediaType.IMAGE || mediaType == MediaType.MEDIA) { + ArrayList otherMediaImageOptions = mOnMediaLibraryButtonListener.onGetOtherMediaImageOptions(); + otherMediaOptionsReceivedCallback.onOtherMediaOptionsReceived(otherMediaImageOptions); + } else { + otherMediaOptionsReceivedCallback.onOtherMediaOptionsReceived(new ArrayList()); + } + } + + @Override + public void requestMediaPickFrom(String mediaSource, + MediaUploadCallback mediaSelectedCallback, + Boolean allowMultipleSelection) { + mPendingMediaUploadCallback = mediaSelectedCallback; + mMediaPickedByUserOnBlock = true; + mOnMediaLibraryButtonListener.onOtherMediaButtonClicked(mediaSource, allowMultipleSelection); + } }); return Arrays.asList( @@ -522,21 +542,6 @@ private String getMediaType(final boolean isVideo) { return isVideo ? "video" : "image"; } - public void appendMediaFile(int mediaId, final String mediaUrl, final boolean isVideo) { - if (mPendingMediaSelectedCallback != null && mMediaPickedByUserOnBlock) { - String mediaType = getMediaType(isVideo); - mMediaPickedByUserOnBlock = false; - List mediaList = new ArrayList<>(); - mediaList.add(new Media(mediaId, mediaUrl, mediaType)); - mPendingMediaSelectedCallback.onMediaSelected(mediaList); - mPendingMediaSelectedCallback = null; - } else { - // we can assume we're being passed a new image from share intent as there was no selectMedia callback - sendOrDeferAppendMediaSignal(mediaId, mediaUrl, isVideo); - } - } - - public void toggleEditorMode(boolean htmlModeEnabled) { // Turn off hardware acceleration for Oreo // see https://github.com/wordpress-mobile/gutenberg-mobile/issues/1268#issuecomment-535887390 @@ -551,23 +556,6 @@ public void toggleEditorMode(boolean htmlModeEnabled) { mRnReactNativeGutenbergBridgePackage.getRNReactNativeGutenbergBridgeModule().toggleEditorMode(); } - public void appendMediaFiles(ArrayList mediaList) { - if (mPendingMediaSelectedCallback != null && mMediaPickedByUserOnBlock) { - mMediaPickedByUserOnBlock = false; - List rnMediaList = new ArrayList<>(); - for (Media media : mediaList) { - rnMediaList.add(new Media(media.getId(), media.getUrl())); - } - mPendingMediaSelectedCallback.onMediaSelected(rnMediaList); - mPendingMediaSelectedCallback = null; - } - } - - - public void toggleEditorMode() { - mRnReactNativeGutenbergBridgePackage.getRNReactNativeGutenbergBridgeModule().toggleEditorMode(); - } - public void appendUploadMediaFile(final int mediaId, final String mediaUri, final boolean isVideo) { if (isMediaUploadCallbackRegistered() && mMediaPickedByUserOnBlock) { String mediaType = getMediaType(isVideo); diff --git a/react-native-gutenberg-bridge/index.js b/react-native-gutenberg-bridge/index.js index 49fa6a9e61bcf..160e24c5c54f9 100644 --- a/react-native-gutenberg-bridge/index.js +++ b/react-native-gutenberg-bridge/index.js @@ -89,4 +89,12 @@ export function requestImageUploadCancel( mediaId ) { return RNReactNativeGutenbergBridge.requestImageUploadCancel( mediaId ); } +export function getOtherMediaOptions( filter, callback ) { + return RNReactNativeGutenbergBridge.getOtherMediaOptions( filter, callback ); +} + +export function requestOtherMediaPickFrom( mediaSource, multiple, callback ) { + return RNReactNativeGutenbergBridge.requestOtherMediaPickFrom( mediaSource, multiple, callback ); +} + export default RNReactNativeGutenbergBridge; diff --git a/react-native-gutenberg-bridge/ios/RNReactNativeGutenbergBridge.m b/react-native-gutenberg-bridge/ios/RNReactNativeGutenbergBridge.m index 80380f3b86eac..cfbdb36c87ea1 100644 --- a/react-native-gutenberg-bridge/ios/RNReactNativeGutenbergBridge.m +++ b/react-native-gutenberg-bridge/ios/RNReactNativeGutenbergBridge.m @@ -4,6 +4,8 @@ @interface RCT_EXTERN_MODULE(RNReactNativeGutenbergBridge, NSObject) RCT_EXTERN_METHOD(provideToNative_Html:(NSString *)html title:(NSString *)title changed:(BOOL)changed) RCT_EXTERN_METHOD(requestMediaPickFrom:(NSString *)source filter:(NSArray *)filter allowMultipleSelection:(BOOL)allowMultipleSelection callback:(RCTResponseSenderBlock)callback) +RCT_EXTERN_METHOD(requestOtherMediaPickFrom:(NSString *)source allowMultipleSelection:(BOOL)allowMultipleSelection callback:(RCTResponseSenderBlock)callback) +RCT_EXTERN_METHOD(getOtherMediaOptions:(NSArray *)filter callback:(RCTResponseSenderBlock)callback) RCT_EXTERN_METHOD(mediaUploadSync) RCT_EXTERN_METHOD(requestImageFailedRetryDialog:(int)mediaID) RCT_EXTERN_METHOD(requestImageUploadCancelDialog:(int)mediaID) diff --git a/react-native-gutenberg-bridge/ios/RNReactNativeGutenbergBridge.swift b/react-native-gutenberg-bridge/ios/RNReactNativeGutenbergBridge.swift index 47f145b70f765..9cb0b6f608ea8 100644 --- a/react-native-gutenberg-bridge/ios/RNReactNativeGutenbergBridge.swift +++ b/react-native-gutenberg-bridge/ios/RNReactNativeGutenbergBridge.swift @@ -42,6 +42,16 @@ public class RNReactNativeGutenbergBridge: RCTEventEmitter { }) } } + + @objc + func requestOtherMediaPickFrom(_ source: String, allowMultipleSelection: Bool, callback: @escaping RCTResponseSenderBlock) { + //TODO implement me + } + + @objc + func getOtherMediaOptions(_ filter: [String]?, callback: @escaping RCTResponseSenderBlock) { + //TODO implement me + } @objc func requestMediaImport(_ urlString: String, callback: @escaping RCTResponseSenderBlock) {