2015-03-23 20:28:42 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*/
|
2015-03-10 00:08:01 +00:00
|
|
|
|
|
|
|
#import "RCTCameraRollManager.h"
|
|
|
|
|
|
|
|
#import <AssetsLibrary/AssetsLibrary.h>
|
|
|
|
#import <CoreLocation/CoreLocation.h>
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
#import <UIKit/UIKit.h>
|
|
|
|
|
|
|
|
#import "RCTImageLoader.h"
|
|
|
|
#import "RCTLog.h"
|
|
|
|
|
|
|
|
@implementation RCTCameraRollManager
|
|
|
|
|
|
|
|
- (void)saveImageWithTag:(NSString *)imageTag successCallback:(RCTResponseSenderBlock)successCallback errorCallback:(RCTResponseSenderBlock)errorCallback
|
|
|
|
{
|
|
|
|
RCT_EXPORT();
|
|
|
|
|
|
|
|
[RCTImageLoader loadImageWithTag:imageTag callback:^(NSError *loadError, UIImage *loadedImage) {
|
|
|
|
if (loadError) {
|
|
|
|
errorCallback(@[[loadError localizedDescription]]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
[[RCTImageLoader assetsLibrary] writeImageToSavedPhotosAlbum:[loadedImage CGImage] metadata:nil completionBlock:^(NSURL *assetURL, NSError *saveError) {
|
|
|
|
if (saveError) {
|
|
|
|
NSString *errorMessage = [NSString stringWithFormat:@"Error saving cropped image: %@", saveError];
|
|
|
|
RCTLogWarn(@"%@", errorMessage);
|
|
|
|
errorCallback(@[errorMessage]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
successCallback(@[[assetURL absoluteString]]);
|
|
|
|
}];
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)callCallback:(RCTResponseSenderBlock)callback withAssets:(NSArray *)assets hasNextPage:(BOOL)hasNextPage
|
|
|
|
{
|
|
|
|
if (![assets count]) {
|
|
|
|
callback(@[@{
|
|
|
|
@"edges": assets,
|
|
|
|
@"page_info": @{
|
|
|
|
@"has_next_page": @NO}
|
|
|
|
}]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
callback(@[@{
|
|
|
|
@"edges": assets,
|
|
|
|
@"page_info": @{
|
|
|
|
@"start_cursor": assets[0][@"node"][@"image"][@"uri"],
|
|
|
|
@"end_cursor": assets[assets.count - 1][@"node"][@"image"][@"uri"],
|
|
|
|
@"has_next_page": @(hasNextPage)}
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)getPhotos:(NSDictionary *)params callback:(RCTResponseSenderBlock)callback errorCallback:(RCTResponseSenderBlock)errorCallback
|
|
|
|
{
|
|
|
|
RCT_EXPORT();
|
|
|
|
|
|
|
|
NSUInteger first = [params[@"first"] integerValue];
|
|
|
|
NSString *afterCursor = params[@"after"];
|
|
|
|
NSString *groupTypesStr = params[@"groupTypes"];
|
|
|
|
NSString *groupName = params[@"groupName"];
|
|
|
|
ALAssetsGroupType groupTypes;
|
|
|
|
if ([groupTypesStr isEqualToString:@"Album"]) {
|
|
|
|
groupTypes = ALAssetsGroupAlbum;
|
|
|
|
} else if ([groupTypesStr isEqualToString:@"All"]) {
|
|
|
|
groupTypes = ALAssetsGroupAll;
|
|
|
|
} else if ([groupTypesStr isEqualToString:@"Event"]) {
|
|
|
|
groupTypes = ALAssetsGroupEvent;
|
|
|
|
} else if ([groupTypesStr isEqualToString:@"Faces"]) {
|
|
|
|
groupTypes = ALAssetsGroupFaces;
|
|
|
|
} else if ([groupTypesStr isEqualToString:@"Library"]) {
|
|
|
|
groupTypes = ALAssetsGroupLibrary;
|
|
|
|
} else if ([groupTypesStr isEqualToString:@"PhotoStream"]) {
|
|
|
|
groupTypes = ALAssetsGroupPhotoStream;
|
|
|
|
} else {
|
|
|
|
groupTypes = ALAssetsGroupSavedPhotos;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL __block foundAfter = NO;
|
|
|
|
BOOL __block hasNextPage = NO;
|
|
|
|
BOOL __block calledCallback = NO;
|
|
|
|
NSMutableArray *assets = [[NSMutableArray alloc] init];
|
|
|
|
|
|
|
|
[[RCTImageLoader assetsLibrary] enumerateGroupsWithTypes:groupTypes usingBlock:^(ALAssetsGroup *group, BOOL *stopGroups) {
|
|
|
|
if (group && (groupName == nil || [groupName isEqualToString:[group valueForProperty:ALAssetsGroupPropertyName]])) {
|
|
|
|
[group setAssetsFilter:ALAssetsFilter.allPhotos];
|
|
|
|
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stopAssets) {
|
|
|
|
if (result) {
|
|
|
|
NSString *uri = [(NSURL *)[result valueForProperty:ALAssetPropertyAssetURL] absoluteString];
|
|
|
|
if (afterCursor && !foundAfter) {
|
|
|
|
if ([afterCursor isEqualToString:uri]) {
|
|
|
|
foundAfter = YES;
|
|
|
|
}
|
|
|
|
return; // Skip until we get to the first one
|
|
|
|
}
|
|
|
|
if (first == [assets count]) {
|
|
|
|
*stopAssets = YES;
|
|
|
|
*stopGroups = YES;
|
|
|
|
hasNextPage = YES;
|
|
|
|
RCTAssert(calledCallback == NO, @"Called the callback before we finished processing the results.");
|
|
|
|
[self callCallback:callback withAssets:assets hasNextPage:hasNextPage];
|
|
|
|
calledCallback = YES;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
CGSize dimensions = [result defaultRepresentation].dimensions;
|
|
|
|
CLLocation *loc = [result valueForProperty:ALAssetPropertyLocation];
|
|
|
|
NSDate *date = [result valueForProperty:ALAssetPropertyDate];
|
|
|
|
[assets addObject:@{
|
|
|
|
@"node": @{
|
|
|
|
@"type": [result valueForProperty:ALAssetPropertyType],
|
|
|
|
@"group_name": [group valueForProperty:ALAssetsGroupPropertyName],
|
|
|
|
@"image": @{
|
|
|
|
@"uri": uri,
|
|
|
|
@"height": @(dimensions.height),
|
|
|
|
@"width": @(dimensions.width),
|
|
|
|
@"isStored": @YES,
|
|
|
|
},
|
|
|
|
@"timestamp": @([date timeIntervalSince1970]),
|
|
|
|
@"location": loc ?
|
|
|
|
@{
|
|
|
|
@"latitude": @(loc.coordinate.latitude),
|
|
|
|
@"longitude": @(loc.coordinate.longitude),
|
|
|
|
@"altitude": @(loc.altitude),
|
|
|
|
@"heading": @(loc.course),
|
|
|
|
@"speed": @(loc.speed),
|
|
|
|
} : @{},
|
|
|
|
}
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
}];
|
|
|
|
} else {
|
|
|
|
// Sometimes the enumeration continues even if we set stop above, so we guard against calling the callback
|
|
|
|
// multiple times here.
|
|
|
|
if (!calledCallback) {
|
|
|
|
[self callCallback:callback withAssets:assets hasNextPage:hasNextPage];
|
|
|
|
calledCallback = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} failureBlock:^(NSError *error) {
|
|
|
|
if (error.code != ALAssetsLibraryAccessUserDeniedError) {
|
|
|
|
RCTLogError(@"Failure while iterating through asset groups %@", error);
|
|
|
|
}
|
|
|
|
errorCallback(@[error.description]);
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|