Moved CameraRoll-related classes into CameraRoll folder instead of Image

Summary:
The CameraRoll-related APIs were mixed in with the Image classes due to legacy coupling issues. Now that the APIs have been decoupled, it makes more sense for the CameraRoll classes to live in a separate library.

This will be a breaking change for apps using the CameraRoll or related APIs. Fix is to add the RCTCameraRoll lib to your project.
This commit is contained in:
Nick Lockwood
2015-09-08 08:58:13 -07:00
parent 93b9329b75
commit 56d25bbbdd
15 changed files with 345 additions and 36 deletions

View File

@@ -1,40 +0,0 @@
/**
* 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.
*
* @providesModule ImagePickerIOS
* @flow
*/
'use strict';
var RCTImagePicker = require('NativeModules').ImagePickerIOS;
var ImagePickerIOS = {
canRecordVideos: function(callback: Function) {
return RCTImagePicker.canRecordVideos(callback);
},
canUseCamera: function(callback: Function) {
return RCTImagePicker.canUseCamera(callback);
},
openCameraDialog: function(config: Object, successCallback: Function, cancelCallback: Function) {
config = {
videoMode: false,
...config,
}
return RCTImagePicker.openCameraDialog(config, successCallback, cancelCallback);
},
openSelectDialog: function(config: Object, successCallback: Function, cancelCallback: Function) {
config = {
showImages: true,
showVideos: false,
...config,
}
return RCTImagePicker.openSelectDialog(config, successCallback, cancelCallback);
},
};
module.exports = ImagePickerIOS;

View File

@@ -1,28 +0,0 @@
/**
* 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.
*/
#import "RCTImageLoader.h"
@interface RCTAssetsLibraryImageLoader : NSObject <RCTImageURLLoader>
@end
@interface RCTBridge (RCTAssetsLibraryImageLoader)
/**
* The shared Assets Library image loader
*/
@property (nonatomic, readonly) RCTAssetsLibraryImageLoader *assetsLibraryImageLoader;
/**
* The shared asset library instance.
*/
@property (nonatomic, readonly) ALAssetsLibrary *assetsLibrary;
@end

View File

@@ -1,155 +0,0 @@
/**
* 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.
*/
#import "RCTAssetsLibraryImageLoader.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <ImageIO/ImageIO.h>
#import <UIKit/UIKit.h>
#import "RCTBridge.h"
#import "RCTConvert.h"
#import "RCTImageLoader.h"
#import "RCTImageUtils.h"
#import "RCTUtils.h"
static dispatch_queue_t RCTAssetsLibraryImageLoaderQueue(void);
static UIImage *RCTScaledImageForAsset(ALAssetRepresentation *representation, CGSize size, CGFloat scale, UIViewContentMode resizeMode, NSError **error);
@implementation RCTAssetsLibraryImageLoader
{
ALAssetsLibrary *_assetsLibrary;
}
RCT_EXPORT_MODULE()
@synthesize bridge = _bridge;
- (ALAssetsLibrary *)assetsLibrary
{
return _assetsLibrary ?: (_assetsLibrary = [ALAssetsLibrary new]);
}
#pragma mark - RCTImageLoader
- (BOOL)canLoadImageURL:(NSURL *)requestURL
{
return [requestURL.scheme.lowercaseString isEqualToString:@"assets-library"];
}
- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL size:(CGSize)size scale:(CGFloat)scale resizeMode:(UIViewContentMode)resizeMode progressHandler:(RCTImageLoaderProgressBlock)progressHandler completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
[[self assetsLibrary] assetForURL:imageURL resultBlock:^(ALAsset *asset) {
if (asset) {
// ALAssetLibrary API is async and will be multi-threaded. Loading a few full
// resolution images at once will spike the memory up to store the image data,
// and might trigger memory warnings and/or OOM crashes.
// To improve this, process the loaded asset in a serial queue.
dispatch_async(RCTAssetsLibraryImageLoaderQueue(), ^{
// Also make sure the image is released immediately after it's used so it
// doesn't spike the memory up during the process.
@autoreleasepool {
BOOL useMaximumSize = CGSizeEqualToSize(size, CGSizeZero);
ALAssetRepresentation *representation = [asset defaultRepresentation];
UIImage *image;
NSError *error = nil;
if (useMaximumSize) {
image = [UIImage imageWithCGImage:representation.fullResolutionImage
scale:scale
orientation:(UIImageOrientation)representation.orientation];
} else {
image = RCTScaledImageForAsset(representation, size, scale, resizeMode, &error);
}
completionHandler(error, image);
}
});
} else {
NSString *errorText = [NSString stringWithFormat:@"Failed to load asset at URL %@ with no error message.", imageURL];
NSError *error = RCTErrorWithMessage(errorText);
completionHandler(error, nil);
}
} failureBlock:^(NSError *loadError) {
NSString *errorText = [NSString stringWithFormat:@"Failed to load asset at URL %@.\niOS Error: %@", imageURL, loadError];
NSError *error = RCTErrorWithMessage(errorText);
completionHandler(error, nil);
}];
return ^{};
}
@end
@implementation RCTBridge (RCTAssetsLibraryImageLoader)
- (RCTAssetsLibraryImageLoader *)assetsLibraryImageLoader
{
return self.modules[RCTBridgeModuleNameForClass([RCTAssetsLibraryImageLoader class])];
}
- (ALAssetsLibrary *)assetsLibrary
{
return [self.assetsLibraryImageLoader assetsLibrary];
}
@end
static dispatch_queue_t RCTAssetsLibraryImageLoaderQueue(void)
{
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue = dispatch_queue_create("com.facebook.RCTAssetsLibraryImageLoader", DISPATCH_QUEUE_SERIAL);
});
return queue;
}
// Why use a custom scaling method? Greater efficiency, reduced memory overhead:
// http://www.mindsea.com/2012/12/downscaling-huge-alassets-without-fear-of-sigkill
static UIImage *RCTScaledImageForAsset(ALAssetRepresentation *representation, CGSize size, CGFloat scale, UIViewContentMode resizeMode, NSError **error)
{
NSUInteger length = (NSUInteger)representation.size;
NSMutableData *data = [NSMutableData dataWithLength:length];
if (![representation getBytes:data.mutableBytes
fromOffset:0
length:length
error:error]) {
return nil;
}
CGSize sourceSize = representation.dimensions;
CGSize targetSize = RCTTargetSize(sourceSize, representation.scale,
size, scale, resizeMode, NO);
NSDictionary *options = @{
(id)kCGImageSourceShouldAllowFloat: @YES,
(id)kCGImageSourceCreateThumbnailWithTransform: @YES,
(id)kCGImageSourceCreateThumbnailFromImageAlways: @YES,
(id)kCGImageSourceThumbnailMaxPixelSize: @(MAX(targetSize.width, targetSize.height) * scale)
};
CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, nil);
CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(sourceRef, 0, (__bridge CFDictionaryRef)options);
if (sourceRef) {
CFRelease(sourceRef);
}
if (imageRef) {
UIImage *image = [UIImage imageWithCGImage:imageRef scale:scale
orientation:UIImageOrientationUp];
CGImageRelease(imageRef);
return image;
}
return nil;
}

View File

@@ -1,14 +0,0 @@
/**
* 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.
*/
#import "RCTBridgeModule.h"
@interface RCTCameraRollManager : NSObject <RCTBridgeModule>
@end

View File

@@ -1,171 +0,0 @@
/**
* 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.
*/
#import "RCTCameraRollManager.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <CoreLocation/CoreLocation.h>
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "RCTAssetsLibraryImageLoader.h"
#import "RCTBridge.h"
#import "RCTImageLoader.h"
#import "RCTLog.h"
#import "RCTUtils.h"
@implementation RCTCameraRollManager
RCT_EXPORT_MODULE()
@synthesize bridge = _bridge;
RCT_EXPORT_METHOD(saveImageWithTag:(NSString *)imageTag
successCallback:(RCTResponseSenderBlock)successCallback
errorCallback:(RCTResponseErrorBlock)errorCallback)
{
[_bridge.imageLoader loadImageWithTag:imageTag callback:^(NSError *loadError, UIImage *loadedImage) {
if (loadError) {
errorCallback(loadError);
return;
}
[_bridge.assetsLibrary writeImageToSavedPhotosAlbum:loadedImage.CGImage metadata:nil completionBlock:^(NSURL *assetURL, NSError *saveError) {
if (saveError) {
RCTLogWarn(@"Error saving cropped image: %@", saveError);
errorCallback(saveError);
} else {
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)}
}]);
}
RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
callback:(RCTResponseSenderBlock)callback
errorCallback:(RCTResponseErrorBlock)errorCallback)
{
NSUInteger first = [params[@"first"] integerValue];
NSString *afterCursor = params[@"after"];
NSString *groupTypesStr = params[@"groupTypes"];
NSString *groupName = params[@"groupName"];
NSString *assetType = params[@"assetType"];
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 new];
[_bridge.assetsLibrary enumerateGroupsWithTypes:groupTypes usingBlock:^(ALAssetsGroup *group, BOOL *stopGroups) {
if (group && (groupName == nil || [groupName isEqualToString:[group valueForProperty:ALAssetsGroupPropertyName]])) {
if (assetType == nil || [assetType isEqualToString:@"Photos"]) {
[group setAssetsFilter:ALAssetsFilter.allPhotos];
} else if ([assetType isEqualToString:@"Videos"]) {
[group setAssetsFilter:ALAssetsFilter.allVideos];
} else if ([assetType isEqualToString:@"All"]) {
[group setAssetsFilter:ALAssetsFilter.allAssets];
}
[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);
}];
}
@end

View File

@@ -11,14 +11,10 @@
1304D5AC1AA8C4A30002E2BE /* RCTImageViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5AA1AA8C4A30002E2BE /* RCTImageViewManager.m */; };
1304D5B21AA8C50D0002E2BE /* RCTGIFImageDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5B11AA8C50D0002E2BE /* RCTGIFImageDecoder.m */; };
134B00A21B54232B00EC8DFB /* RCTImageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 134B00A11B54232B00EC8DFB /* RCTImageUtils.m */; };
137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137620341B31C53500677FF0 /* RCTImagePickerManager.m */; };
143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */; };
143879381AAD32A300F088A5 /* RCTImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879371AAD32A300F088A5 /* RCTImageLoader.m */; };
35123E6B1B59C99D00EBAD80 /* RCTImageStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 35123E6A1B59C99D00EBAD80 /* RCTImageStoreManager.m */; };
354631681B69857700AA0B86 /* RCTImageEditingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 354631671B69857700AA0B86 /* RCTImageEditingManager.m */; };
58B5118F1A9E6BD600147676 /* RCTImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 58B5118A1A9E6BD600147676 /* RCTImageDownloader.m */; };
8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */; };
8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */; };
83DDA1571B8DCA5800892A1C /* RCTAssetBundleImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 83DDA1561B8DCA5800892A1C /* RCTAssetBundleImageLoader.m */; };
/* End PBXBuildFile section */
@@ -43,10 +39,6 @@
1304D5B11AA8C50D0002E2BE /* RCTGIFImageDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTGIFImageDecoder.m; sourceTree = "<group>"; };
134B00A01B54232B00EC8DFB /* RCTImageUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageUtils.h; sourceTree = "<group>"; };
134B00A11B54232B00EC8DFB /* RCTImageUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageUtils.m; sourceTree = "<group>"; };
137620331B31C53500677FF0 /* RCTImagePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImagePickerManager.h; sourceTree = "<group>"; };
137620341B31C53500677FF0 /* RCTImagePickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImagePickerManager.m; sourceTree = "<group>"; };
143879331AAD238D00F088A5 /* RCTCameraRollManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTCameraRollManager.h; sourceTree = "<group>"; };
143879341AAD238D00F088A5 /* RCTCameraRollManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCameraRollManager.m; sourceTree = "<group>"; };
143879361AAD32A300F088A5 /* RCTImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageLoader.h; sourceTree = "<group>"; };
143879371AAD32A300F088A5 /* RCTImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoader.m; sourceTree = "<group>"; };
35123E691B59C99D00EBAD80 /* RCTImageStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageStoreManager.h; sourceTree = "<group>"; };
@@ -56,10 +48,6 @@
58B5115D1A9E6B3D00147676 /* libRCTImage.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTImage.a; sourceTree = BUILT_PRODUCTS_DIR; };
58B511891A9E6BD600147676 /* RCTImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageDownloader.h; sourceTree = "<group>"; };
58B5118A1A9E6BD600147676 /* RCTImageDownloader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageDownloader.m; sourceTree = "<group>"; };
8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAssetsLibraryImageLoader.h; sourceTree = "<group>"; };
8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAssetsLibraryImageLoader.m; sourceTree = "<group>"; };
8312EAEF1B85F071001867A2 /* RCTPhotoLibraryImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPhotoLibraryImageLoader.h; sourceTree = "<group>"; };
8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPhotoLibraryImageLoader.m; sourceTree = "<group>"; };
83DDA1551B8DCA5800892A1C /* RCTAssetBundleImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAssetBundleImageLoader.h; sourceTree = "<group>"; };
83DDA1561B8DCA5800892A1C /* RCTAssetBundleImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAssetBundleImageLoader.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -80,10 +68,6 @@
children = (
83DDA1551B8DCA5800892A1C /* RCTAssetBundleImageLoader.h */,
83DDA1561B8DCA5800892A1C /* RCTAssetBundleImageLoader.m */,
8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.h */,
8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */,
143879331AAD238D00F088A5 /* RCTCameraRollManager.h */,
143879341AAD238D00F088A5 /* RCTCameraRollManager.m */,
1304D5B01AA8C50D0002E2BE /* RCTGIFImageDecoder.h */,
1304D5B11AA8C50D0002E2BE /* RCTGIFImageDecoder.m */,
58B511891A9E6BD600147676 /* RCTImageDownloader.h */,
@@ -92,8 +76,6 @@
354631671B69857700AA0B86 /* RCTImageEditingManager.m */,
143879361AAD32A300F088A5 /* RCTImageLoader.h */,
143879371AAD32A300F088A5 /* RCTImageLoader.m */,
137620331B31C53500677FF0 /* RCTImagePickerManager.h */,
137620341B31C53500677FF0 /* RCTImagePickerManager.m */,
1304D5A71AA8C4A30002E2BE /* RCTImageView.h */,
1304D5A81AA8C4A30002E2BE /* RCTImageView.m */,
1304D5A91AA8C4A30002E2BE /* RCTImageViewManager.h */,
@@ -102,8 +84,6 @@
35123E6A1B59C99D00EBAD80 /* RCTImageStoreManager.m */,
134B00A01B54232B00EC8DFB /* RCTImageUtils.h */,
134B00A11B54232B00EC8DFB /* RCTImageUtils.m */,
8312EAEF1B85F071001867A2 /* RCTPhotoLibraryImageLoader.h */,
8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */,
58B5115E1A9E6B3D00147676 /* Products */,
);
indentWidth = 2;
@@ -174,14 +154,10 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m in Sources */,
35123E6B1B59C99D00EBAD80 /* RCTImageStoreManager.m in Sources */,
8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */,
58B5118F1A9E6BD600147676 /* RCTImageDownloader.m in Sources */,
137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */,
1304D5AC1AA8C4A30002E2BE /* RCTImageViewManager.m in Sources */,
1304D5B21AA8C50D0002E2BE /* RCTGIFImageDecoder.m in Sources */,
143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */,
143879381AAD32A300F088A5 /* RCTImageLoader.m in Sources */,
354631681B69857700AA0B86 /* RCTImageEditingManager.m in Sources */,
1304D5AB1AA8C4A30002E2BE /* RCTImageView.m in Sources */,

View File

@@ -1,15 +0,0 @@
/*
* Copyright (c) 2013, 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.
*
*/
#import "RCTBridgeModule.h"
@interface RCTImagePickerManager : NSObject <RCTBridgeModule>
@end

View File

@@ -1,135 +0,0 @@
/*
* Copyright (c) 2013, 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.
*
*/
#import "RCTImagePickerManager.h"
#import "RCTRootView.h"
#import <UIKit/UIKit.h>
#import <MobileCoreServices/UTCoreTypes.h>
@interface RCTImagePickerManager ()<UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@end
@implementation RCTImagePickerManager
{
NSMutableArray *_pickers;
NSMutableArray *_pickerCallbacks;
NSMutableArray *_pickerCancelCallbacks;
}
RCT_EXPORT_MODULE(ImagePickerIOS);
- (instancetype)init
{
if ((self = [super init])) {
_pickers = [NSMutableArray new];
_pickerCallbacks = [NSMutableArray new];
_pickerCancelCallbacks = [NSMutableArray new];
}
return self;
}
RCT_EXPORT_METHOD(canRecordVideos:(RCTResponseSenderBlock)callback)
{
NSArray *availableMediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
callback(@[@([availableMediaTypes containsObject:(NSString *)kUTTypeMovie])]);
}
RCT_EXPORT_METHOD(canUseCamera:(RCTResponseSenderBlock)callback)
{
callback(@[@([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])]);
}
RCT_EXPORT_METHOD(openCameraDialog:(NSDictionary *)config
successCallback:(RCTResponseSenderBlock)callback
cancelCallback:(RCTResponseSenderBlock)cancelCallback)
{
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
UIViewController *rootViewController = keyWindow.rootViewController;
UIImagePickerController *imagePicker = [UIImagePickerController new];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
if ([config[@"videoMode"] boolValue]) {
imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;
}
[_pickers addObject:imagePicker];
[_pickerCallbacks addObject:callback];
[_pickerCancelCallbacks addObject:cancelCallback];
[rootViewController presentViewController:imagePicker animated:YES completion:nil];
}
RCT_EXPORT_METHOD(openSelectDialog:(NSDictionary *)config
successCallback:(RCTResponseSenderBlock)callback
cancelCallback:(RCTResponseSenderBlock)cancelCallback)
{
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
UIViewController *rootViewController = keyWindow.rootViewController;
UIImagePickerController *imagePicker = [UIImagePickerController new];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
NSMutableArray *allowedTypes = [NSMutableArray new];
if ([config[@"showImages"] boolValue]) {
[allowedTypes addObject:(NSString *)kUTTypeImage];
}
if ([config[@"showVideos"] boolValue]) {
[allowedTypes addObject:(NSString *)kUTTypeMovie];
}
imagePicker.mediaTypes = allowedTypes;
[_pickers addObject:imagePicker];
[_pickerCallbacks addObject:callback];
[_pickerCancelCallbacks addObject:cancelCallback];
[rootViewController presentViewController:imagePicker animated:YES completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSUInteger index = [_pickers indexOfObject:picker];
RCTResponseSenderBlock callback = _pickerCallbacks[index];
[_pickers removeObjectAtIndex:index];
[_pickerCallbacks removeObjectAtIndex:index];
[_pickerCancelCallbacks removeObjectAtIndex:index];
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
UIViewController *rootViewController = keyWindow.rootViewController;
[rootViewController dismissViewControllerAnimated:YES completion:nil];
callback(@[[info[UIImagePickerControllerReferenceURL] absoluteString]]);
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
NSUInteger index = [_pickers indexOfObject:picker];
RCTResponseSenderBlock callback = _pickerCancelCallbacks[index];
[_pickers removeObjectAtIndex:index];
[_pickerCallbacks removeObjectAtIndex:index];
[_pickerCancelCallbacks removeObjectAtIndex:index];
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
UIViewController *rootViewController = keyWindow.rootViewController;
[rootViewController dismissViewControllerAnimated:YES completion:nil];
callback(@[]);
}
@end

View File

@@ -1,14 +0,0 @@
/**
* 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.
*/
#import "RCTImageLoader.h"
@interface RCTPhotoLibraryImageLoader : NSObject <RCTImageURLLoader>
@end

View File

@@ -1,82 +0,0 @@
/**
* 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.
*/
#import "RCTPhotoLibraryImageLoader.h"
#import <Photos/Photos.h>
#import "RCTImageUtils.h"
#import "RCTUtils.h"
@implementation RCTPhotoLibraryImageLoader
RCT_EXPORT_MODULE()
@synthesize bridge = _bridge;
#pragma mark - RCTImageLoader
- (BOOL)canLoadImageURL:(NSURL *)requestURL
{
return [requestURL.scheme.lowercaseString isEqualToString:@"ph"];
}
- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL size:(CGSize)size scale:(CGFloat)scale resizeMode:(UIViewContentMode)resizeMode progressHandler:(RCTImageLoaderProgressBlock)progressHandler completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
// Using PhotoKit for iOS 8+
// The 'ph://' prefix is used by FBMediaKit to differentiate between
// assets-library. It is prepended to the local ID so that it is in the
// form of an, NSURL which is what assets-library uses.
NSString *phAssetID = [imageURL.absoluteString substringFromIndex:[@"ph://" length]];
PHFetchResult *results = [PHAsset fetchAssetsWithLocalIdentifiers:@[phAssetID] options:nil];
if (results.count == 0) {
NSString *errorText = [NSString stringWithFormat:@"Failed to fetch PHAsset with local identifier %@ with no error message.", phAssetID];
NSError *error = RCTErrorWithMessage(errorText);
completionHandler(error, nil);
return ^{};
}
PHAsset *asset = [results firstObject];
PHImageRequestOptions *imageOptions = [PHImageRequestOptions new];
imageOptions.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
static const double multiplier = 1e6;
progressHandler(progress * multiplier, multiplier);
};
BOOL useMaximumSize = CGSizeEqualToSize(size, CGSizeZero);
CGSize targetSize;
if (useMaximumSize) {
targetSize = PHImageManagerMaximumSize;
imageOptions.resizeMode = PHImageRequestOptionsResizeModeNone;
} else {
targetSize = size;
imageOptions.resizeMode = PHImageRequestOptionsResizeModeFast;
}
PHImageContentMode contentMode = PHImageContentModeAspectFill;
if (resizeMode == UIViewContentModeScaleAspectFit) {
contentMode = PHImageContentModeAspectFit;
}
PHImageRequestID requestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:targetSize contentMode:contentMode options:imageOptions resultHandler:^(UIImage *result, NSDictionary *info) {
if (result) {
completionHandler(nil, result);
} else {
completionHandler(info[PHImageErrorKey], nil);
}
}];
return ^{
[[PHImageManager defaultManager] cancelImageRequest:requestID];
};
}
@end