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:
Родитель
099be9b356
Коммит
3f04cfecda
|
@ -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 we’re 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;
|
Загрузка…
Ссылка в новой задаче