From cd412c195f7a6f36da6189fb0dcf12913e6175bc Mon Sep 17 00:00:00 2001 From: Woraphot Chokratanasombat Date: Wed, 5 Jun 2019 17:35:35 +0700 Subject: [PATCH 1/4] BREAKING CHANGE: Use promise instead of callback --- .../imageeditor/ImageEditorModule.java | 30 ++++++++----------- example/src/App.js | 18 ++++++----- ios/RNCImageEditor.m | 10 +++---- lib/ImageEditor.js | 6 ++-- typings/index.d.ts | 4 +-- 5 files changed, 31 insertions(+), 37 deletions(-) diff --git a/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModule.java b/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModule.java index ccba0f4..0c3378f 100644 --- a/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModule.java +++ b/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModule.java @@ -37,8 +37,8 @@ import android.text.TextUtils; import com.facebook.common.logging.FLog; -import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.GuardedAsyncTask; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; @@ -150,25 +150,23 @@ public boolean accept(File dir, String filename) { } /** - * Crop an image. If all goes well, the success callback will be called with the file:// URI of + * Crop an image. If all goes well, the promise will be resolved with the file:// URI of * the new image as the only argument. This is a temporary file - consider using * CameraRollManager.saveImageWithTag to save it in the gallery. * - * @param uri the MediaStore URI of the image to crop + * @param uri the URI of the image to crop * @param options crop parameters specified as {@code {offset: {x, y}, size: {width, height}}}. * Optionally this also contains {@code {targetSize: {width, height}}}. If this is * specified, the cropped image will be resized to that size. * All units are in pixels (not DPs). - * @param success callback to be invoked when the image has been cropped; the only argument that - * is passed to this callback is the file:// URI of the new image - * @param error callback to be invoked when an error occurs (e.g. can't create file etc.) + * @param promise Promise to be resolved when the image has been cropped; the only argument that + * is passed to this is the file:// URI of the new image */ @ReactMethod public void cropImage( String uri, ReadableMap options, - final Callback success, - final Callback error) { + Promise promise) { ReadableMap offset = options.hasKey("offset") ? options.getMap("offset") : null; ReadableMap size = options.hasKey("size") ? options.getMap("size") : null; if (offset == null || size == null || @@ -187,8 +185,7 @@ public void cropImage( (int) offset.getDouble("y"), (int) size.getDouble("width"), (int) size.getDouble("height"), - success, - error); + promise); if (options.hasKey("displaySize")) { ReadableMap targetSize = options.getMap("displaySize"); cropTask.setTargetSize( @@ -207,8 +204,7 @@ private static class CropTask extends GuardedAsyncTask { final int mHeight; int mTargetWidth = 0; int mTargetHeight = 0; - final Callback mSuccess; - final Callback mError; + final Promise mPromise; private CropTask( ReactContext context, @@ -217,8 +213,7 @@ private CropTask( int y, int width, int height, - Callback success, - Callback error) { + Promise promise) { super(context); if (x < 0 || y < 0 || width <= 0 || height <= 0) { throw new JSApplicationIllegalArgumentException(String.format( @@ -230,8 +225,7 @@ private CropTask( mY = y; mWidth = width; mHeight = height; - mSuccess = success; - mError = error; + mPromise = promise; } public void setTargetSize(int width, int height) { @@ -284,9 +278,9 @@ protected void doInBackgroundGuarded(Void... params) { copyExif(mContext, Uri.parse(mUri), tempFile); } - mSuccess.invoke(Uri.fromFile(tempFile).toString()); + mPromise.resolve(Uri.fromFile(tempFile).toString()); } catch (Exception e) { - mError.invoke(e.getMessage()); + mPromise.reject(e); } } diff --git a/example/src/App.js b/example/src/App.js index b70001e..10a55ec 100755 --- a/example/src/App.js +++ b/example/src/App.js @@ -150,13 +150,17 @@ export default class SquareImageCropper extends React.Component< ); } - _crop() { - ImageEditor.cropImage( - this.state.randomPhoto.uri, - this._transformData, - croppedImageURI => this.setState({croppedImageURI}), - cropError => this.setState({cropError}), - ); + async _crop() { + try { + const croppedImageURI = await ImageEditor.cropImage( + this.state.randomPhoto.uri, + this._transformData, + ); + + if (!!croppedImageURI) this.setState({croppedImageURI}); + } catch (cropError) { + this.setState({cropError}); + } } _reset() { diff --git a/ios/RNCImageEditor.m b/ios/RNCImageEditor.m index 23d928a..3654af7 100644 --- a/ios/RNCImageEditor.m +++ b/ios/RNCImageEditor.m @@ -42,8 +42,8 @@ @implementation RNCImageEditor */ RCT_EXPORT_METHOD(cropImage:(NSURLRequest *)imageRequest cropData:(NSDictionary *)cropData - successCallback:(RCTResponseSenderBlock)successCallback - errorCallback:(RCTResponseErrorBlock)errorCallback) + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) { CGRect rect = { [RCTConvert CGPoint:cropData[@"offset"]], @@ -52,7 +52,7 @@ @implementation RNCImageEditor [_bridge.imageLoader loadImageWithURLRequest:imageRequest callback:^(NSError *error, UIImage *image) { if (error) { - errorCallback(error); + reject(@(error.code).stringValue, error.description, error); return; } @@ -79,11 +79,11 @@ @implementation RNCImageEditor NSString *uri = [RNCImageUtils writeImage:imageData toPath:path error:&writeError]; if (writeError != nil) { - errorCallback(writeError); + reject(@(writeError.code).stringValue, writeError.description, writeError); return; } - successCallback(@[uri]); + resolve(uri); }]; } diff --git a/lib/ImageEditor.js b/lib/ImageEditor.js index e07a1ea..a358fa3 100644 --- a/lib/ImageEditor.js +++ b/lib/ImageEditor.js @@ -63,10 +63,8 @@ class ImageEditor { static cropImage( uri: string, cropData: ImageCropData, - success: (uri: string) => void, - failure: (error: Object) => void, - ) { - RNCImageEditor.cropImage(uri, cropData, success, failure); + ): Promise { + return RNCImageEditor.cropImage(uri, cropData); } } diff --git a/typings/index.d.ts b/typings/index.d.ts index 43d35f3..0456e46 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -47,9 +47,7 @@ declare class ImageEditor { static cropImage: ( uri: string, cropData: ImageCropData, - success: (uri: string) => void, - failure: (error: Object) => void, - ) => void + ) => Promise } export default ImageEditor \ No newline at end of file From a96448702f26ccc9ac9f42dae89e57a7c7c81487 Mon Sep 17 00:00:00 2001 From: Woraphot Chokratanasombat Date: Wed, 5 Jun 2019 17:36:38 +0700 Subject: [PATCH 2/4] chore(doc): Update document to reflect using promise instead of callback --- README.md | 18 ++++++++++++++---- lib/ImageEditor.js | 8 ++++---- typings/index.d.ts | 8 ++++---- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 1104905..3414918 100755 --- a/README.md +++ b/README.md @@ -21,15 +21,25 @@ or `react-native link @react-native-community/image-editor` -## Api reference +## Usage + +Start by importing the library: ```javascript - static cropImage(uri, cropData, success, failure) +import ImageEditor from "@react-native-community/image-editor"; ``` -Crop the image specified by the URI param. If URI points to a remote image, it will be downloaded automatically. If the image cannot be loaded/downloaded, the failure callback will be called. +### Crop image + +Crop the image specified by the URI param. If URI points to a remote image, it will be downloaded automatically. If the image cannot be loaded/downloaded, the promise will be rejected. + +If the cropping process is successful, the resultant cropped image will be stored in the cache path, and the URI returned in the promise will point to the image in the cache path. Remember to delete the cropped image from the cache path when you are done with it. -If the cropping process is successful, the resultant cropped image will be stored in the ImageStore, and the URI returned in the success callback will point to the image in the store. Remember to delete the cropped image from the ImageStore when you are done with it. +```javascript + ImageEditor.cropImage(uri, cropData).then(url => { + console.log("Cropped image uri", url); + }) +``` ### cropData | Property | Required | Description | diff --git a/lib/ImageEditor.js b/lib/ImageEditor.js index a358fa3..33aa136 100644 --- a/lib/ImageEditor.js +++ b/lib/ImageEditor.js @@ -51,14 +51,14 @@ class ImageEditor { /** * Crop the image specified by the URI param. If URI points to a remote * image, it will be downloaded automatically. If the image cannot be - * loaded/downloaded, the failure callback will be called. On Android, a + * loaded/downloaded, the promise will be rejected. On Android, a * downloaded image may be cached in external storage, a publicly accessible * location, if it has more available space than internal storage. * * If the cropping process is successful, the resultant cropped image - * will be stored in the ImageStore, and the URI returned in the success - * callback will point to the image in the store. Remember to delete the - * cropped image from the ImageStore when you are done with it. + * will be stored in the Cache Path, and the URI returned in the promise + * will point to the image in the cache path. Remember to delete the + * cropped image from the cache path when you are done with it. */ static cropImage( uri: string, diff --git a/typings/index.d.ts b/typings/index.d.ts index 0456e46..5c000be 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -35,14 +35,14 @@ declare class ImageEditor { /** * Crop the image specified by the URI param. If URI points to a remote * image, it will be downloaded automatically. If the image cannot be - * loaded/downloaded, the failure callback will be called. On Android, a + * loaded/downloaded, the promise will be rejected. On Android, a * downloaded image may be cached in external storage, a publicly accessible * location, if it has more available space than internal storage. * * If the cropping process is successful, the resultant cropped image - * will be stored in the ImageStore, and the URI returned in the success - * callback will point to the image in the store. Remember to delete the - * cropped image from the ImageStore when you are done with it. + * will be stored in the Cache Path, and the URI returned in the promise + * will point to the image in the cache path. Remember to delete the + * cropped image from the cache path when you are done with it. */ static cropImage: ( uri: string, From bd2677c93f3ac59592ff130b0f3537a57bdaf283 Mon Sep 17 00:00:00 2001 From: Woraphot Chokratanasombat Date: Wed, 5 Jun 2019 17:44:23 +0700 Subject: [PATCH 3/4] fix(example): Ensure that iOS always get new image --- example/src/App.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/src/App.js b/example/src/App.js index 10a55ec..80ba86d 100755 --- a/example/src/App.js +++ b/example/src/App.js @@ -65,7 +65,7 @@ export default class SquareImageCropper extends React.Component< async _fetchRandomPhoto() { this.setState({ randomPhoto: { - uri: `http://placeimg.com/${DEFAULT_IMAGE_WIDTH}/${DEFAULT_IMAGE_HEIGHT}/tech`, + uri: `http://placeimg.com/${DEFAULT_IMAGE_WIDTH}/${DEFAULT_IMAGE_HEIGHT}/tech?${new Date().getTime()}`, height: DEFAULT_IMAGE_HEIGHT, width: DEFAULT_IMAGE_WIDTH, }, From edb9056e6aad2a5c06acc7172ee6fbdcfb6a2d42 Mon Sep 17 00:00:00 2001 From: Trancever Date: Mon, 10 Jun 2019 09:26:23 +0200 Subject: [PATCH 4/4] fix: eslint errors --- example/src/App.js | 4 +++- lib/ImageEditor.js | 5 +---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/example/src/App.js b/example/src/App.js index 80ba86d..0499e20 100755 --- a/example/src/App.js +++ b/example/src/App.js @@ -157,7 +157,9 @@ export default class SquareImageCropper extends React.Component< this._transformData, ); - if (!!croppedImageURI) this.setState({croppedImageURI}); + if (croppedImageURI) { + this.setState({croppedImageURI}); + } } catch (cropError) { this.setState({cropError}); } diff --git a/lib/ImageEditor.js b/lib/ImageEditor.js index 33aa136..9d0e8c5 100644 --- a/lib/ImageEditor.js +++ b/lib/ImageEditor.js @@ -60,10 +60,7 @@ class ImageEditor { * will point to the image in the cache path. Remember to delete the * cropped image from the cache path when you are done with it. */ - static cropImage( - uri: string, - cropData: ImageCropData, - ): Promise { + static cropImage(uri: string, cropData: ImageCropData): Promise { return RNCImageEditor.cropImage(uri, cropData); } }