Move CameraRoll JS to FB internal

Summary: Moves relevant JS files to fb internal, removes stuff we don't need in the RN repo any more. Android and iOS will happen in a follow-up.

Reviewed By: rickhanlonii

Differential Revision: D15468419

fbshipit-source-id: 39fffc22f87534e557788e398bbae575043353b6
This commit is contained in:
Christoph Nakazawa 2019-05-23 07:02:23 -07:00 коммит произвёл Facebook Github Bot
Родитель 099be9b356
Коммит 3f04cfecda
18 изменённых файлов: 23 добавлений и 1661 удалений

Просмотреть файл

@ -1,250 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const PropTypes = require('prop-types');
const {checkPropTypes} = PropTypes;
const RCTCameraRollManager = require('../BatchedBridge/NativeModules')
.CameraRollManager;
const deprecatedCreateStrictShapeTypeChecker = require('../DeprecatedPropTypes/deprecatedCreateStrictShapeTypeChecker');
const invariant = require('invariant');
const GROUP_TYPES_OPTIONS = {
Album: 'Album',
All: 'All',
Event: 'Event',
Faces: 'Faces',
Library: 'Library',
PhotoStream: 'PhotoStream',
SavedPhotos: 'SavedPhotos', // default
};
const ASSET_TYPE_OPTIONS = {
All: 'All',
Videos: 'Videos',
Photos: 'Photos',
};
export type GroupTypes = $Keys<typeof GROUP_TYPES_OPTIONS>;
export type GetPhotosParams = {
first: number,
after?: string,
groupTypes?: GroupTypes,
groupName?: string,
assetType?: $Keys<typeof ASSET_TYPE_OPTIONS>,
mimeTypes?: Array<string>,
};
/**
* Shape of the param arg for the `getPhotos` function.
*/
const getPhotosParamChecker = deprecatedCreateStrictShapeTypeChecker({
/**
* The number of photos wanted in reverse order of the photo application
* (i.e. most recent first for SavedPhotos).
*/
first: PropTypes.number.isRequired,
/**
* A cursor that matches `page_info { end_cursor }` returned from a previous
* call to `getPhotos`
*/
after: PropTypes.string,
/**
* Specifies which group types to filter the results to.
*/
groupTypes: PropTypes.oneOf(Object.keys(GROUP_TYPES_OPTIONS)),
/**
* Specifies filter on group names, like 'Recent Photos' or custom album
* titles.
*/
groupName: PropTypes.string,
/**
* Specifies filter on asset type
*/
assetType: PropTypes.oneOf(Object.keys(ASSET_TYPE_OPTIONS)),
/**
* Filter by mimetype (e.g. image/jpeg).
*/
mimeTypes: PropTypes.arrayOf(PropTypes.string),
});
export type PhotoIdentifier = {
node: {
type: string,
group_name: string,
image: {
filename: string,
uri: string,
height: number,
width: number,
isStored?: boolean,
playableDuration: number,
},
timestamp: number,
location?: {
latitude?: number,
longitude?: number,
altitude?: number,
heading?: number,
speed?: number,
},
},
};
export type PhotoIdentifiersPage = {
edges: Array<PhotoIdentifier>,
page_info: {
has_next_page: boolean,
start_cursor?: string,
end_cursor?: string,
},
};
/**
* Shape of the return value of the `getPhotos` function.
*/
const getPhotosReturnChecker = deprecatedCreateStrictShapeTypeChecker({
edges: PropTypes.arrayOf(
/* $FlowFixMe(>=0.66.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.66 was deployed. To see the error delete this
* comment and run Flow. */
deprecatedCreateStrictShapeTypeChecker({
node: deprecatedCreateStrictShapeTypeChecker({
type: PropTypes.string.isRequired,
group_name: PropTypes.string.isRequired,
image: deprecatedCreateStrictShapeTypeChecker({
uri: PropTypes.string.isRequired,
height: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
isStored: PropTypes.bool,
playableDuration: PropTypes.number.isRequired,
}).isRequired,
timestamp: PropTypes.number.isRequired,
location: deprecatedCreateStrictShapeTypeChecker({
latitude: PropTypes.number,
longitude: PropTypes.number,
altitude: PropTypes.number,
heading: PropTypes.number,
speed: PropTypes.number,
}),
}).isRequired,
}),
).isRequired,
page_info: deprecatedCreateStrictShapeTypeChecker({
has_next_page: PropTypes.bool.isRequired,
start_cursor: PropTypes.string,
end_cursor: PropTypes.string,
}).isRequired,
});
/**
* `CameraRoll` provides access to the local camera roll or photo library.
*
* See https://facebook.github.io/react-native/docs/cameraroll.html
*/
class CameraRoll {
static GroupTypesOptions = GROUP_TYPES_OPTIONS;
static AssetTypeOptions = ASSET_TYPE_OPTIONS;
/**
* `CameraRoll.saveImageWithTag()` is deprecated. Use `CameraRoll.saveToCameraRoll()` instead.
*/
static saveImageWithTag(tag: string): Promise<string> {
console.warn(
'`CameraRoll.saveImageWithTag()` is deprecated. Use `CameraRoll.saveToCameraRoll()` instead.',
);
return this.saveToCameraRoll(tag, 'photo');
}
static deletePhotos(photos: Array<string>) {
return RCTCameraRollManager.deletePhotos(photos);
}
/**
* Saves the photo or video to the camera roll or photo library.
*
* See https://facebook.github.io/react-native/docs/cameraroll.html#savetocameraroll
*/
static saveToCameraRoll(
tag: string,
type?: 'photo' | 'video',
): Promise<string> {
invariant(
typeof tag === 'string',
'CameraRoll.saveToCameraRoll must be a valid string.',
);
invariant(
type === 'photo' || type === 'video' || type === undefined,
`The second argument to saveToCameraRoll must be 'photo' or 'video'. You passed ${type ||
'unknown'}`,
);
let mediaType = 'photo';
if (type) {
mediaType = type;
} else if (['mov', 'mp4'].indexOf(tag.split('.').slice(-1)[0]) >= 0) {
mediaType = 'video';
}
return RCTCameraRollManager.saveToCameraRoll(tag, mediaType);
}
/**
* Returns a Promise with photo identifier objects from the local camera
* roll of the device matching shape defined by `getPhotosReturnChecker`.
*
* See https://facebook.github.io/react-native/docs/cameraroll.html#getphotos
*/
static getPhotos(params: GetPhotosParams): Promise<PhotoIdentifiersPage> {
if (__DEV__) {
checkPropTypes(
{params: getPhotosParamChecker},
{params},
'params',
'CameraRoll.getPhotos',
);
}
if (arguments.length > 1) {
console.warn(
'CameraRoll.getPhotos(tag, success, error) is deprecated. Use the returned Promise instead',
);
let successCallback = arguments[1];
if (__DEV__) {
const callback = arguments[1];
successCallback = response => {
checkPropTypes(
{response: getPhotosReturnChecker},
{response},
'response',
'CameraRoll.getPhotos callback',
);
callback(response);
};
}
const errorCallback = arguments[2] || (() => {});
RCTCameraRollManager.getPhotos(params).then(
successCallback,
errorCallback,
);
}
// TODO: Add the __DEV__ check back in to verify the Promise result
return RCTCameraRollManager.getPhotos(params);
}
}
module.exports = CameraRoll;

Просмотреть файл

@ -1,302 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137620341B31C53500677FF0 /* RCTImagePickerManager.m */; };
143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */; };
8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m */; };
8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
58B5115B1A9E6B3D00147676 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
137620331B31C53500677FF0 /* RCTImagePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTImagePickerManager.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
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; lineEnding = 0; path = RCTCameraRollManager.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
143879341AAD238D00F088A5 /* RCTCameraRollManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCameraRollManager.m; sourceTree = "<group>"; };
58B5115D1A9E6B3D00147676 /* libRCTCameraRoll.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTCameraRoll.a; sourceTree = BUILT_PRODUCTS_DIR; };
8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTAssetsLibraryRequestHandler.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAssetsLibraryRequestHandler.m; sourceTree = "<group>"; };
8312EAEF1B85F071001867A2 /* RCTPhotoLibraryImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTPhotoLibraryImageLoader.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPhotoLibraryImageLoader.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
58B5115A1A9E6B3D00147676 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
58B511541A9E6B3D00147676 = {
isa = PBXGroup;
children = (
8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.h */,
8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m */,
143879331AAD238D00F088A5 /* RCTCameraRollManager.h */,
143879341AAD238D00F088A5 /* RCTCameraRollManager.m */,
137620331B31C53500677FF0 /* RCTImagePickerManager.h */,
137620341B31C53500677FF0 /* RCTImagePickerManager.m */,
8312EAEF1B85F071001867A2 /* RCTPhotoLibraryImageLoader.h */,
8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */,
58B5115E1A9E6B3D00147676 /* Products */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
usesTabs = 0;
};
58B5115E1A9E6B3D00147676 /* Products */ = {
isa = PBXGroup;
children = (
58B5115D1A9E6B3D00147676 /* libRCTCameraRoll.a */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
58B5115C1A9E6B3D00147676 /* RCTCameraRoll */ = {
isa = PBXNativeTarget;
buildConfigurationList = 58B511711A9E6B3D00147676 /* Build configuration list for PBXNativeTarget "RCTCameraRoll" */;
buildPhases = (
58B511591A9E6B3D00147676 /* Sources */,
58B5115A1A9E6B3D00147676 /* Frameworks */,
58B5115B1A9E6B3D00147676 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = RCTCameraRoll;
productName = RCTNetworkImage;
productReference = 58B5115D1A9E6B3D00147676 /* libRCTCameraRoll.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
58B511551A9E6B3D00147676 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0940;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
58B5115C1A9E6B3D00147676 = {
CreatedOnToolsVersion = 6.1.1;
};
};
};
buildConfigurationList = 58B511581A9E6B3D00147676 /* Build configuration list for PBXProject "RCTCameraRoll" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 58B511541A9E6B3D00147676;
productRefGroup = 58B5115E1A9E6B3D00147676 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
58B5115C1A9E6B3D00147676 /* RCTCameraRoll */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
58B511591A9E6B3D00147676 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m in Sources */,
8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */,
137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */,
143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
58B5116F1A9E6B3D00147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
WARNING_CFLAGS = (
"-Werror",
"-Wall",
"-Wno-deprecated-declarations",
);
};
name = Debug;
};
58B511701A9E6B3D00147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
VALIDATE_PRODUCT = YES;
WARNING_CFLAGS = (
"-Werror",
"-Wall",
"-Wno-deprecated-declarations",
);
};
name = Release;
};
58B511721A9E6B3D00147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_STATIC_ANALYZER_MODE = deep;
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RCTCameraRoll;
RUN_CLANG_STATIC_ANALYZER = YES;
};
name = Debug;
};
58B511731A9E6B3D00147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_STATIC_ANALYZER_MODE = deep;
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RCTCameraRoll;
RUN_CLANG_STATIC_ANALYZER = NO;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
58B511581A9E6B3D00147676 /* Build configuration list for PBXProject "RCTCameraRoll" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B5116F1A9E6B3D00147676 /* Debug */,
58B511701A9E6B3D00147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
58B511711A9E6B3D00147676 /* Build configuration list for PBXNativeTarget "RCTCameraRoll" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511721A9E6B3D00147676 /* Debug */,
58B511731A9E6B3D00147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 58B511551A9E6B3D00147676 /* Project object */;
}

Просмотреть файл

@ -1,36 +0,0 @@
# coding: utf-8
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require "json"
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))
version = package['version']
source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which were presumably in.
source[:commit] = `git rev-parse HEAD`.strip
else
source[:tag] = "v#{version}"
end
Pod::Spec.new do |s|
s.name = "React-RCTCameraRoll"
s.version = version
s.summary = "An API that provides access to the local camera roll or photo library."
s.homepage = "http://facebook.github.io/react-native/"
s.documentation_url = "https://facebook.github.io/react-native/docs/cameraroll"
s.license = package["license"]
s.author = "Facebook, Inc. and its affiliates"
s.platforms = { :ios => "9.0", :tvos => "9.2" }
s.source = source
s.source_files = "*.{h,m}"
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
s.header_dir = "React"
s.dependency "React-Core", version
s.dependency "React-RCTImage", version
end

Просмотреть файл

@ -1,14 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const CameraRoll = {};
export default CameraRoll;

Просмотреть файл

@ -202,15 +202,6 @@ module.exports = {
get BackHandler() {
return require('BackHandler');
},
get CameraRoll() {
warnOnce(
'cameraroll-moved',
'CameraRoll has been extracted from react-native core and will be removed in a future release. ' +
"It can now be installed and imported from '@react-native-community/cameraroll' instead of 'react-native'. " +
'See https://github.com/react-native-community/react-native-cameraroll',
);
return require('CameraRoll');
},
get Clipboard() {
return require('Clipboard');
},

Просмотреть файл

@ -7,13 +7,12 @@ target 'RNTester' do
# use_frameworks!
project 'RNTesterPods.xcodeproj'
# Enable TurboModule
use_react_native!(path: "..", turbo_modules_enabled: true)
pod 'React-turbomodule-samples', :path => '../ReactCommon/turbomodule/samples'
# Additional Pods which aren't included in the default Podfile
pod 'React-RCTCameraRoll', :path => '../Libraries/CameraRoll'
pod 'React-ART', :path => '../Libraries/ART'
pod 'React-RCTPushNotification', :path => '../Libraries/PushNotificationIOS'

Просмотреть файл

@ -67,9 +67,6 @@ PODS:
- React-Core (= 1000.0.0)
- React-RCTNetwork (= 1000.0.0)
- React-RCTWebSocket (= 1000.0.0)
- React-RCTCameraRoll (1000.0.0):
- React-Core (= 1000.0.0)
- React-RCTImage (= 1000.0.0)
- React-RCTImage (1000.0.0):
- React-Core (= 1000.0.0)
- React-RCTNetwork (= 1000.0.0)
@ -130,7 +127,6 @@ DEPENDENCIES:
- React-RCTActionSheet (from `../Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../Libraries/NativeAnimation`)
- React-RCTBlob (from `../Libraries/Blob`)
- React-RCTCameraRoll (from `../Libraries/CameraRoll`)
- React-RCTImage (from `../Libraries/Image`)
- React-RCTLinking (from `../Libraries/LinkingIOS`)
- React-RCTNetwork (from `../Libraries/Network`)
@ -178,8 +174,6 @@ EXTERNAL SOURCES:
:path: "../Libraries/NativeAnimation"
React-RCTBlob:
:path: "../Libraries/Blob"
React-RCTCameraRoll:
:path: "../Libraries/CameraRoll"
React-RCTImage:
:path: "../Libraries/Image"
React-RCTLinking:
@ -220,7 +214,6 @@ SPEC CHECKSUMS:
React-RCTActionSheet: 4ad4bfac1ba9ec020edf278362855448d607cafd
React-RCTAnimation: f050e9fbe85e5616f74cea7a2557bdfb6be73cee
React-RCTBlob: 9f907aab3417a43bbda84aef76f88ee528e877d4
React-RCTCameraRoll: 288b1007d8e540771b917f89d7d99118a3477ee1
React-RCTImage: 4234a754ebdb922416f5f77cff121c680fd3ccbe
React-RCTLinking: 3a52500942cc73999df19f541b7bda5887c3c43d
React-RCTNetwork: 2042d2648e1160770ac0e5068bb5b648c03296a5

Просмотреть файл

@ -16,7 +16,6 @@
1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341802B1AA91779003F314A /* libRCTNetwork.a */; };
134CB92A1C85A38800265FA6 /* RCTModuleInitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 134CB9291C85A38800265FA6 /* RCTModuleInitTests.m */; };
138D6A181B53CD440074A87E /* RCTShadowViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 138D6A161B53CD440074A87E /* RCTShadowViewTests.m */; };
138DEE241B9EDFB6007F4EA5 /* libRCTCameraRoll.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 138DEE091B9EDDDB007F4EA5 /* libRCTCameraRoll.a */; };
1393D0381B68CD1300E1B601 /* RCTModuleMethodTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1393D0371B68CD1300E1B601 /* RCTModuleMethodTests.mm */; };
139FDEDB1B0651FB00C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */; };
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
@ -161,13 +160,6 @@
remoteGlobalIDString = 58B511DB1A9E6C8500147676;
remoteInfo = RCTNetwork;
};
138DEE081B9EDDDB007F4EA5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 58B5115D1A9E6B3D00147676;
remoteInfo = RCTImage;
};
139FDED81B0651EA00C62182 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 139FDECA1B0651EA00C62182 /* RCTWebSocket.xcodeproj */;
@ -488,7 +480,6 @@
134180261AA91779003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
134CB9291C85A38800265FA6 /* RCTModuleInitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleInitTests.m; sourceTree = "<group>"; };
138D6A161B53CD440074A87E /* RCTShadowViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTShadowViewTests.m; sourceTree = "<group>"; };
138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTCameraRoll.xcodeproj; path = ../Libraries/CameraRoll/RCTCameraRoll.xcodeproj; sourceTree = "<group>"; };
1393D0371B68CD1300E1B601 /* RCTModuleMethodTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTModuleMethodTests.mm; sourceTree = "<group>"; };
139FDECA1B0651EA00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* RNTester.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RNTester.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -606,7 +597,6 @@
2D66FF8F1ECA406D00F0A767 /* libART.a in Frameworks */,
147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */,
13E501F11D07A84A005F35D8 /* libRCTAnimation.a in Frameworks */,
138DEE241B9EDFB6007F4EA5 /* libRCTCameraRoll.a in Frameworks */,
1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */,
13417FE91AA91432003F314A /* libRCTImage.a in Frameworks */,
3578590A1B28D2CF00341EDB /* libRCTLinking.a in Frameworks */,
@ -690,7 +680,6 @@
14AADEFF1AC3DB95002390C9 /* React.xcodeproj */,
14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */,
13E5019C1D07A502005F35D8 /* RCTAnimation.xcodeproj */,
138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */,
13417FE31AA91428003F314A /* RCTImage.xcodeproj */,
357858F81B28D2C400341EDB /* RCTLinking.xcodeproj */,
134180261AA91779003F314A /* RCTNetwork.xcodeproj */,
@ -740,14 +729,6 @@
name = Products;
sourceTree = "<group>";
};
138DEE031B9EDDDB007F4EA5 /* Products */ = {
isa = PBXGroup;
children = (
138DEE091B9EDDDB007F4EA5 /* libRCTCameraRoll.a */,
);
name = Products;
sourceTree = "<group>";
};
139FDECB1B0651EA00C62182 /* Products */ = {
isa = PBXGroup;
children = (
@ -1270,10 +1251,6 @@
ProductGroup = 5281CA4C1EEAC9A700AC40CD /* Products */;
ProjectRef = 5281CA4B1EEAC9A700AC40CD /* RCTBlob.xcodeproj */;
},
{
ProductGroup = 138DEE031B9EDDDB007F4EA5 /* Products */;
ProjectRef = 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */;
},
{
ProductGroup = 13417FE41AA91428003F314A /* Products */;
ProjectRef = 13417FE31AA91428003F314A /* RCTImage.xcodeproj */;
@ -1350,13 +1327,6 @@
remoteRef = 1341802A1AA91779003F314A /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
138DEE091B9EDDDB007F4EA5 /* libRCTCameraRoll.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTCameraRoll.a;
remoteRef = 138DEE081B9EDDDB007F4EA5 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
139FDED91B0651EA00C62182 /* libRCTWebSocket.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;

Просмотреть файл

@ -385,7 +385,6 @@
"\"${PODS_ROOT}/Headers/Public/React-RCTActionSheet\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTAnimation\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTBlob\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTCameraRoll\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTFabric\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTGeolocation\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTImage\"",
@ -434,7 +433,6 @@
"\"${PODS_ROOT}/Headers/Public/React-RCTActionSheet\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTAnimation\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTBlob\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTCameraRoll\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTFabric\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTGeolocation\"",
"\"${PODS_ROOT}/Headers/Public/React-RCTImage\"",

Просмотреть файл

@ -13,7 +13,28 @@
const React = require('react');
const {Image, StyleSheet, View, ScrollView} = require('react-native');
import type {PhotoIdentifier} from '../../Libraries/CameraRoll/CameraRoll';
type PhotoIdentifier = {
node: {
type: string,
group_name: string,
image: {
filename: string,
uri: string,
height: number,
width: number,
isStored?: boolean,
playableDuration: number,
},
timestamp: number,
location?: {
latitude?: number,
longitude?: number,
altitude?: number,
heading?: number,
speed?: number,
},
},
};
type Props = $ReadOnly<{|
asset: PhotoIdentifier,

Просмотреть файл

@ -1,162 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const React = require('react');
const {
CameraRoll,
Image,
Slider,
StyleSheet,
Switch,
Text,
View,
TouchableOpacity,
} = require('react-native');
const invariant = require('invariant');
const CameraRollView = require('./CameraRollView');
const AssetScaledImageExampleView = require('./AssetScaledImageExample');
import type {
PhotoIdentifier,
GroupTypes,
} from '../../Libraries/CameraRoll/CameraRoll';
type Props = $ReadOnly<{|
navigator?: ?Array<
$ReadOnly<{|
title: string,
component: Class<React.Component<any, any>>,
backButtonTitle: string,
passProps: $ReadOnly<{|asset: PhotoIdentifier|}>,
|}>,
>,
|}>;
type State = {|
groupTypes: GroupTypes,
sliderValue: number,
bigImages: boolean,
|};
class CameraRollExample extends React.Component<Props, State> {
state = {
groupTypes: 'SavedPhotos',
sliderValue: 1,
bigImages: true,
};
_cameraRollView: ?React.ElementRef<typeof CameraRollView>;
render() {
return (
<View>
<Switch
onValueChange={this._onSwitchChange}
value={this.state.bigImages}
/>
<Text>{(this.state.bigImages ? 'Big' : 'Small') + ' Images'}</Text>
<Slider
value={this.state.sliderValue}
onValueChange={this._onSliderChange}
/>
<Text>{'Group Type: ' + this.state.groupTypes}</Text>
<CameraRollView
ref={ref => {
this._cameraRollView = ref;
}}
batchSize={20}
groupTypes={this.state.groupTypes}
renderImage={this._renderImage}
bigImages={this.state.bigImages}
/>
</View>
);
}
loadAsset(asset) {
if (this.props.navigator) {
this.props.navigator.push({
title: 'Camera Roll Image',
component: AssetScaledImageExampleView,
backButtonTitle: 'Back',
passProps: {asset: asset},
});
}
}
_renderImage = (asset: PhotoIdentifier) => {
const imageSize = this.state.bigImages ? 150 : 75;
const imageStyle = [styles.image, {width: imageSize, height: imageSize}];
const {location} = asset.node;
const locationStr = location
? JSON.stringify(location)
: 'Unknown location';
return (
<TouchableOpacity
key={asset.node.image.uri}
onPress={this.loadAsset.bind(this, asset)}>
<View style={styles.row}>
<Image source={asset.node.image} style={imageStyle} />
<View style={styles.info}>
<Text style={styles.url}>{asset.node.image.uri}</Text>
<Text>{locationStr}</Text>
<Text>{asset.node.group_name}</Text>
<Text>{new Date(asset.node.timestamp).toString()}</Text>
</View>
</View>
</TouchableOpacity>
);
};
_onSliderChange = value => {
const options = Object.keys(CameraRoll.GroupTypesOptions);
const index = Math.floor(value * options.length * 0.99);
const groupTypes = options[index];
if (groupTypes !== this.state.groupTypes) {
this.setState({groupTypes: groupTypes});
}
};
_onSwitchChange = value => {
invariant(this._cameraRollView, 'ref should be set');
this.setState({bigImages: value});
};
}
const styles = StyleSheet.create({
row: {
flexDirection: 'row',
flex: 1,
},
url: {
fontSize: 9,
marginBottom: 14,
},
image: {
margin: 4,
},
info: {
flex: 1,
},
});
exports.title = 'Camera Roll';
exports.description =
"Example component that uses CameraRoll to list user's photos";
exports.examples = [
{
title: 'Photos',
render(): React.Node {
return <CameraRollExample />;
},
},
];

Просмотреть файл

@ -1,264 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
const React = require('react');
const {
ActivityIndicator,
Alert,
CameraRoll,
Image,
FlatList,
PermissionsAndroid,
Platform,
StyleSheet,
View,
} = require('react-native');
const groupByEveryN = require('../../Libraries/Utilities/groupByEveryN');
const logError = require('../../Libraries/Utilities/logError');
import type {
PhotoIdentifier,
PhotoIdentifiersPage,
GetPhotosParams,
} from '../../Libraries/CameraRoll/CameraRoll';
type Props = $ReadOnly<{|
/**
* The group where the photos will be fetched from. Possible
* values are 'Album', 'All', 'Event', 'Faces', 'Library', 'PhotoStream'
* and SavedPhotos.
*/
groupTypes:
| 'Album'
| 'All'
| 'Event'
| 'Faces'
| 'Library'
| 'PhotoStream'
| 'SavedPhotos',
/**
* Number of images that will be fetched in one page.
*/
batchSize: number,
/**
* A function that takes a single image as a parameter and renders it.
*/
renderImage: PhotoIdentifier => React.Node,
/**
* imagesPerRow: Number of images to be shown in each row.
*/
imagesPerRow: number,
/**
* A boolean that indicates if we should render large or small images.
*/
bigImages?: boolean,
/**
* The asset type, one of 'Photos', 'Videos' or 'All'
*/
assetType: 'Photos' | 'Videos' | 'All',
|}>;
type State = {|
assets: Array<PhotoIdentifier>,
data: Array<Array<?PhotoIdentifier>>,
seen: Set<string>,
lastCursor: ?string,
noMore: boolean,
loadingMore: boolean,
|};
type Row = {
item: Array<?PhotoIdentifier>,
};
class CameraRollView extends React.Component<Props, State> {
static defaultProps = {
groupTypes: 'SavedPhotos',
batchSize: 5,
imagesPerRow: 1,
assetType: 'Photos',
renderImage: function(asset: PhotoIdentifier) {
const imageSize = 150;
const imageStyle = [styles.image, {width: imageSize, height: imageSize}];
return <Image source={asset.node.image} style={imageStyle} />;
},
};
state = this.getInitialState();
getInitialState() {
return {
assets: [],
data: [],
seen: new Set(),
lastCursor: null,
noMore: false,
loadingMore: false,
};
}
componentDidMount() {
this.fetch();
}
UNSAFE_componentWillReceiveProps(nextProps: Props) {
if (this.props.groupTypes !== nextProps.groupTypes) {
this.fetch(true);
}
}
async _fetch(clear?: boolean) {
if (clear) {
this.setState(this.getInitialState(), this.fetch);
return;
}
if (Platform.OS === 'android') {
const result = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
{
title: 'Permission Explanation',
message: 'RNTester would like to access your pictures.',
},
);
if (result !== 'granted') {
Alert.alert('Access to pictures was denied.');
return;
}
}
const fetchParams: GetPhotosParams = {
first: this.props.batchSize,
groupTypes: this.props.groupTypes,
assetType: this.props.assetType,
};
if (Platform.OS === 'android') {
// not supported in android
delete fetchParams.groupTypes;
}
if (this.state.lastCursor) {
fetchParams.after = this.state.lastCursor;
}
try {
const data = await CameraRoll.getPhotos(fetchParams);
this._appendAssets(data);
} catch (e) {
logError(e);
}
}
/**
* Fetches more images from the camera roll. If clear is set to true, it will
* set the component to its initial state and re-fetch the images.
*/
fetch = (clear?: boolean) => {
if (!this.state.loadingMore) {
this.setState({loadingMore: true}, () => {
this._fetch(clear);
});
}
};
render() {
return (
<FlatList
keyExtractor={(_, idx) => String(idx)}
renderItem={this._renderItem}
ListFooterComponent={this._renderFooterSpinner}
onEndReached={this._onEndReached}
onEndReachedThreshold={0.2}
style={styles.container}
data={this.state.data || []}
extraData={this.props.bigImages + this.state.noMore}
/>
);
}
_renderFooterSpinner = () => {
if (!this.state.noMore) {
return <ActivityIndicator />;
}
return null;
};
_renderItem = (row: Row) => {
return (
<View style={styles.row}>
{row.item.map(image => (image ? this.props.renderImage(image) : null))}
</View>
);
};
_appendAssets(data: PhotoIdentifiersPage) {
const assets = data.edges;
const newState: $Shape<State> = {loadingMore: false};
if (!data.page_info.has_next_page) {
newState.noMore = true;
}
if (assets.length > 0) {
newState.lastCursor = data.page_info.end_cursor;
newState.seen = new Set(this.state.seen);
// Unique assets efficiently
// Checks new pages against seen objects
const uniqAssets = [];
for (let index = 0; index < assets.length; index++) {
const asset = assets[index];
let value = asset.node.image.uri;
if (newState.seen.has(value)) {
continue;
}
newState.seen.add(value);
uniqAssets.push(asset);
}
newState.assets = this.state.assets.concat(uniqAssets);
newState.data = groupByEveryN<PhotoIdentifier>(
newState.assets,
this.props.imagesPerRow,
);
}
this.setState(newState);
}
_onEndReached = () => {
if (!this.state.noMore) {
this.fetch();
}
};
}
const styles = StyleSheet.create({
row: {
flexDirection: 'row',
flex: 1,
},
image: {
margin: 4,
},
container: {
flex: 1,
},
});
module.exports = CameraRollView;

Просмотреть файл

@ -1,315 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
const React = require('react');
const {
CameraRoll,
Image,
ImageEditor,
Platform,
ScrollView,
StyleSheet,
Text,
TouchableHighlight,
View,
} = require('react-native');
const PAGE_SIZE = 20;
type ImageOffset = {|
x: number,
y: number,
|};
type ImageSize = {|
width: number,
height: number,
|};
type ImageCropData = {|
offset: ImageOffset,
size: ImageSize,
displaySize?: ?ImageSize,
resizeMode?: ?any,
|};
class SquareImageCropper extends React.Component<
$FlowFixMeProps,
$FlowFixMeState,
> {
state: any;
_isMounted: boolean;
_transformData: ImageCropData;
/* $FlowFixMe(>=0.85.0 site=react_native_fb) This comment suppresses an error
* found when Flow v0.85 was deployed. To see the error, delete this comment
* and run Flow. */
constructor(props) {
super(props);
this._isMounted = true;
this.state = {
randomPhoto: null,
measuredSize: null,
croppedImageURI: null,
cropError: null,
};
this._fetchRandomPhoto();
}
async _fetchRandomPhoto() {
try {
const data = await CameraRoll.getPhotos({first: PAGE_SIZE});
if (!this._isMounted) {
return;
}
const edges = data.edges;
const edge = edges[Math.floor(Math.random() * edges.length)];
const randomPhoto = edge && edge.node && edge.node.image;
if (randomPhoto) {
this.setState({randomPhoto});
}
} catch (error) {
console.warn("Can't get a photo from camera roll", error);
}
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
if (!this.state.measuredSize) {
return (
<View
style={styles.container}
onLayout={event => {
const measuredWidth = event.nativeEvent.layout.width;
if (!measuredWidth) {
return;
}
this.setState({
measuredSize: {width: measuredWidth, height: measuredWidth},
});
}}
/>
);
}
if (!this.state.croppedImageURI) {
return this._renderImageCropper();
}
return this._renderCroppedImage();
}
_renderImageCropper() {
if (!this.state.randomPhoto) {
return <View style={styles.container} />;
}
let error = null;
if (this.state.cropError) {
error = <Text>{this.state.cropError.message}</Text>;
}
return (
<View style={styles.container}>
<Text>Drag the image within the square to crop:</Text>
<ImageCropper
image={this.state.randomPhoto}
size={this.state.measuredSize}
style={[styles.imageCropper, this.state.measuredSize]}
onTransformDataChange={data => (this._transformData = data)}
/>
<TouchableHighlight
style={styles.cropButtonTouchable}
onPress={this._crop.bind(this)}>
<View style={styles.cropButton}>
<Text style={styles.cropButtonLabel}>Crop</Text>
</View>
</TouchableHighlight>
{error}
</View>
);
}
_renderCroppedImage() {
return (
<View style={styles.container}>
<Text>Here is the cropped image:</Text>
<Image
source={{uri: this.state.croppedImageURI}}
style={[styles.imageCropper, this.state.measuredSize]}
/>
<TouchableHighlight
style={styles.cropButtonTouchable}
onPress={this._reset.bind(this)}>
<View style={styles.cropButton}>
<Text style={styles.cropButtonLabel}>Try again</Text>
</View>
</TouchableHighlight>
</View>
);
}
_crop() {
ImageEditor.cropImage(
this.state.randomPhoto.uri,
this._transformData,
croppedImageURI => this.setState({croppedImageURI}),
cropError => this.setState({cropError}),
);
}
_reset() {
this.setState({
randomPhoto: null,
croppedImageURI: null,
cropError: null,
});
this._fetchRandomPhoto();
}
}
class ImageCropper extends React.Component<$FlowFixMeProps, $FlowFixMeState> {
_contentOffset: ImageOffset;
_maximumZoomScale: number;
_minimumZoomScale: number;
_scaledImageSize: ImageSize;
_horizontal: boolean;
UNSAFE_componentWillMount() {
// Scale an image to the minimum size that is large enough to completely
// fill the crop box.
const widthRatio = this.props.image.width / this.props.size.width;
const heightRatio = this.props.image.height / this.props.size.height;
this._horizontal = widthRatio > heightRatio;
if (this._horizontal) {
this._scaledImageSize = {
width: this.props.image.width / heightRatio,
height: this.props.size.height,
};
} else {
this._scaledImageSize = {
width: this.props.size.width,
height: this.props.image.height / widthRatio,
};
if (Platform.OS === 'android') {
// hack to work around Android ScrollView a) not supporting zoom, and
// b) not supporting vertical scrolling when nested inside another
// vertical ScrollView (which it is, when displayed inside UIExplorer)
this._scaledImageSize.width *= 2;
this._scaledImageSize.height *= 2;
this._horizontal = true;
}
}
this._contentOffset = {
x: (this._scaledImageSize.width - this.props.size.width) / 2,
y: (this._scaledImageSize.height - this.props.size.height) / 2,
};
this._maximumZoomScale = Math.min(
this.props.image.width / this._scaledImageSize.width,
this.props.image.height / this._scaledImageSize.height,
);
this._minimumZoomScale = Math.max(
this.props.size.width / this._scaledImageSize.width,
this.props.size.height / this._scaledImageSize.height,
);
this._updateTransformData(
this._contentOffset,
this._scaledImageSize,
this.props.size,
);
}
_onScroll(event) {
this._updateTransformData(
event.nativeEvent.contentOffset,
event.nativeEvent.contentSize,
event.nativeEvent.layoutMeasurement,
);
}
_updateTransformData(offset, scaledImageSize, croppedImageSize) {
const offsetRatioX = offset.x / scaledImageSize.width;
const offsetRatioY = offset.y / scaledImageSize.height;
const sizeRatioX = croppedImageSize.width / scaledImageSize.width;
const sizeRatioY = croppedImageSize.height / scaledImageSize.height;
const cropData: ImageCropData = {
offset: {
x: this.props.image.width * offsetRatioX,
y: this.props.image.height * offsetRatioY,
},
size: {
width: this.props.image.width * sizeRatioX,
height: this.props.image.height * sizeRatioY,
},
};
this.props.onTransformDataChange &&
this.props.onTransformDataChange(cropData);
}
render() {
return (
<ScrollView
alwaysBounceVertical={true}
automaticallyAdjustContentInsets={false}
contentOffset={this._contentOffset}
decelerationRate="fast"
horizontal={this._horizontal}
maximumZoomScale={this._maximumZoomScale}
minimumZoomScale={this._minimumZoomScale}
onMomentumScrollEnd={this._onScroll.bind(this)}
onScrollEndDrag={this._onScroll.bind(this)}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
style={this.props.style}
scrollEventThrottle={16}>
<Image source={this.props.image} style={this._scaledImageSize} />
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignSelf: 'stretch',
},
imageCropper: {
alignSelf: 'center',
marginTop: 12,
},
cropButtonTouchable: {
alignSelf: 'center',
marginTop: 12,
},
cropButton: {
padding: 12,
backgroundColor: 'blue',
borderRadius: 4,
},
cropButtonLabel: {
color: 'white',
fontSize: 16,
fontWeight: '500',
},
});
exports.framework = 'React';
exports.title = 'ImageEditor';
exports.description = 'Cropping and scaling with ImageEditor';
exports.examples = [
{
title: 'Image Cropping',
render() {
return <SquareImageCropper />;
},
},
];

Просмотреть файл

@ -138,10 +138,6 @@ const APIExamples: Array<RNTesterExample> = [
key: 'BorderExample',
module: require('./BorderExample'),
},
{
key: 'CameraRollExample',
module: require('./CameraRollExample'),
},
{
key: 'ClipboardExample',
module: require('./ClipboardExample'),
@ -158,10 +154,6 @@ const APIExamples: Array<RNTesterExample> = [
key: 'Dimensions',
module: require('./DimensionsExample'),
},
{
key: 'ImageEditingExample',
module: require('./ImageEditingExample'),
},
{
key: 'LayoutEventsExample',
module: require('./LayoutEventsExample'),

Просмотреть файл

@ -216,11 +216,6 @@ const APIExamples: Array<RNTesterExample> = [
module: require('./BoxShadowExample'),
supportsTVOS: true,
},
{
key: 'CameraRollExample',
module: require('./CameraRollExample'),
supportsTVOS: false,
},
{
key: 'ClipboardExample',
module: require('./ClipboardExample'),
@ -236,11 +231,6 @@ const APIExamples: Array<RNTesterExample> = [
module: require('./DimensionsExample'),
supportsTVOS: true,
},
{
key: 'ImageEditingExample',
module: require('./ImageEditingExample'),
supportsTVOS: false,
},
{
key: 'LayoutAnimationExample',
module: require('./LayoutAnimationExample'),

Просмотреть файл

@ -14,7 +14,6 @@ const React = require('react');
const XHRExampleDownload = require('./XHRExampleDownload');
const XHRExampleBinaryUpload = require('./XHRExampleBinaryUpload');
const XHRExampleFormData = require('./XHRExampleFormData');
const XHRExampleHeaders = require('./XHRExampleHeaders');
const XHRExampleFetch = require('./XHRExampleFetch');
const XHRExampleOnTimeOut = require('./XHRExampleOnTimeOut');
@ -38,12 +37,6 @@ exports.examples = [
return <XHRExampleBinaryUpload />;
},
},
{
title: 'multipart/form-data Upload',
render() {
return <XHRExampleFormData />;
},
},
{
title: 'Fetch Test',
render() {

Просмотреть файл

@ -1,242 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
const React = require('react');
const {
CameraRoll,
Image,
ImageEditor,
Platform,
StyleSheet,
Text,
TextInput,
TouchableHighlight,
View,
} = require('react-native');
const XHRExampleBinaryUpload = require('./XHRExampleBinaryUpload');
const PAGE_SIZE = 20;
class XHRExampleFormData extends React.Component<Object, Object> {
state: Object = {
isUploading: false,
uploadProgress: null,
randomPhoto: null,
textParams: [],
};
_isMounted: boolean = true;
constructor(props: Object) {
super(props);
this._fetchRandomPhoto();
}
componentWillUnmount() {
this._isMounted = false;
}
_fetchRandomPhoto = () => {
CameraRoll.getPhotos({
first: PAGE_SIZE,
groupTypes: Platform.OS === 'ios' ? 'All' : undefined,
assetType: 'All',
}).then(
data => {
if (!this._isMounted) {
return;
}
const edges = data.edges;
const edge = edges[Math.floor(Math.random() * edges.length)];
const randomPhoto = edge && edge.node && edge.node.image;
if (randomPhoto) {
let {width, height} = randomPhoto;
width *= 0.25;
height *= 0.25;
ImageEditor.cropImage(
randomPhoto.uri,
{offset: {x: 0, y: 0}, size: {width, height}},
uri => this.setState({randomPhoto: {uri}}),
error => undefined,
);
}
},
error => undefined,
);
};
_addTextParam = () => {
const textParams = this.state.textParams;
textParams.push({name: '', value: ''});
this.setState({textParams});
};
_onTextParamNameChange(index, text) {
const textParams = this.state.textParams;
textParams[index].name = text;
this.setState({textParams});
}
_onTextParamValueChange(index, text) {
const textParams = this.state.textParams;
textParams[index].value = text;
this.setState({textParams});
}
_upload = () => {
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://posttestserver.com/post.php');
xhr.onload = () => {
this.setState({isUploading: false});
XHRExampleBinaryUpload.handlePostTestServerUpload(xhr);
};
const formdata = new FormData();
if (this.state.randomPhoto) {
formdata.append('image', {
...this.state.randomPhoto,
type: 'image/jpg',
name: 'image.jpg',
});
}
this.state.textParams.forEach(param =>
formdata.append(param.name, param.value),
);
xhr.upload.onprogress = event => {
if (event.lengthComputable) {
this.setState({uploadProgress: event.loaded / event.total});
}
};
xhr.send(formdata);
this.setState({isUploading: true});
};
render() {
let image = null;
if (this.state.randomPhoto) {
image = (
<Image source={this.state.randomPhoto} style={styles.randomPhoto} />
);
}
const textItems = this.state.textParams.map((item, index) => (
<View style={styles.paramRow}>
<TextInput
autoCapitalize="none"
autoCorrect={false}
onChangeText={this._onTextParamNameChange.bind(this, index)}
placeholder="name..."
style={styles.textInput}
/>
<Text style={styles.equalSign}>=</Text>
<TextInput
autoCapitalize="none"
autoCorrect={false}
onChangeText={this._onTextParamValueChange.bind(this, index)}
placeholder="value..."
style={styles.textInput}
/>
</View>
));
let uploadButtonLabel = this.state.isUploading ? 'Uploading...' : 'Upload';
const uploadProgress = this.state.uploadProgress;
if (uploadProgress !== null) {
uploadButtonLabel += ' ' + Math.round(uploadProgress * 100) + '%';
}
let uploadButton = (
<View style={styles.uploadButtonBox}>
<Text style={styles.uploadButtonLabel}>{uploadButtonLabel}</Text>
</View>
);
if (!this.state.isUploading) {
uploadButton = (
<TouchableHighlight onPress={this._upload}>
{uploadButton}
</TouchableHighlight>
);
}
return (
<View>
<View style={styles.paramRow}>
<Text style={styles.photoLabel}>
Random photo from your library (
<Text style={styles.textButton} onPress={this._fetchRandomPhoto}>
update
</Text>
)
</Text>
{image}
</View>
{textItems}
<View>
<Text
style={[styles.textButton, styles.addTextParamButton]}
onPress={this._addTextParam}>
Add a text param
</Text>
</View>
<View style={styles.uploadButton}>{uploadButton}</View>
</View>
);
}
}
const styles = StyleSheet.create({
paramRow: {
flexDirection: 'row',
paddingVertical: 8,
alignItems: 'center',
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: 'grey',
},
photoLabel: {
flex: 1,
},
randomPhoto: {
width: 50,
height: 50,
},
textButton: {
color: 'blue',
},
addTextParamButton: {
marginTop: 8,
},
textInput: {
flex: 1,
borderRadius: 3,
borderColor: 'grey',
borderWidth: 1,
height: Platform.OS === 'android' ? 50 : 30,
paddingLeft: 8,
},
equalSign: {
paddingHorizontal: 4,
},
uploadButton: {
marginTop: 16,
},
uploadButtonBox: {
flex: 1,
paddingVertical: 12,
alignItems: 'center',
backgroundColor: 'blue',
borderRadius: 4,
},
uploadButtonLabel: {
color: 'white',
fontSize: 16,
fontWeight: '500',
},
});
module.exports = XHRExampleFormData;