mirror of
https://github.com/status-im/react-native-cameraroll.git
synced 2025-02-17 03:56:45 +00:00
feat(lib): Moved deletePhotos to use new PHAsset API and added an implementation for Android (#69)
* deletePhotos works in iOS * Deletion works on Android. * Removing unnecessary commented out code. * Updated typescript typings. * Made readme more accurate based on being able to retrieve failure from the iOS API. * Let formatter run, also now rejecting the promise when there's any error on deletion on Android.
This commit is contained in:
parent
384103860f
commit
7850dd538f
21
README.md
21
README.md
@ -73,6 +73,7 @@ On Android permission is required to read the external storage. Add below line t
|
|||||||
* [`saveToCameraRoll`](#savetocameraroll)
|
* [`saveToCameraRoll`](#savetocameraroll)
|
||||||
* [`save`](#save)
|
* [`save`](#save)
|
||||||
* [`getPhotos`](#getphotos)
|
* [`getPhotos`](#getphotos)
|
||||||
|
* [`deletePhotos`](#deletephotos)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -208,3 +209,23 @@ render() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
---
|
||||||
|
### `deletePhotos()`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
CameraRoll.deletePhotos([uri]);
|
||||||
|
```
|
||||||
|
|
||||||
|
Requests deletion of photos in the camera roll.
|
||||||
|
|
||||||
|
On Android, the uri must be a local image or video URI, such as `"file:///sdcard/img.png"`.
|
||||||
|
|
||||||
|
On iOS, the uri can be any image URI (including local, remote asset-library and base64 data URIs) or a local video file URI. The user is presented with a dialog box that shows them the asset(s) and asks them to confirm deletion. This is not able to be bypassed as per Apple Developer guidelines.
|
||||||
|
|
||||||
|
Returns a Promise which will resolve when the deletion request is completed, or reject if there is a problem during the deletion. On iOS the user is able to cancel the deletion request, which causes a rejection, while on Android the rejection will be due to a system error.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
| Name | Type | Required | Description |
|
||||||
|
| ---- | ---------------------- | -------- | ---------------------------------------------------------- |
|
||||||
|
| uri | string | Yes | See above. |
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
package com.reactnativecommunity.cameraroll;
|
package com.reactnativecommunity.cameraroll;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
|
import android.content.ContentUris;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.AssetFileDescriptor;
|
import android.content.res.AssetFileDescriptor;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
@ -61,6 +62,7 @@ public class CameraRollModule extends ReactContextBaseJavaModule {
|
|||||||
private static final String ERROR_UNABLE_TO_LOAD = "E_UNABLE_TO_LOAD";
|
private static final String ERROR_UNABLE_TO_LOAD = "E_UNABLE_TO_LOAD";
|
||||||
private static final String ERROR_UNABLE_TO_LOAD_PERMISSION = "E_UNABLE_TO_LOAD_PERMISSION";
|
private static final String ERROR_UNABLE_TO_LOAD_PERMISSION = "E_UNABLE_TO_LOAD_PERMISSION";
|
||||||
private static final String ERROR_UNABLE_TO_SAVE = "E_UNABLE_TO_SAVE";
|
private static final String ERROR_UNABLE_TO_SAVE = "E_UNABLE_TO_SAVE";
|
||||||
|
private static final String ERROR_UNABLE_TO_DELETE = "E_UNABLE_TO_DELETE";
|
||||||
private static final String ERROR_UNABLE_TO_FILTER = "E_UNABLE_TO_FILTER";
|
private static final String ERROR_UNABLE_TO_FILTER = "E_UNABLE_TO_FILTER";
|
||||||
|
|
||||||
private static final String ASSET_TYPE_PHOTOS = "Photos";
|
private static final String ASSET_TYPE_PHOTOS = "Photos";
|
||||||
@ -504,4 +506,79 @@ public class CameraRollModule extends ReactContextBaseJavaModule {
|
|||||||
node.putMap("location", location);
|
node.putMap("location", location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a set of images.
|
||||||
|
*
|
||||||
|
* @param uris array of file:// URIs of the images to delete
|
||||||
|
* @param promise to be resolved
|
||||||
|
*/
|
||||||
|
@ReactMethod
|
||||||
|
public void deletePhotos(ReadableArray uris, Promise promise) {
|
||||||
|
if (uris.size() == 0) {
|
||||||
|
promise.reject(ERROR_UNABLE_TO_DELETE, "Need at least one URI to delete");
|
||||||
|
} else {
|
||||||
|
new DeletePhotos(getReactApplicationContext(), uris, promise)
|
||||||
|
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DeletePhotos extends GuardedAsyncTask<Void, Void> {
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final ReadableArray mUris;
|
||||||
|
private final Promise mPromise;
|
||||||
|
|
||||||
|
public DeletePhotos(ReactContext context, ReadableArray uris, Promise promise) {
|
||||||
|
super(context);
|
||||||
|
mContext = context;
|
||||||
|
mUris = uris;
|
||||||
|
mPromise = promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doInBackgroundGuarded(Void... params) {
|
||||||
|
ContentResolver resolver = mContext.getContentResolver();
|
||||||
|
|
||||||
|
// Set up the projection (we only need the ID)
|
||||||
|
String[] projection = { MediaStore.Images.Media._ID };
|
||||||
|
|
||||||
|
// Match on the file path
|
||||||
|
String innerWhere = "?";
|
||||||
|
for (int i = 1; i < mUris.size(); i++) {
|
||||||
|
innerWhere += ", ?";
|
||||||
|
}
|
||||||
|
|
||||||
|
String selection = MediaStore.Images.Media.DATA + " IN (" + innerWhere + ")";
|
||||||
|
// Query for the ID of the media matching the file path
|
||||||
|
Uri queryUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||||
|
|
||||||
|
String[] selectionArgs = new String[mUris.size()];
|
||||||
|
for (int i = 0; i < mUris.size(); i++) {
|
||||||
|
Uri uri = Uri.parse(mUris.getString(i));
|
||||||
|
selectionArgs[i] = uri.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor cursor = resolver.query(queryUri, projection, selection, selectionArgs, null);
|
||||||
|
int deletedCount = 0;
|
||||||
|
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
|
||||||
|
Uri deleteUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
|
||||||
|
|
||||||
|
if (resolver.delete(deleteUri, null, null) == 1) {
|
||||||
|
deletedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
if (deletedCount == mUris.size()) {
|
||||||
|
mPromise.resolve(null);
|
||||||
|
} else {
|
||||||
|
mPromise.reject(ERROR_UNABLE_TO_DELETE,
|
||||||
|
"Could not delete all media, only deleted " + deletedCount + " photos.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,12 +367,17 @@ RCT_EXPORT_METHOD(deletePhotos:(NSArray<NSString *>*)assets
|
|||||||
resolve:(RCTPromiseResolveBlock)resolve
|
resolve:(RCTPromiseResolveBlock)resolve
|
||||||
reject:(RCTPromiseRejectBlock)reject)
|
reject:(RCTPromiseRejectBlock)reject)
|
||||||
{
|
{
|
||||||
NSArray<NSURL *> *assets_ = [RCTConvert NSURLArray:assets];
|
NSMutableArray *convertedAssets = [NSMutableArray array];
|
||||||
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
|
||||||
PHFetchResult<PHAsset *> *fetched =
|
for (NSString *asset in assets) {
|
||||||
[PHAsset fetchAssetsWithALAssetURLs:assets_ options:nil];
|
[convertedAssets addObject: [asset stringByReplacingOccurrencesOfString:@"ph://" withString:@""]];
|
||||||
[PHAssetChangeRequest deleteAssets:fetched];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
||||||
|
PHFetchResult<PHAsset *> *fetched =
|
||||||
|
[PHAsset fetchAssetsWithLocalIdentifiers:convertedAssets options:nil];
|
||||||
|
[PHAssetChangeRequest deleteAssets:fetched];
|
||||||
|
}
|
||||||
completionHandler:^(BOOL success, NSError *error) {
|
completionHandler:^(BOOL success, NSError *error) {
|
||||||
if (success == YES) {
|
if (success == YES) {
|
||||||
resolve(@(success));
|
resolve(@(success));
|
||||||
|
@ -123,8 +123,13 @@ class CameraRoll {
|
|||||||
return this.saveToCameraRoll(tag, 'photo');
|
return this.saveToCameraRoll(tag, 'photo');
|
||||||
}
|
}
|
||||||
|
|
||||||
static deletePhotos(photos: Array<string>) {
|
/**
|
||||||
return RNCCameraRoll.deletePhotos(photos);
|
* On iOS: requests deletion of a set of photos from the camera roll.
|
||||||
|
* On Android: Deletes a set of photos from the camera roll.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static deletePhotos(photoUris: Array<string>) {
|
||||||
|
return RNCCameraRoll.deletePhotos(photoUris);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
7
typings/CameraRoll.d.ts
vendored
7
typings/CameraRoll.d.ts
vendored
@ -71,11 +71,10 @@ declare namespace CameraRoll {
|
|||||||
function saveImageWithTag(tag: string): Promise<string>;
|
function saveImageWithTag(tag: string): Promise<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a photo from the camera roll or media library. photos is an array of photo uri's.
|
* Delete a photo from the camera roll or media library. photoUris is an array of photo uri's.
|
||||||
*/
|
*/
|
||||||
function deletePhotos(photos: Array<string>): void;
|
function deletePhotos(photoUris: Array<string>): void;
|
||||||
// deletePhotos: (photos: Array<string>) => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the photo or video to the camera roll or photo library.
|
* Saves the photo or video to the camera roll or photo library.
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user