Updates from Tue Mar 10
- [ReactNative] Make tests run on TravisCI | Alex Kotliarskyi - [Relay] Update Relay + ES6 class containers | Christoph Pojer - [React Native] Add RCTAdSupport.xcodeproj | Alexsander Akers - [ReactNative][Android] Fix after a new React version was downstreamed | Philipp von Weitershausen - [React Native] Add preliminary animation API | Alex Akers - [ReactKit] Create test for OSS ReactKit | Alex Kotliarskyi - [React Native][Device ID][wip] implement most basic js access | Alex Akers - [ReactNative] OSS Picker | Spencer Ahrens - [ReactNative] Fix typo in RCTUIManager | Tadeu Zagallo - [ReactNative] Fix GeoLocation files letter case | Tadeu Zagallo - Unified the method signature for addUIBlock: to further simplify porting ViewManagers | Nick Lockwood - [ReactNative] Oss GeoMap | Tadeu Zagallo - [ReactNative] OSS CameraRoll | Tadeu Zagallo - [ReactNative] allowLossyConversion on NSString->NSData conversion | Andrew Rasmussen - [React Native][RFC] Print __DEV__ value on app start | Alex Kotliarskyi
This commit is contained in:
Родитель
83581cfe6b
Коммит
fab5ec617d
10
.travis.yml
10
.travis.yml
|
@ -1,3 +1,7 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
language: objective-c
|
||||
xcode_project: Examples/UIExplorer/UIExplorer.xcodeproj
|
||||
xcode_scheme: UIExplorer
|
||||
xcode_sdk: iphonesimulator8.1
|
||||
install:
|
||||
- npm install
|
||||
- npm test
|
||||
|
|
|
@ -0,0 +1,357 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
|
||||
8323482C1A77B59500B55238 /* libReactKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832348291A77B50100B55238 /* libReactKit.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 58B5119B1A9E6C1200147676;
|
||||
remoteInfo = RCTText;
|
||||
};
|
||||
832348281A77B50100B55238 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 834D32361A76971A00F38302 /* ReactKit.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
|
||||
remoteInfo = ReactKit;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
13B07F961A680F5B00A75B9A /* 2048.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 2048.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = "<group>"; };
|
||||
834D32361A76971A00F38302 /* ReactKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactKit.xcodeproj; path = ../../ReactKit/ReactKit.xcodeproj; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8323482C1A77B59500B55238 /* libReactKit.a in Frameworks */,
|
||||
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
13B07FAE1A68108700A75B9A /* 2048 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */,
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */,
|
||||
13B07FB61A68108700A75B9A /* Info.plist */,
|
||||
13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
|
||||
13B07FB71A68108700A75B9A /* main.m */,
|
||||
);
|
||||
name = 2048;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
834D32361A76971A00F38302 /* ReactKit.xcodeproj */,
|
||||
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
832341B11AAA6A8300B99B32 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
832341B51AAA6A8300B99B32 /* libRCTText.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
832348241A77B50100B55238 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
832348291A77B50100B55238 /* libReactKit.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07FAE1A68108700A75B9A /* 2048 */,
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */,
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83CBBA001A601CBA00E9B192 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07F961A680F5B00A75B9A /* 2048.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
13B07F861A680F5B00A75B9A /* 2048 */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "2048" */;
|
||||
buildPhases = (
|
||||
13B07F871A680F5B00A75B9A /* Sources */,
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = 2048;
|
||||
productName = "Hello World";
|
||||
productReference = 13B07F961A680F5B00A75B9A /* 2048.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
83CBB9F71A601CBA00E9B192 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0610;
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
};
|
||||
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "2048" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 83CBB9F61A601CBA00E9B192;
|
||||
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = 832341B11AAA6A8300B99B32 /* Products */;
|
||||
ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 832348241A77B50100B55238 /* Products */;
|
||||
ProjectRef = 834D32361A76971A00F38302 /* ReactKit.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
13B07F861A680F5B00A75B9A /* 2048 */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
832341B51AAA6A8300B99B32 /* libRCTText.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRCTText.a;
|
||||
remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
832348291A77B50100B55238 /* libReactKit.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libReactKit.a;
|
||||
remoteRef = 832348281A77B50100B55238 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
13B07F871A680F5B00A75B9A /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
13B07FB21A68108700A75B9A /* Base */,
|
||||
);
|
||||
name = LaunchScreen.xib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
13B07F941A680F5B00A75B9A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = 2048;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
13B07F951A680F5B00A75B9A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = 2048;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
83CBBA201A601CBA00E9B192 /* 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_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
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_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../../ReactKit/**",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
83CBBA211A601CBA00E9B192 /* 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_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../../ReactKit/**",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "2048" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
13B07F941A680F5B00A75B9A /* Debug */,
|
||||
13B07F951A680F5B00A75B9A /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "2048" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
83CBBA201A601CBA00E9B192 /* Debug */,
|
||||
83CBBA211A601CBA00E9B192 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (nonatomic, strong) UIWindow *window;
|
||||
|
||||
@end
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "RCTRootView.h"
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
NSURL *jsCodeLocation;
|
||||
RCTRootView *rootView = [[RCTRootView alloc] init];
|
||||
|
||||
// Loading JavaScript code - uncomment the one you want.
|
||||
|
||||
// OPTION 1
|
||||
// Load from development server. Start the server from the repository root:
|
||||
//
|
||||
// $ npm start
|
||||
//
|
||||
// To run on device, change `localhost` to the IP address of your computer, and make sure your computer and
|
||||
// iOS device are on the same Wi-Fi network.
|
||||
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/2048/Game2048.includeRequire.runModule.bundle?dev=true"];
|
||||
|
||||
// OPTION 2
|
||||
// Load from pre-bundled file on disk. To re-generate the static bundle, run
|
||||
//
|
||||
// $ curl http://localhost:8081/Examples/2048/Game2048.includeRequire.runModule.bundle -o main.jsbundle
|
||||
//
|
||||
// and uncomment the next following line
|
||||
// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
|
||||
rootView.scriptURL = jsCodeLocation;
|
||||
rootView.moduleName = @"Game2048";
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
UIViewController *rootViewController = [[UIViewController alloc] init];
|
||||
rootViewController.view = rootView;
|
||||
self.window.rootViewController = rootViewController;
|
||||
[self.window makeKeyAndVisible];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6254" systemVersion="14C109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Facebook. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2048" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<rect key="frame" x="20" y="140" width="441" height="43"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
|
||||
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
|
||||
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
|
||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="548" y="455"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
|
@ -0,0 +1,298 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule Game2048
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
Animation,
|
||||
AppRegistry,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var GameBoard = require('./GameBoard');
|
||||
var TouchableBounce = require('TouchableBounce');
|
||||
|
||||
var BOARD_PADDING = 3;
|
||||
var CELL_MARGIN = 4;
|
||||
var CELL_SIZE = 60;
|
||||
|
||||
var Cell = React.createClass({
|
||||
render: function() {
|
||||
return <View style={styles.cell} />;
|
||||
}
|
||||
});
|
||||
|
||||
var Board = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.board}>
|
||||
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
|
||||
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
|
||||
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
|
||||
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
|
||||
{this.props.children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Tile = React.createClass({
|
||||
mixins: [Animation.Mixin],
|
||||
|
||||
calculateOffset() {
|
||||
var tile = this.props.tile;
|
||||
|
||||
var pos = (i) => {
|
||||
return BOARD_PADDING + (i * (CELL_SIZE + CELL_MARGIN * 2) + CELL_MARGIN);
|
||||
};
|
||||
|
||||
var animationPosition = (i) => {
|
||||
return pos(i) + (CELL_SIZE / 2);
|
||||
};
|
||||
|
||||
var offset = {
|
||||
top: pos(tile.toRow()),
|
||||
left: pos(tile.toColumn()),
|
||||
};
|
||||
|
||||
if (tile.isNew()) {
|
||||
offset.opacity = 0;
|
||||
} else {
|
||||
var point = [
|
||||
animationPosition(tile.toColumn()),
|
||||
animationPosition(tile.toRow()),
|
||||
];
|
||||
this.startAnimation('this', 100, 0, 'easeInOutQuad', {position: point});
|
||||
}
|
||||
|
||||
return offset;
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
setTimeout(() => {
|
||||
this.startAnimation('this', 300, 0, 'easeInOutQuad', {scaleXY: [1, 1]});
|
||||
this.startAnimation('this', 100, 0, 'easeInOutQuad', {opacity: 1});
|
||||
}, 0);
|
||||
},
|
||||
|
||||
render() {
|
||||
var tile = this.props.tile;
|
||||
|
||||
var tileStyles = [
|
||||
styles.tile,
|
||||
styles['tile' + tile.value],
|
||||
this.calculateOffset()
|
||||
];
|
||||
|
||||
var textStyles = [
|
||||
styles.value,
|
||||
tile.value > 4 && styles.whiteText,
|
||||
tile.value > 100 && styles.threeDigits,
|
||||
tile.value > 1000 && styles.fourDigits,
|
||||
];
|
||||
|
||||
return (
|
||||
<View ref="this" style={tileStyles}>
|
||||
<Text style={textStyles}>{tile.value}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var GameEndOverlay = React.createClass({
|
||||
render() {
|
||||
var board = this.props.board;
|
||||
|
||||
if (!board.hasWon() && !board.hasLost()) {
|
||||
return <View/>;
|
||||
}
|
||||
|
||||
var message = board.hasWon() ?
|
||||
'Good Job!' : 'Game Over';
|
||||
|
||||
return (
|
||||
<View style={styles.overlay}>
|
||||
<Text style={styles.overlayMessage}>{message}</Text>
|
||||
<TouchableBounce onPress={this.props.onRestart}>
|
||||
<View style={styles.tryAgain}>
|
||||
<Text style={styles.tryAgainText}>Try Again?</Text>
|
||||
</View>
|
||||
</TouchableBounce>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Game2048 = React.createClass({
|
||||
getInitialState() {
|
||||
return { board: new GameBoard() };
|
||||
},
|
||||
|
||||
restartGame() {
|
||||
this.setState(this.getInitialState());
|
||||
},
|
||||
|
||||
handleTouchStart(event) {
|
||||
if (this.state.board.hasWon()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.startX = event.nativeEvent.pageX;
|
||||
this.startY = event.nativeEvent.pageY;
|
||||
},
|
||||
|
||||
handleTouchEnd(event) {
|
||||
if (this.state.board.hasWon()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var deltaX = event.nativeEvent.pageX - this.startX;
|
||||
var deltaY = event.nativeEvent.pageY - this.startY;
|
||||
|
||||
var direction = -1;
|
||||
if (Math.abs(deltaX) > 3 * Math.abs(deltaY) && Math.abs(deltaX) > 30) {
|
||||
direction = deltaX > 0 ? 2 : 0;
|
||||
} else if (Math.abs(deltaY) > 3 * Math.abs(deltaX) && Math.abs(deltaY) > 30) {
|
||||
direction = deltaY > 0 ? 3 : 1;
|
||||
}
|
||||
|
||||
if (direction !== -1) {
|
||||
this.setState({board: this.state.board.move(direction)});
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
var tiles = this.state.board.tiles
|
||||
.filter((tile) => tile.value)
|
||||
.map((tile) => <Tile ref={tile.id} key={tile.id} tile={tile} />);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={styles.container}
|
||||
onTouchStart={this.handleTouchStart}
|
||||
onTouchEnd={this.handleTouchEnd}>
|
||||
<Board>
|
||||
{tiles}
|
||||
</Board>
|
||||
<GameEndOverlay board={this.state.board} onRestart={this.restartGame} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
board: {
|
||||
padding: BOARD_PADDING,
|
||||
backgroundColor: '#bbaaaa',
|
||||
borderRadius: 5,
|
||||
},
|
||||
overlay: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
backgroundColor: 'rgba(221, 221, 221, 0.5)',
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
overlayMessage: {
|
||||
fontSize: 40,
|
||||
marginBottom: 20,
|
||||
},
|
||||
tryAgain: {
|
||||
backgroundColor: '#887766',
|
||||
padding: 20,
|
||||
borderRadius: 5,
|
||||
},
|
||||
tryAgainText: {
|
||||
color: '#ffffff',
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
cell: {
|
||||
width: CELL_SIZE,
|
||||
height: CELL_SIZE,
|
||||
borderRadius: 5,
|
||||
backgroundColor: '#ddccbb',
|
||||
margin: CELL_MARGIN,
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
tile: {
|
||||
position: 'absolute',
|
||||
width: CELL_SIZE,
|
||||
height: CELL_SIZE,
|
||||
backgroundColor: '#ddccbb',
|
||||
borderRadius: 5,
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
value: {
|
||||
fontSize: 24,
|
||||
color: '#776666',
|
||||
fontFamily: 'Verdana',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
tile2: {
|
||||
backgroundColor: '#eeeeee',
|
||||
},
|
||||
tile4: {
|
||||
backgroundColor: '#eeeecc',
|
||||
},
|
||||
tile8: {
|
||||
backgroundColor: '#ffbb88',
|
||||
},
|
||||
tile16: {
|
||||
backgroundColor: '#ff9966',
|
||||
},
|
||||
tile32: {
|
||||
backgroundColor: '#ff7755',
|
||||
},
|
||||
tile64: {
|
||||
backgroundColor: '#ff5533',
|
||||
},
|
||||
tile128: {
|
||||
backgroundColor: '#eecc77',
|
||||
},
|
||||
tile256: {
|
||||
backgroundColor: '#eecc66',
|
||||
},
|
||||
tile512: {
|
||||
backgroundColor: '#eecc55',
|
||||
},
|
||||
tile1024: {
|
||||
backgroundColor: '#eecc33',
|
||||
},
|
||||
tile2048: {
|
||||
backgroundColor: '#eecc22',
|
||||
},
|
||||
whiteText: {
|
||||
color: '#ffffff',
|
||||
},
|
||||
threeDigits: {
|
||||
fontSize: 20,
|
||||
},
|
||||
fourDigits: {
|
||||
fontSize: 18,
|
||||
},
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent('Game2048', () => Game2048);
|
||||
|
||||
module.exports = Game2048;
|
|
@ -0,0 +1,189 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule GameBoard
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// NB: Taken straight from: https://github.com/IvanVergiliev/2048-react/blob/master/src/board.js
|
||||
// with no modificiation except to format it for CommonJS and fix lint errors
|
||||
|
||||
var rotateLeft = function (matrix) {
|
||||
var rows = matrix.length;
|
||||
var columns = matrix[0].length;
|
||||
var res = [];
|
||||
for (var row = 0; row < rows; ++row) {
|
||||
res.push([]);
|
||||
for (var column = 0; column < columns; ++column) {
|
||||
res[row][column] = matrix[column][columns - row - 1];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
var Tile = function (value, row, column) {
|
||||
this.value = value || 0;
|
||||
this.row = row || -1;
|
||||
this.column = column || -1;
|
||||
this.oldRow = -1;
|
||||
this.oldColumn = -1;
|
||||
this.markForDeletion = false;
|
||||
this.mergedInto = null;
|
||||
this.id = Tile.id++;
|
||||
};
|
||||
|
||||
Tile.id = 0;
|
||||
|
||||
Tile.prototype.moveTo = function (row, column) {
|
||||
this.oldRow = this.row;
|
||||
this.oldColumn = this.column;
|
||||
this.row = row;
|
||||
this.column = column;
|
||||
};
|
||||
|
||||
Tile.prototype.isNew = function () {
|
||||
return this.oldRow === -1 && !this.mergedInto;
|
||||
};
|
||||
|
||||
Tile.prototype.hasMoved = function () {
|
||||
return (this.fromRow() !== -1 && (this.fromRow() !== this.toRow() || this.fromColumn() !== this.toColumn())) ||
|
||||
this.mergedInto;
|
||||
};
|
||||
|
||||
Tile.prototype.fromRow = function () {
|
||||
return this.mergedInto ? this.row : this.oldRow;
|
||||
};
|
||||
|
||||
Tile.prototype.fromColumn = function () {
|
||||
return this.mergedInto ? this.column : this.oldColumn;
|
||||
};
|
||||
|
||||
Tile.prototype.toRow = function () {
|
||||
return this.mergedInto ? this.mergedInto.row : this.row;
|
||||
};
|
||||
|
||||
Tile.prototype.toColumn = function () {
|
||||
return this.mergedInto ? this.mergedInto.column : this.column;
|
||||
};
|
||||
|
||||
var Board = function () {
|
||||
this.tiles = [];
|
||||
this.cells = [];
|
||||
for (var i = 0; i < Board.size; ++i) {
|
||||
this.cells[i] = [this.addTile(), this.addTile(), this.addTile(), this.addTile()];
|
||||
}
|
||||
this.addRandomTile();
|
||||
this.setPositions();
|
||||
this.won = false;
|
||||
};
|
||||
|
||||
Board.prototype.addTile = function () {
|
||||
var res = new Tile();
|
||||
Tile.apply(res, arguments);
|
||||
this.tiles.push(res);
|
||||
return res;
|
||||
};
|
||||
|
||||
Board.size = 4;
|
||||
|
||||
Board.prototype.moveLeft = function () {
|
||||
var hasChanged = false;
|
||||
for (var row = 0; row < Board.size; ++row) {
|
||||
var currentRow = this.cells[row].filter(function (tile) { return tile.value !== 0; });
|
||||
var resultRow = [];
|
||||
for (var target = 0; target < Board.size; ++target) {
|
||||
var targetTile = currentRow.length ? currentRow.shift() : this.addTile();
|
||||
if (currentRow.length > 0 && currentRow[0].value === targetTile.value) {
|
||||
var tile1 = targetTile;
|
||||
targetTile = this.addTile(targetTile.value);
|
||||
tile1.mergedInto = targetTile;
|
||||
var tile2 = currentRow.shift();
|
||||
tile2.mergedInto = targetTile;
|
||||
targetTile.value += tile2.value;
|
||||
}
|
||||
resultRow[target] = targetTile;
|
||||
this.won |= (targetTile.value === 2048);
|
||||
hasChanged |= (targetTile.value !== this.cells[row][target].value);
|
||||
}
|
||||
this.cells[row] = resultRow;
|
||||
}
|
||||
return hasChanged;
|
||||
};
|
||||
|
||||
Board.prototype.setPositions = function () {
|
||||
this.cells.forEach(function (row, rowIndex) {
|
||||
row.forEach(function (tile, columnIndex) {
|
||||
tile.oldRow = tile.row;
|
||||
tile.oldColumn = tile.column;
|
||||
tile.row = rowIndex;
|
||||
tile.column = columnIndex;
|
||||
tile.markForDeletion = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Board.fourProbability = 0.1;
|
||||
|
||||
Board.prototype.addRandomTile = function () {
|
||||
var emptyCells = [];
|
||||
for (var r = 0; r < Board.size; ++r) {
|
||||
for (var c = 0; c < Board.size; ++c) {
|
||||
if (this.cells[r][c].value === 0) {
|
||||
emptyCells.push({r: r, c: c});
|
||||
}
|
||||
}
|
||||
}
|
||||
var index = Math.floor(Math.random() * emptyCells.length);
|
||||
var cell = emptyCells[index];
|
||||
var newValue = Math.random() < Board.fourProbability ? 4 : 2;
|
||||
this.cells[cell.r][cell.c] = this.addTile(newValue);
|
||||
};
|
||||
|
||||
Board.prototype.move = function (direction) {
|
||||
// 0 -> left, 1 -> up, 2 -> right, 3 -> down
|
||||
this.clearOldTiles();
|
||||
for (var i = 0; i < direction; ++i) {
|
||||
this.cells = rotateLeft(this.cells);
|
||||
}
|
||||
var hasChanged = this.moveLeft();
|
||||
for (var i = direction; i < 4; ++i) {
|
||||
this.cells = rotateLeft(this.cells);
|
||||
}
|
||||
if (hasChanged) {
|
||||
this.addRandomTile();
|
||||
}
|
||||
this.setPositions();
|
||||
return this;
|
||||
};
|
||||
|
||||
Board.prototype.clearOldTiles = function () {
|
||||
this.tiles = this.tiles.filter(function (tile) { return tile.markForDeletion === false; });
|
||||
this.tiles.forEach(function (tile) { tile.markForDeletion = true; });
|
||||
};
|
||||
|
||||
Board.prototype.hasWon = function () {
|
||||
return this.won;
|
||||
};
|
||||
|
||||
Board.deltaX = [-1, 0, 1, 0];
|
||||
Board.deltaY = [0, -1, 0, 1];
|
||||
|
||||
Board.prototype.hasLost = function () {
|
||||
var canMove = false;
|
||||
for (var row = 0; row < Board.size; ++row) {
|
||||
for (var column = 0; column < Board.size; ++column) {
|
||||
canMove |= (this.cells[row][column].value === 0);
|
||||
for (var dir = 0; dir < 4; ++dir) {
|
||||
var newRow = row + Board.deltaX[dir];
|
||||
var newColumn = column + Board.deltaY[dir];
|
||||
if (newRow < 0 || newRow >= Board.size || newColumn < 0 || newColumn >= Board.size) {
|
||||
continue;
|
||||
}
|
||||
canMove |= (this.cells[row][column].value === this.cells[newRow][newColumn].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return !canMove;
|
||||
};
|
||||
|
||||
module.exports = Board;
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.facebook.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@
|
|||
//
|
||||
// To run on device, change `localhost` to the IP address of your computer, and make sure your computer and
|
||||
// iOS device are on the same Wi-Fi network.
|
||||
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/Movies/MoviesApp.includeRequire.runModule.bundle"];
|
||||
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/Movies/MoviesApp.includeRequire.runModule.bundle?dev=true"];
|
||||
|
||||
// OPTION 2
|
||||
// Load from pre-bundled file on disk. To re-generate the static bundle, run
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
//
|
||||
// To run on device, change `localhost` to the IP address of your computer, and make sure your computer and
|
||||
// iOS device are on the same Wi-Fi network.
|
||||
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/TicTacToe/TicTacToeApp.includeRequire.runModule.bundle"];
|
||||
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/TicTacToe/TicTacToeApp.includeRequire.runModule.bundle?dev=true"];
|
||||
|
||||
// OPTION 2
|
||||
// Load from pre-bundled file on disk. To re-generate the static bundle, run
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule AdSupportIOSExample
|
||||
*/
|
||||
/* eslint no-console: 0 */
|
||||
'use strict';
|
||||
|
||||
var AdSupportIOS = require('AdSupportIOS');
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
exports.framework = 'React';
|
||||
exports.title = 'Advertising ID';
|
||||
exports.description = 'Example of using the ad support API.';
|
||||
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'Ad Support IOS',
|
||||
render: function() {
|
||||
return <AdSupportIOSExample />;
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
var AdSupportIOSExample = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
deviceID: 'No IDFA yet',
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
AdSupportIOS.getAdvertisingId(
|
||||
this._onSuccess,
|
||||
this._onFailure
|
||||
);
|
||||
},
|
||||
|
||||
_onSuccess: function(deviceID) {
|
||||
this.setState({
|
||||
'deviceID': deviceID,
|
||||
});
|
||||
},
|
||||
|
||||
_onFailure: function(e) {
|
||||
this.setState({
|
||||
'deviceID': 'Error!',
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text>
|
||||
<Text style={styles.title}>Advertising ID: </Text>
|
||||
{JSON.stringify(this.state.deviceID)}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
title: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
});
|
|
@ -20,7 +20,7 @@
|
|||
//
|
||||
// To run on device, change `localhost` to the IP address of your computer, and make sure your computer and
|
||||
// iOS device are on the same Wi-Fi network.
|
||||
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/UIExplorer/UIExplorerApp.includeRequire.runModule.bundle"];
|
||||
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/UIExplorer/UIExplorerApp.includeRequire.runModule.bundle?dev=true"];
|
||||
|
||||
// OPTION 2
|
||||
// Load from pre-bundled file on disk. To re-generate the static bundle, run
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule CameraRollExample
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
CameraRoll,
|
||||
Image,
|
||||
Slider,
|
||||
StyleSheet,
|
||||
SwitchIOS,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var CameraRollView = require('./CameraRollView.ios');
|
||||
|
||||
var CAMERA_ROLL_VIEW = 'camera_roll_view';
|
||||
|
||||
var CameraRollExample = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
groupTypes: 'SavedPhotos',
|
||||
sliderValue: 1,
|
||||
bigImages: true,
|
||||
};
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<SwitchIOS
|
||||
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={CAMERA_ROLL_VIEW}
|
||||
batchSize={5}
|
||||
groupTypes={this.state.groupTypes}
|
||||
renderImage={this._renderImage}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
|
||||
_renderImage(asset) {
|
||||
var imageSize = this.state.bigImages ? 150 : 75;
|
||||
var imageStyle = [styles.image, {width: imageSize, height: imageSize}];
|
||||
var location = asset.node.location.longitude ?
|
||||
JSON.stringify(asset.node.location) : 'Unknown location';
|
||||
return (
|
||||
<View key={asset} style={styles.row}>
|
||||
<Image
|
||||
source={asset.node.image}
|
||||
style={imageStyle}
|
||||
/>
|
||||
<View style={styles.info}>
|
||||
<Text style={styles.url}>{asset.node.image.uri}</Text>
|
||||
<Text>{location}</Text>
|
||||
<Text>{asset.node.group_name}</Text>
|
||||
<Text>{new Date(asset.node.timestamp).toString()}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
|
||||
_onSliderChange(value) {
|
||||
var options = CameraRoll.GroupTypesOptions;
|
||||
var index = Math.floor(value * options.length * 0.99);
|
||||
var groupTypes = options[index];
|
||||
if (groupTypes !== this.state.groupTypes) {
|
||||
this.setState({groupTypes: groupTypes});
|
||||
}
|
||||
},
|
||||
|
||||
_onSwitchChange(value) {
|
||||
this.refs[CAMERA_ROLL_VIEW].rendererChanged();
|
||||
this.setState({ bigImages: value });
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
flex: 1,
|
||||
},
|
||||
url: {
|
||||
fontSize: 9,
|
||||
marginBottom: 14,
|
||||
},
|
||||
image: {
|
||||
margin: 4,
|
||||
},
|
||||
info: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
exports.title = '<CameraRollView>';
|
||||
exports.description = 'Example component that uses CameraRoll to list user\'s photos';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'Photos',
|
||||
render() { return <CameraRollExample />; }
|
||||
}
|
||||
];
|
|
@ -0,0 +1,231 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule CameraRollView
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
ActivityIndicatorIOS,
|
||||
CameraRoll,
|
||||
Image,
|
||||
ListView,
|
||||
ListViewDataSource,
|
||||
StyleSheet,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var groupByEveryN = require('groupByEveryN');
|
||||
var logError = require('logError');
|
||||
|
||||
var propTypes = {
|
||||
/**
|
||||
* The group where the photos will be fetched from. Possible
|
||||
* values are 'Album', 'All', 'Event', 'Faces', 'Library', 'PhotoStream'
|
||||
* and SavedPhotos.
|
||||
*/
|
||||
groupTypes: React.PropTypes.oneOf([
|
||||
'Album',
|
||||
'All',
|
||||
'Event',
|
||||
'Faces',
|
||||
'Library',
|
||||
'PhotoStream',
|
||||
'SavedPhotos',
|
||||
]),
|
||||
|
||||
/**
|
||||
* Number of images that will be fetched in one page.
|
||||
*/
|
||||
batchSize: React.PropTypes.number,
|
||||
|
||||
/**
|
||||
* A function that takes a single image as a parameter and renders it.
|
||||
*/
|
||||
renderImage: React.PropTypes.func,
|
||||
|
||||
/**
|
||||
* imagesPerRow: Number of images to be shown in each row.
|
||||
*/
|
||||
imagesPerRow: React.PropTypes.number,
|
||||
};
|
||||
|
||||
var CameraRollView = React.createClass({
|
||||
propTypes: propTypes,
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
groupTypes: 'SavedPhotos',
|
||||
batchSize: 5,
|
||||
imagesPerRow: 1,
|
||||
renderImage: function(asset) {
|
||||
var imageSize = 150;
|
||||
var imageStyle = [styles.image, {width: imageSize, height: imageSize}];
|
||||
return (
|
||||
<Image
|
||||
source={asset.node.image}
|
||||
style={imageStyle}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
var ds = new ListViewDataSource({rowHasChanged: this._rowHasChanged});
|
||||
|
||||
return {
|
||||
assets: [],
|
||||
groupTypes: this.props.groupTypes,
|
||||
lastCursor: null,
|
||||
noMore: false,
|
||||
loadingMore: false,
|
||||
dataSource: ds,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* This should be called when the image renderer is changed to tell the
|
||||
* component to re-render its assets.
|
||||
*/
|
||||
rendererChanged: function() {
|
||||
var ds = new ListViewDataSource({rowHasChanged: this._rowHasChanged});
|
||||
this.state.dataSource = ds.cloneWithRows(
|
||||
groupByEveryN(this.state.assets, this.props.imagesPerRow)
|
||||
);
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.fetch();
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
if (this.props.groupTypes !== nextProps.groupTypes) {
|
||||
this.fetch(true);
|
||||
}
|
||||
},
|
||||
|
||||
_fetch: function(clear) {
|
||||
if (clear) {
|
||||
this.setState(this.getInitialState(), this.fetch);
|
||||
return;
|
||||
}
|
||||
|
||||
var fetchParams = {
|
||||
first: this.props.batchSize,
|
||||
groupTypes: this.props.groupTypes,
|
||||
};
|
||||
if (this.state.lastCursor) {
|
||||
fetchParams.after = this.state.lastCursor;
|
||||
}
|
||||
|
||||
CameraRoll.getPhotos(fetchParams, this._appendAssets, logError);
|
||||
},
|
||||
|
||||
/**
|
||||
* 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: function(clear) {
|
||||
if (!this.state.loadingMore) {
|
||||
this.setState({loadingMore: true}, () => { this._fetch(clear); });
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<ListView
|
||||
renderRow={this._renderRow}
|
||||
renderFooter={this._renderFooterSpinner}
|
||||
onEndReached={this._onEndReached}
|
||||
style={styles.container}
|
||||
dataSource={this.state.dataSource}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
_rowHasChanged: function(r1, r2) {
|
||||
if (r1.length !== r2.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < r1.length; i++) {
|
||||
if (r1[i] !== r2[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_renderFooterSpinner: function() {
|
||||
if (!this.state.noMore) {
|
||||
return <ActivityIndicatorIOS style={styles.spinner} />;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
// rowData is an array of images
|
||||
_renderRow: function(rowData, sectionID, rowID) {
|
||||
var images = rowData.map((image) => {
|
||||
if (image === null) {
|
||||
return null;
|
||||
}
|
||||
return this.props.renderImage(image);
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
{images}
|
||||
</View>
|
||||
);
|
||||
},
|
||||
|
||||
_appendAssets: function(data) {
|
||||
var assets = data.edges;
|
||||
var newState = { loadingMore: false };
|
||||
|
||||
if (!data.page_info.has_next_page) {
|
||||
newState.noMore = true;
|
||||
}
|
||||
|
||||
if (assets.length > 0) {
|
||||
newState.lastCursor = data.page_info.end_cursor;
|
||||
newState.assets = this.state.assets.concat(assets);
|
||||
newState.dataSource = this.state.dataSource.cloneWithRows(
|
||||
groupByEveryN(newState.assets, this.props.imagesPerRow)
|
||||
);
|
||||
}
|
||||
|
||||
this.setState(newState);
|
||||
},
|
||||
|
||||
_onEndReached: function() {
|
||||
if (!this.state.noMore) {
|
||||
this.fetch();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
flex: 1,
|
||||
},
|
||||
url: {
|
||||
fontSize: 9,
|
||||
marginBottom: 14,
|
||||
},
|
||||
image: {
|
||||
margin: 4,
|
||||
},
|
||||
info: {
|
||||
flex: 1,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = CameraRollView;
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule GeoLocationExample
|
||||
* @providesModule GeolocationExample
|
||||
*/
|
||||
/* eslint no-console: 0 */
|
||||
'use strict';
|
|
@ -0,0 +1,196 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule MapViewExample
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var {
|
||||
MapView,
|
||||
Text,
|
||||
TextInput,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var MapRegionInput = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
region: React.PropTypes.shape({
|
||||
latitude: React.PropTypes.number,
|
||||
longitude: React.PropTypes.number,
|
||||
latitudeDelta: React.PropTypes.number,
|
||||
longitudeDelta: React.PropTypes.number,
|
||||
}),
|
||||
onChange: React.PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
latitude: 0,
|
||||
longitude: 0,
|
||||
latitudeDelta: 0,
|
||||
longitudeDelta: 0,
|
||||
};
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
this.setState(nextProps.region);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var region = this.state;
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.row}>
|
||||
<Text>
|
||||
{'Latitude'}
|
||||
</Text>
|
||||
<TextInput
|
||||
value={'' + region.latitude}
|
||||
style={styles.textInput}
|
||||
onChange={this._onChangeLatitude}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<Text>
|
||||
{'Longitude'}
|
||||
</Text>
|
||||
<TextInput
|
||||
value={'' + region.longitude}
|
||||
style={styles.textInput}
|
||||
onChange={this._onChangeLongitude}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<Text>
|
||||
{'Latitude delta'}
|
||||
</Text>
|
||||
<TextInput
|
||||
value={'' + region.latitudeDelta}
|
||||
style={styles.textInput}
|
||||
onChange={this._onChangeLatitudeDelta}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<Text>
|
||||
{'Longitude delta'}
|
||||
</Text>
|
||||
<TextInput
|
||||
value={'' + region.longitudeDelta}
|
||||
style={styles.textInput}
|
||||
onChange={this._onChangeLongitudeDelta}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.changeButton}>
|
||||
<Text onPress={this._change}>
|
||||
{'Change'}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
|
||||
_onChangeLatitude: function(e) {
|
||||
this.setState({latitude: parseFloat(e.nativeEvent.text)});
|
||||
},
|
||||
|
||||
_onChangeLongitude: function(e) {
|
||||
this.setState({longitude: parseFloat(e.nativeEvent.text)});
|
||||
},
|
||||
|
||||
_onChangeLatitudeDelta: function(e) {
|
||||
this.setState({latitudeDelta: parseFloat(e.nativeEvent.text)});
|
||||
},
|
||||
|
||||
_onChangeLongitudeDelta: function(e) {
|
||||
this.setState({longitudeDelta: parseFloat(e.nativeEvent.text)});
|
||||
},
|
||||
|
||||
_change: function() {
|
||||
this.props.onChange(this.state);
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
var MapViewExample = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
mapRegion: null,
|
||||
mapRegionInput: null,
|
||||
};
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<MapView
|
||||
style={styles.map}
|
||||
onRegionChange={this._onRegionChanged}
|
||||
region={this.state.mapRegion}
|
||||
/>
|
||||
<MapRegionInput
|
||||
onChange={this._onRegionInputChanged}
|
||||
region={this.state.mapRegionInput}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
|
||||
_onRegionChanged(region) {
|
||||
this.setState({mapRegionInput: region});
|
||||
},
|
||||
|
||||
_onRegionInputChanged(region) {
|
||||
this.setState({
|
||||
mapRegion: region,
|
||||
mapRegionInput: region,
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
map: {
|
||||
height: 150,
|
||||
margin: 10,
|
||||
borderWidth: 1,
|
||||
borderColor: '#000000',
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
textInput: {
|
||||
width: 150,
|
||||
height: 20,
|
||||
borderWidth: 0.5,
|
||||
borderColor: '#aaaaaa',
|
||||
fontSize: 13,
|
||||
padding: 4,
|
||||
},
|
||||
changeButton: {
|
||||
alignSelf: 'center',
|
||||
marginTop: 5,
|
||||
padding: 3,
|
||||
borderWidth: 0.5,
|
||||
borderColor: '#777777',
|
||||
},
|
||||
});
|
||||
|
||||
exports.title = '<MapView>';
|
||||
exports.description = 'Base component to display maps';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'Map',
|
||||
render() { return <MapViewExample />; }
|
||||
},
|
||||
{
|
||||
title: 'Map shows user location',
|
||||
render() {
|
||||
return <MapView style={styles.map} showsUserLocation={true} />;
|
||||
}
|
||||
}
|
||||
];
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule PickerExample
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
PickerIOS,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var PickerItemIOS = PickerIOS.Item;
|
||||
|
||||
var CAR_MAKES_AND_MODELS = {
|
||||
amc: {
|
||||
name: 'AMC',
|
||||
models: ['AMX', 'Concord', 'Eagle', 'Gremlin', 'Matador', 'Pacer'],
|
||||
},
|
||||
alfa: {
|
||||
name: 'Alfa-Romeo',
|
||||
models: ['159', '4C', 'Alfasud', 'Brera', 'GTV6', 'Giulia', 'MiTo', 'Spider'],
|
||||
},
|
||||
aston: {
|
||||
name: 'Aston Martin',
|
||||
models: ['DB5', 'DB9', 'DBS', 'Rapide', 'Vanquish', 'Vantage'],
|
||||
},
|
||||
audi: {
|
||||
name: 'Audi',
|
||||
models: ['90', '4000', '5000', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'Q5', 'Q7'],
|
||||
},
|
||||
austin: {
|
||||
name: 'Austin',
|
||||
models: ['America', 'Maestro', 'Maxi', 'Mini', 'Montego', 'Princess'],
|
||||
},
|
||||
borgward: {
|
||||
name: 'Borgward',
|
||||
models: ['Hansa', 'Isabella', 'P100'],
|
||||
},
|
||||
buick: {
|
||||
name: 'Buick',
|
||||
models: ['Electra', 'LaCrosse', 'LeSabre', 'Park Avenue', 'Regal',
|
||||
'Roadmaster', 'Skylark'],
|
||||
},
|
||||
cadillac: {
|
||||
name: 'Cadillac',
|
||||
models: ['Catera', 'Cimarron', 'Eldorado', 'Fleetwood', 'Sedan de Ville'],
|
||||
},
|
||||
chevrolet: {
|
||||
name: 'Chevrolet',
|
||||
models: ['Astro', 'Aveo', 'Bel Air', 'Captiva', 'Cavalier', 'Chevelle',
|
||||
'Corvair', 'Corvette', 'Cruze', 'Nova', 'SS', 'Vega', 'Volt'],
|
||||
},
|
||||
};
|
||||
|
||||
var PickerExample = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
carMake: 'cadillac',
|
||||
modelIndex: 3,
|
||||
};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var make = CAR_MAKES_AND_MODELS[this.state.carMake];
|
||||
var selectionString = make.name + ' ' + make.models[this.state.modelIndex];
|
||||
return (
|
||||
<View>
|
||||
<Text>Please choose a make for your car:</Text>
|
||||
<PickerIOS
|
||||
selectedValue={this.state.carMake}
|
||||
onValueChange={(carMake) => this.setState({carMake, modelIndex: 0})}>
|
||||
{Object.keys(CAR_MAKES_AND_MODELS).map((carMake) => (
|
||||
<PickerItemIOS
|
||||
key={carMake}
|
||||
value={carMake}
|
||||
label={CAR_MAKES_AND_MODELS[carMake].name}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</PickerIOS>
|
||||
<Text>Please choose a model of {make.name}:</Text>
|
||||
<PickerIOS
|
||||
selectedValue={this.state.modelIndex}
|
||||
key={this.state.carMake}
|
||||
onValueChange={(modelIndex) => this.setState({modelIndex})}>
|
||||
{CAR_MAKES_AND_MODELS[this.state.carMake].models.map(
|
||||
(modelName, modelIndex) => (
|
||||
<PickerItemIOS
|
||||
key={this.state.carmake + '_' + modelIndex}
|
||||
value={modelIndex}
|
||||
label={modelName}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</PickerIOS>
|
||||
<Text>You selected: {selectionString}</Text>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
exports.title = '<PickerIOS>';
|
||||
exports.description = 'Render lists of selectable options with UIPickerView.';
|
||||
exports.examples = [
|
||||
{
|
||||
title: '<PickerIOS>',
|
||||
render: function() {
|
||||
return <PickerExample />;
|
||||
},
|
||||
}];
|
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
004D28A31AAF61C70097A701 /* UIExplorerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 004D28A21AAF61C70097A701 /* UIExplorerTests.m */; };
|
||||
13417FE91AA91432003F314A /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FE81AA91428003F314A /* libRCTImage.a */; };
|
||||
134180011AA9153C003F314A /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FEF1AA914B8003F314A /* libRCTText.a */; };
|
||||
134180021AA9153C003F314A /* libReactKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FFF1AA91531003F314A /* libReactKit.a */; };
|
||||
|
@ -16,9 +17,17 @@
|
|||
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
832C81C71AAF73C5007FA2F7 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832C81A61AAF6EFF007FA2F7 /* libRCTAdSupport.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
004D28A41AAF61C70097A701 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
|
||||
remoteInfo = UIExplorer;
|
||||
};
|
||||
13417FE71AA91428003F314A /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 13417FE31AA91428003F314A /* RCTImage.xcodeproj */;
|
||||
|
@ -54,9 +63,19 @@
|
|||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = RCTGeolocation;
|
||||
};
|
||||
832C81A51AAF6EFF007FA2F7 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 832C81A11AAF6EFE007FA2F7 /* RCTAdSupport.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
|
||||
remoteInfo = RCTAdSupport;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
004D289E1AAF61C70097A701 /* UIExplorerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIExplorerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
004D28A11AAF61C70097A701 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
004D28A21AAF61C70097A701 /* UIExplorerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UIExplorerTests.m; sourceTree = "<group>"; };
|
||||
13417FE31AA91428003F314A /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = "<group>"; };
|
||||
13417FEA1AA914B8003F314A /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = "<group>"; };
|
||||
13417FFA1AA91531003F314A /* ReactKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactKit.xcodeproj; path = ../../ReactKit/ReactKit.xcodeproj; sourceTree = "<group>"; };
|
||||
|
@ -69,13 +88,22 @@
|
|||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
832C81A11AAF6EFE007FA2F7 /* RCTAdSupport.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAdSupport.xcodeproj; path = ../../Libraries/AdSupport/RCTAdSupport.xcodeproj; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
004D289B1AAF61C70097A701 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
832C81C71AAF73C5007FA2F7 /* libRCTAdSupport.a in Frameworks */,
|
||||
134A8A2A1AACED7A00945AAE /* libRCTGeolocation.a in Frameworks */,
|
||||
1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */,
|
||||
134180011AA9153C003F314A /* libRCTText.a in Frameworks */,
|
||||
|
@ -87,14 +115,32 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
004D289F1AAF61C70097A701 /* UIExplorerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
004D28A21AAF61C70097A701 /* UIExplorerTests.m */,
|
||||
004D28A01AAF61C70097A701 /* Supporting Files */,
|
||||
);
|
||||
path = UIExplorerTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
004D28A01AAF61C70097A701 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
004D28A11AAF61C70097A701 /* Info.plist */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1316A21D1AA397F400C0188E /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */,
|
||||
13417FFA1AA91531003F314A /* ReactKit.xcodeproj */,
|
||||
832C81A11AAF6EFE007FA2F7 /* RCTAdSupport.xcodeproj */,
|
||||
134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */,
|
||||
13417FE31AA91428003F314A /* RCTImage.xcodeproj */,
|
||||
134180261AA91779003F314A /* RCTNetwork.xcodeproj */,
|
||||
13417FEA1AA914B8003F314A /* RCTText.xcodeproj */,
|
||||
13417FE31AA91428003F314A /* RCTImage.xcodeproj */,
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
|
@ -152,11 +198,20 @@
|
|||
name = UIExplorer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
832C81A21AAF6EFE007FA2F7 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
832C81A61AAF6EFF007FA2F7 /* libRCTAdSupport.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07FAE1A68108700A75B9A /* UIExplorer */,
|
||||
1316A21D1AA397F400C0188E /* Libraries */,
|
||||
004D289F1AAF61C70097A701 /* UIExplorerTests */,
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
|
@ -165,6 +220,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07F961A680F5B00A75B9A /* UIExplorer.app */,
|
||||
004D289E1AAF61C70097A701 /* UIExplorerTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
@ -172,6 +228,24 @@
|
|||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
004D289D1AAF61C70097A701 /* UIExplorerTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 004D28AD1AAF61C70097A701 /* Build configuration list for PBXNativeTarget "UIExplorerTests" */;
|
||||
buildPhases = (
|
||||
004D289A1AAF61C70097A701 /* Sources */,
|
||||
004D289B1AAF61C70097A701 /* Frameworks */,
|
||||
004D289C1AAF61C70097A701 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
004D28A51AAF61C70097A701 /* PBXTargetDependency */,
|
||||
);
|
||||
name = UIExplorerTests;
|
||||
productName = UIExplorerTests;
|
||||
productReference = 004D289E1AAF61C70097A701 /* UIExplorerTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
13B07F861A680F5B00A75B9A /* UIExplorer */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "UIExplorer" */;
|
||||
|
@ -197,6 +271,12 @@
|
|||
attributes = {
|
||||
LastUpgradeCheck = 0610;
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
TargetAttributes = {
|
||||
004D289D1AAF61C70097A701 = {
|
||||
CreatedOnToolsVersion = 6.1.1;
|
||||
TestTargetID = 13B07F861A680F5B00A75B9A;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "UIExplorer" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
|
@ -210,6 +290,10 @@
|
|||
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = 832C81A21AAF6EFE007FA2F7 /* Products */;
|
||||
ProjectRef = 832C81A11AAF6EFE007FA2F7 /* RCTAdSupport.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 134A8A211AACED6A00945AAE /* Products */;
|
||||
ProjectRef = 134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */;
|
||||
|
@ -234,6 +318,7 @@
|
|||
projectRoot = "";
|
||||
targets = (
|
||||
13B07F861A680F5B00A75B9A /* UIExplorer */,
|
||||
004D289D1AAF61C70097A701 /* UIExplorerTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
@ -274,9 +359,23 @@
|
|||
remoteRef = 134A8A241AACED6A00945AAE /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
832C81A61AAF6EFF007FA2F7 /* libRCTAdSupport.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRCTAdSupport.a;
|
||||
remoteRef = 832C81A51AAF6EFF007FA2F7 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
004D289C1AAF61C70097A701 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -289,6 +388,14 @@
|
|||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
004D289A1AAF61C70097A701 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
004D28A31AAF61C70097A701 /* UIExplorerTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
13B07F871A680F5B00A75B9A /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -300,6 +407,14 @@
|
|||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
004D28A51AAF61C70097A701 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 13B07F861A680F5B00A75B9A /* UIExplorer */;
|
||||
targetProxy = 004D28A41AAF61C70097A701 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
|
@ -312,6 +427,42 @@
|
|||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
004D28A61AAF61C70097A701 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = UIExplorerTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UIExplorer.app/UIExplorer";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
004D28A71AAF61C70097A701 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = UIExplorerTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UIExplorer.app/UIExplorer";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
13B07F941A680F5B00A75B9A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
|
@ -435,6 +586,15 @@
|
|||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
004D28AD1AAF61C70097A701 /* Build configuration list for PBXNativeTarget "UIExplorerTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
004D28A61AAF61C70097A701 /* Debug */,
|
||||
004D28A71AAF61C70097A701 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "UIExplorer" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
|
|
@ -20,6 +20,20 @@
|
|||
ReferencedContainer = "container:UIExplorer.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "004D289D1AAF61C70097A701"
|
||||
BuildableName = "UIExplorerTests.xctest"
|
||||
BlueprintName = "UIExplorerTests"
|
||||
ReferencedContainer = "container:UIExplorer.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
|
@ -28,6 +42,16 @@
|
|||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "004D289D1AAF61C70097A701"
|
||||
BuildableName = "UIExplorerTests.xctest"
|
||||
BlueprintName = "UIExplorerTests"
|
||||
ReferencedContainer = "container:UIExplorer.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
|
|
|
@ -31,11 +31,15 @@ var EXAMPLES = [
|
|||
require('./TouchableExample'),
|
||||
require('./ActivityIndicatorExample'),
|
||||
require('./ScrollViewExample'),
|
||||
require('./PickerExample'),
|
||||
require('./DatePickerExample'),
|
||||
require('./GeoLocationExample'),
|
||||
require('./GeolocationExample'),
|
||||
require('./TabBarExample'),
|
||||
require('./SwitchExample'),
|
||||
require('./SliderExample'),
|
||||
require('./CameraRollExample.ios'),
|
||||
require('./MapViewExample'),
|
||||
require('./AdSupportIOSExample'),
|
||||
];
|
||||
|
||||
var UIExplorerList = React.createClass({
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.facebook.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#define TIMEOUT_SECONDS 30
|
||||
|
||||
@interface UIExplorerTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIExplorerTests
|
||||
|
||||
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
|
||||
{
|
||||
if (test(view)) {
|
||||
return YES;
|
||||
}
|
||||
for (UIView *subview in [view subviews]) {
|
||||
if ([self findSubviewInView:subview matching:test]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)testRootViewLoadsAndRenders {
|
||||
UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
|
||||
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
|
||||
BOOL foundElement = NO;
|
||||
|
||||
while ([date timeIntervalSinceNow] > 0 && !foundElement) {
|
||||
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:date];
|
||||
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:date];
|
||||
|
||||
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
|
||||
if ([view respondsToSelector:@selector(attributedText)]) {
|
||||
NSString *text = [(id)view attributedText].string;
|
||||
if ([text isEqualToString:@"<View>"]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}];
|
||||
}
|
||||
|
||||
XCTAssertTrue(foundElement, @"Cound't find element with '<View>' text in %d seconds", TIMEOUT_SECONDS);
|
||||
}
|
||||
|
||||
|
||||
@end
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule AdSupportIOS
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var AdSupport = require('NativeModules').RCTAdSupport;
|
||||
|
||||
module.exports = {
|
||||
getAdvertisingId: function(onSuccess, onFailure) {
|
||||
AdSupport.getAdvertisingId(onSuccess, onFailure);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTBridgeModule.h"
|
||||
|
||||
@interface RCTAdSupport : NSObject <RCTBridgeModule>
|
||||
|
||||
@end
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTAdSupport.h"
|
||||
|
||||
#import <AdSupport/ASIdentifierManager.h>
|
||||
|
||||
@implementation RCTAdSupport
|
||||
|
||||
- (void)getAdvertisingId:(RCTResponseSenderBlock)callback withErrorCallback:(RCTResponseSenderBlock)errorCallback
|
||||
{
|
||||
RCT_EXPORT();
|
||||
|
||||
if ([ASIdentifierManager class]) {
|
||||
callback(@[[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]]);
|
||||
} else {
|
||||
return errorCallback(@[@"as_identifier_unavailable"]);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,248 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
832C819C1AAF6E1A007FA2F7 /* RCTAdSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 832C819B1AAF6E1A007FA2F7 /* RCTAdSupport.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
832C817E1AAF6DEF007FA2F7 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "include/$(PRODUCT_NAME)";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
832C81801AAF6DEF007FA2F7 /* libRCTAdSupport.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTAdSupport.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
832C819A1AAF6E1A007FA2F7 /* RCTAdSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAdSupport.h; sourceTree = "<group>"; };
|
||||
832C819B1AAF6E1A007FA2F7 /* RCTAdSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAdSupport.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
832C817D1AAF6DEF007FA2F7 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
832C81771AAF6DEF007FA2F7 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
832C819A1AAF6E1A007FA2F7 /* RCTAdSupport.h */,
|
||||
832C819B1AAF6E1A007FA2F7 /* RCTAdSupport.m */,
|
||||
832C81811AAF6DEF007FA2F7 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
832C81811AAF6DEF007FA2F7 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
832C81801AAF6DEF007FA2F7 /* libRCTAdSupport.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
832C817F1AAF6DEF007FA2F7 /* RCTAdSupport */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 832C81941AAF6DF0007FA2F7 /* Build configuration list for PBXNativeTarget "RCTAdSupport" */;
|
||||
buildPhases = (
|
||||
832C817C1AAF6DEF007FA2F7 /* Sources */,
|
||||
832C817D1AAF6DEF007FA2F7 /* Frameworks */,
|
||||
832C817E1AAF6DEF007FA2F7 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = RCTAdSupport;
|
||||
productName = RCTAdSupport;
|
||||
productReference = 832C81801AAF6DEF007FA2F7 /* libRCTAdSupport.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
832C81781AAF6DEF007FA2F7 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0620;
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
TargetAttributes = {
|
||||
832C817F1AAF6DEF007FA2F7 = {
|
||||
CreatedOnToolsVersion = 6.2;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 832C817B1AAF6DEF007FA2F7 /* Build configuration list for PBXProject "RCTAdSupport" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 832C81771AAF6DEF007FA2F7;
|
||||
productRefGroup = 832C81811AAF6DEF007FA2F7 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
832C817F1AAF6DEF007FA2F7 /* RCTAdSupport */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
832C817C1AAF6DEF007FA2F7 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
832C819C1AAF6E1A007FA2F7 /* RCTAdSupport.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
832C81921AAF6DF0007FA2F7 /* 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_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
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_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../../ReactKit/**",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
832C81931AAF6DF0007FA2F7 /* 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_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../../ReactKit/**",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
832C81951AAF6DF0007FA2F7 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
832C81961AAF6DF0007FA2F7 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
832C817B1AAF6DEF007FA2F7 /* Build configuration list for PBXProject "RCTAdSupport" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
832C81921AAF6DF0007FA2F7 /* Debug */,
|
||||
832C81931AAF6DF0007FA2F7 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
832C81941AAF6DF0007FA2F7 /* Build configuration list for PBXNativeTarget "RCTAdSupport" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
832C81951AAF6DF0007FA2F7 /* Debug */,
|
||||
832C81961AAF6DF0007FA2F7 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 832C81781AAF6DEF007FA2F7 /* Project object */;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule Animation
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var { RCTAnimationManager } = require('NativeModules');
|
||||
var AnimationUtils = require('AnimationUtils');
|
||||
|
||||
type EasingFunction = (t: number) => number;
|
||||
|
||||
var Animation = {
|
||||
Mixin: require('AnimationMixin'),
|
||||
|
||||
startAnimation: function(
|
||||
node: any,
|
||||
duration: number,
|
||||
delay: number,
|
||||
easing: (string | EasingFunction),
|
||||
properties: {[key: string]: any}
|
||||
): number {
|
||||
var nodeHandle = +node.getNodeHandle();
|
||||
var easingSample = AnimationUtils.evaluateEasingFunction(duration, easing);
|
||||
RCTAnimationManager.startAnimation(nodeHandle, AnimationUtils.allocateTag(), duration, delay, easingSample, properties);
|
||||
},
|
||||
|
||||
stopAnimation: function(tag) {
|
||||
RCTAnimationManager.stopAnimation(tag);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = Animation;
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule AnimationMixin
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var AnimationUtils = require('AnimationUtils');
|
||||
var { RCTAnimationManager } = require('NativeModules');
|
||||
|
||||
var invariant = require('invariant');
|
||||
|
||||
type EasingFunction = (t: number) => number;
|
||||
|
||||
var AnimationMixin = {
|
||||
getInitialState: function(): Object {
|
||||
return {};
|
||||
},
|
||||
|
||||
startAnimation: function(
|
||||
refKey: string,
|
||||
duration: number,
|
||||
delay: number,
|
||||
easing: (string | EasingFunction),
|
||||
properties: {[key: string]: any}
|
||||
): number {
|
||||
var ref = this.refs[refKey];
|
||||
invariant(
|
||||
ref,
|
||||
'Invalid refKey ' + refKey + '; ' +
|
||||
'valid refs: ' + JSON.stringify(Object.keys(this.refs))
|
||||
);
|
||||
|
||||
var nodeHandle = +ref.getNodeHandle();
|
||||
var easingSample = AnimationUtils.evaluateEasingFunction(duration, easing);
|
||||
RCTAnimationManager.startAnimation(nodeHandle, AnimationUtils.allocateTag(), duration, delay, easingSample, properties);
|
||||
},
|
||||
|
||||
stopAnimation: function(tag: number) {
|
||||
RCTAnimationManager.stopAnimation(tag);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = AnimationMixin;
|
|
@ -0,0 +1,226 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule AnimationUtils
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
type EasingFunction = (t: number) => number;
|
||||
|
||||
var b = 0,
|
||||
c = 1,
|
||||
d = 1;
|
||||
var defaults = {
|
||||
easeInQuad: function(t) {
|
||||
return c * (t /= 1) * t + b;
|
||||
},
|
||||
easeOutQuad: function(t) {
|
||||
return -c * (t /= d) * (t - 2) + b;
|
||||
},
|
||||
easeInOutQuad: function(t) {
|
||||
if ((t /= d / 2) < 1) {
|
||||
return c / 2 * t * t + b;
|
||||
}
|
||||
return -c / 2 * ((--t) * (t - 2) - 1) + b;
|
||||
},
|
||||
easeInCubic: function(t) {
|
||||
return c * (t /= d) * t * t + b;
|
||||
},
|
||||
easeOutCubic: function(t) {
|
||||
return c * ((t = t / d - 1) * t * t + 1) + b;
|
||||
},
|
||||
easeInOutCubic: function(t) {
|
||||
if ((t /= d / 2) < 1) {
|
||||
return c / 2 * t * t * t + b;
|
||||
}
|
||||
return c / 2 * ((t -= 2) * t * t + 2) + b;
|
||||
},
|
||||
easeInQuart: function(t) {
|
||||
return c * (t /= d) * t * t * t + b;
|
||||
},
|
||||
easeOutQuart: function(t) {
|
||||
return -c * ((t = t / d - 1) * t * t * t - 1) + b;
|
||||
},
|
||||
easeInOutQuart: function(t) {
|
||||
if ((t /= d / 2) < 1) {
|
||||
return c / 2 * t * t * t * t + b;
|
||||
}
|
||||
return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
|
||||
},
|
||||
easeInQuint: function(t) {
|
||||
return c * (t /= d) * t * t * t * t + b;
|
||||
},
|
||||
easeOutQuint: function(t) {
|
||||
return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
|
||||
},
|
||||
easeInOutQuint: function(t) {
|
||||
if ((t /= d / 2) < 1) {
|
||||
return c / 2 * t * t * t * t * t + b;
|
||||
}
|
||||
return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
|
||||
},
|
||||
easeInSine: function(t) {
|
||||
return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
|
||||
},
|
||||
easeOutSine: function(t) {
|
||||
return c * Math.sin(t / d * (Math.PI / 2)) + b;
|
||||
},
|
||||
easeInOutSine: function(t) {
|
||||
return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
|
||||
},
|
||||
easeInExpo: function(t) {
|
||||
return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
|
||||
},
|
||||
easeOutExpo: function(t) {
|
||||
return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
|
||||
},
|
||||
easeInOutExpo: function(t) {
|
||||
if (t === 0) {
|
||||
return b;
|
||||
}
|
||||
if (t === d) {
|
||||
return b + c;
|
||||
}
|
||||
if ((t /= d / 2) < 1) {
|
||||
return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
|
||||
}
|
||||
return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
|
||||
},
|
||||
easeInCirc: function(t) {
|
||||
return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
|
||||
},
|
||||
easeOutCirc: function(t) {
|
||||
return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
|
||||
},
|
||||
easeInOutCirc: function(t) {
|
||||
if ((t /= d / 2) < 1) {
|
||||
return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
|
||||
}
|
||||
return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
|
||||
},
|
||||
easeInElastic: function(t) {
|
||||
var s = 1.70158;
|
||||
var p = 0;
|
||||
var a = c;
|
||||
if (t === 0) {
|
||||
return b;
|
||||
}
|
||||
if ((t /= d) === 1) {
|
||||
return b + c;
|
||||
}
|
||||
if (!p) {
|
||||
p = d * 0.3;
|
||||
}
|
||||
if (a < Math.abs(c)) {
|
||||
a = c;
|
||||
var s = p / 4;
|
||||
} else {
|
||||
var s = p / (2 * Math.PI) * Math.asin(c / a);
|
||||
}
|
||||
return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
|
||||
},
|
||||
easeOutElastic: function(t) {
|
||||
var s = 1.70158;
|
||||
var p = 0;
|
||||
var a = c;
|
||||
if (t === 0) {
|
||||
return b;
|
||||
}
|
||||
if ((t /= d) === 1) {
|
||||
return b + c;
|
||||
}
|
||||
if (!p) {
|
||||
p = d * 0.3;
|
||||
}
|
||||
if (a < Math.abs(c)) {
|
||||
a = c;
|
||||
var s = p / 4;
|
||||
} else {
|
||||
var s = p / (2 * Math.PI) * Math.asin(c / a);
|
||||
}
|
||||
return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
|
||||
},
|
||||
easeInOutElastic: function(t) {
|
||||
var s = 1.70158;
|
||||
var p = 0;
|
||||
var a = c;
|
||||
if (t === 0) {
|
||||
return b;
|
||||
}
|
||||
if ((t /= d / 2) === 2) {
|
||||
return b + c;
|
||||
}
|
||||
if (!p) {
|
||||
p = d * (0.3 * 1.5);
|
||||
}
|
||||
if (a < Math.abs(c)) {
|
||||
a = c;
|
||||
var s = p / 4;
|
||||
} else {
|
||||
var s = p / (2 * Math.PI) * Math.asin(c / a);
|
||||
}
|
||||
if (t < 1) {
|
||||
return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
|
||||
}
|
||||
return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
|
||||
},
|
||||
easeInBack: function(t) {
|
||||
var s = 1.70158;
|
||||
return c * (t /= d) * t * ((s + 1) * t - s) + b;
|
||||
},
|
||||
easeOutBack: function(t) {
|
||||
var s = 1.70158;
|
||||
return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
|
||||
},
|
||||
easeInOutBack: function(t) {
|
||||
var s = 1.70158;
|
||||
if ((t /= d / 2) < 1) {
|
||||
return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
|
||||
}
|
||||
return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
|
||||
},
|
||||
easeInBounce: function(t) {
|
||||
return c - this.easeOutBounce(d - t) + b;
|
||||
},
|
||||
easeOutBounce: function(t) {
|
||||
if ((t /= d) < (1 / 2.75)) {
|
||||
return c * (7.5625 * t * t) + b;
|
||||
} else if (t < (2 / 2.75)) {
|
||||
return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
|
||||
} else if (t < (2.5 / 2.75)) {
|
||||
return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
|
||||
} else {
|
||||
return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
|
||||
}
|
||||
},
|
||||
easeInOutBounce: function(t) {
|
||||
if (t < d / 2) {
|
||||
return this.easeInBounce(t * 2) * 0.5 + b;
|
||||
}
|
||||
return this.easeOutBounce(t * 2 - d) * 0.5 + c * 0.5 + b;
|
||||
},
|
||||
};
|
||||
|
||||
var ticksPerSecond = 60;
|
||||
var lastUsedTag = 0;
|
||||
|
||||
module.exports = {
|
||||
allocateTag: function(): number {
|
||||
return ++lastUsedTag;
|
||||
},
|
||||
|
||||
evaluateEasingFunction: function(duration: number, easing: string | EasingFunction): Array<number> {
|
||||
if (typeof easing === 'string') {
|
||||
easing = defaults[easing] || defaults.easeOutQuad;
|
||||
}
|
||||
|
||||
var tickCount = Math.round(duration * ticksPerSecond / 1000);
|
||||
var sample = [];
|
||||
for (var i = 0; i <= tickCount; i++) {
|
||||
sample.push(easing(i / tickCount));
|
||||
}
|
||||
|
||||
return sample;
|
||||
},
|
||||
};
|
|
@ -53,10 +53,12 @@ var AppRegistry = {
|
|||
|
||||
runApplication: function(appKey, appParameters) {
|
||||
console.log(
|
||||
'Running application "' + appKey + '" with appParams: ',
|
||||
appParameters
|
||||
'Running application "' + appKey + '" with appParams: ' +
|
||||
JSON.stringify(appParameters) + '. ' +
|
||||
'__DEV__ === ' + __DEV__ +
|
||||
', development-level warning are ' + (__DEV__ ? 'ON' : 'OFF') +
|
||||
', performance optimizations are ' + (__DEV__ ? 'OFF' : 'ON')
|
||||
);
|
||||
|
||||
invariant(
|
||||
runnables[appKey] && runnables[appKey].run,
|
||||
'Application ' + appKey + ' has not been registered.'
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule CameraRoll
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ReactPropTypes = require('ReactPropTypes');
|
||||
var RKCameraRollManager = require('NativeModules').RKCameraRollManager;
|
||||
|
||||
var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
|
||||
var deepFreezeAndThrowOnMutationInDev =
|
||||
require('deepFreezeAndThrowOnMutationInDev');
|
||||
var invariant = require('invariant');
|
||||
|
||||
var GROUP_TYPES_OPTIONS = [
|
||||
'Album',
|
||||
'All',
|
||||
'Event',
|
||||
'Faces',
|
||||
'Library',
|
||||
'PhotoStream',
|
||||
'SavedPhotos', // default
|
||||
];
|
||||
|
||||
deepFreezeAndThrowOnMutationInDev(GROUP_TYPES_OPTIONS);
|
||||
|
||||
/**
|
||||
* Shape of the param arg for the `getPhotos` function.
|
||||
*/
|
||||
var getPhotosParamChecker = createStrictShapeTypeChecker({
|
||||
/**
|
||||
* The number of photos wanted in reverse order of the photo application
|
||||
* (i.e. most recent first for SavedPhotos).
|
||||
*/
|
||||
first: ReactPropTypes.number.isRequired,
|
||||
|
||||
/**
|
||||
* A cursor that matches `page_info { end_cursor }` returned from a previous
|
||||
* call to `getPhotos`
|
||||
*/
|
||||
after: ReactPropTypes.string,
|
||||
|
||||
/**
|
||||
* Specifies which group types to filter the results to.
|
||||
*/
|
||||
groupTypes: ReactPropTypes.oneOf(GROUP_TYPES_OPTIONS),
|
||||
|
||||
/**
|
||||
* Specifies filter on group names, like 'Recent Photos' or custom album
|
||||
* titles.
|
||||
*/
|
||||
groupName: ReactPropTypes.string,
|
||||
});
|
||||
|
||||
/**
|
||||
* Shape of the return value of the `getPhotos` function.
|
||||
*/
|
||||
var getPhotosReturnChecker = createStrictShapeTypeChecker({
|
||||
edges: ReactPropTypes.arrayOf(createStrictShapeTypeChecker({
|
||||
node: createStrictShapeTypeChecker({
|
||||
type: ReactPropTypes.string.isRequired,
|
||||
group_name: ReactPropTypes.string.isRequired,
|
||||
image: createStrictShapeTypeChecker({
|
||||
uri: ReactPropTypes.string.isRequired,
|
||||
height: ReactPropTypes.number.isRequired,
|
||||
width: ReactPropTypes.number.isRequired,
|
||||
isStored: ReactPropTypes.bool,
|
||||
}).isRequired,
|
||||
timestamp: ReactPropTypes.number.isRequired,
|
||||
location: createStrictShapeTypeChecker({
|
||||
latitude: ReactPropTypes.number,
|
||||
longitude: ReactPropTypes.number,
|
||||
altitude: ReactPropTypes.number,
|
||||
heading: ReactPropTypes.number,
|
||||
speed: ReactPropTypes.number,
|
||||
}),
|
||||
}).isRequired,
|
||||
})).isRequired,
|
||||
page_info: createStrictShapeTypeChecker({
|
||||
has_next_page: ReactPropTypes.bool.isRequired,
|
||||
start_cursor: ReactPropTypes.string,
|
||||
end_cursor: ReactPropTypes.string,
|
||||
}).isRequired,
|
||||
});
|
||||
|
||||
class CameraRoll {
|
||||
/**
|
||||
* Saves the image with tag `tag` to the camera roll.
|
||||
*
|
||||
* @param {string} tag - Can be any of the three kinds of tags we accept:
|
||||
* 1. URL
|
||||
* 2. assets-library tag
|
||||
* 3. tag returned from storing an image in memory
|
||||
*/
|
||||
static saveImageWithTag(tag, successCallback, errorCallback) {
|
||||
invariant(
|
||||
typeof tag === 'string',
|
||||
'CameraRoll.saveImageWithTag tag must be a valid string.'
|
||||
);
|
||||
RKCameraRollManager.saveImageWithTag(
|
||||
tag,
|
||||
(imageTag) => {
|
||||
successCallback && successCallback(imageTag);
|
||||
},
|
||||
(errorMessage) => {
|
||||
errorCallback && errorCallback(errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes `callback` with photo identifier objects from the local camera
|
||||
* roll of the device matching shape defined by `getPhotosReturnChecker`.
|
||||
*
|
||||
* @param {object} params - See `getPhotosParamChecker`.
|
||||
* @param {function} callback - Invoked with arg of shape defined by
|
||||
* `getPhotosReturnChecker` on success.
|
||||
* @param {function} errorCallback - Invoked with error message on error.
|
||||
*/
|
||||
static getPhotos(params, callback, errorCallback) {
|
||||
var metaCallback = callback;
|
||||
if (__DEV__) {
|
||||
getPhotosParamChecker({params}, 'params', 'CameraRoll.getPhotos');
|
||||
invariant(
|
||||
typeof callback === 'function',
|
||||
'CameraRoll.getPhotos callback must be a valid function.'
|
||||
);
|
||||
invariant(
|
||||
typeof errorCallback === 'function',
|
||||
'CameraRoll.getPhotos errorCallback must be a valid function.'
|
||||
);
|
||||
}
|
||||
if (__DEV__) {
|
||||
metaCallback = (response) => {
|
||||
getPhotosReturnChecker(
|
||||
{response},
|
||||
'response',
|
||||
'CameraRoll.getPhotos callback'
|
||||
);
|
||||
callback(response);
|
||||
};
|
||||
}
|
||||
RKCameraRollManager.getPhotos(params, metaCallback, errorCallback);
|
||||
}
|
||||
}
|
||||
|
||||
CameraRoll.GroupTypesOptions = GROUP_TYPES_OPTIONS;
|
||||
|
||||
module.exports = CameraRoll;
|
|
@ -0,0 +1,165 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule MapView
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var EdgeInsetsPropType = require('EdgeInsetsPropType');
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var React = require('React');
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
var View = require('View');
|
||||
|
||||
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
|
||||
var deepDiffer = require('deepDiffer');
|
||||
var insetsDiffer = require('insetsDiffer');
|
||||
var merge = require('merge');
|
||||
|
||||
var MapView = React.createClass({
|
||||
mixins: [NativeMethodsMixin],
|
||||
|
||||
propTypes: {
|
||||
/**
|
||||
* Used to style and layout the `MapView`. See `StyleSheet.js` and
|
||||
* `ViewStylePropTypes.js` for more info.
|
||||
*/
|
||||
style: View.propTypes.style,
|
||||
|
||||
/**
|
||||
* If `true` the app will ask for the user's location and focus on it.
|
||||
* Default value is `false`.
|
||||
*
|
||||
* **NOTE**: You need to add NSLocationWhenInUseUsageDescription key in
|
||||
* Info.plist to enable geolocation, otherwise it is going
|
||||
* to *fail silently*!
|
||||
*/
|
||||
showsUserLocation: React.PropTypes.bool,
|
||||
|
||||
/**
|
||||
* If `false` the user won't be able to pinch/zoom the map.
|
||||
* Default `value` is true.
|
||||
*/
|
||||
zoomEnabled: React.PropTypes.bool,
|
||||
|
||||
/**
|
||||
* When this property is set to `true` and a valid camera is associated with
|
||||
* the map, the camera’s heading angle is used to rotate the plane of the
|
||||
* map around its center point. When this property is set to `false`, the
|
||||
* camera’s heading angle is ignored and the map is always oriented so
|
||||
* that true north is situated at the top of the map view
|
||||
*/
|
||||
rotateEnabled: React.PropTypes.bool,
|
||||
|
||||
/**
|
||||
* When this property is set to `true` and a valid camera is associated
|
||||
* with the map, the camera’s pitch angle is used to tilt the plane
|
||||
* of the map. When this property is set to `false`, the camera’s pitch
|
||||
* angle is ignored and the map is always displayed as if the user
|
||||
* is looking straight down onto it.
|
||||
*/
|
||||
pitchEnabled: React.PropTypes.bool,
|
||||
|
||||
/**
|
||||
* If `false` the user won't be able to change the map region being displayed.
|
||||
* Default value is `true`.
|
||||
*/
|
||||
scrollEnabled: React.PropTypes.bool,
|
||||
|
||||
/**
|
||||
* The region to be displayed by the map.
|
||||
*
|
||||
* The region is defined by the center coordinates and the span of
|
||||
* coordinates to display.
|
||||
*/
|
||||
region: React.PropTypes.shape({
|
||||
/**
|
||||
* Coordinates for the center of the map.
|
||||
*/
|
||||
latitude: React.PropTypes.number.isRequired,
|
||||
longitude: React.PropTypes.number.isRequired,
|
||||
|
||||
/**
|
||||
* Distance between the minimun and the maximum latitude/longitude
|
||||
* to be displayed.
|
||||
*/
|
||||
latitudeDelta: React.PropTypes.number.isRequired,
|
||||
longitudeDelta: React.PropTypes.number.isRequired,
|
||||
}),
|
||||
|
||||
/**
|
||||
* Maximum size of area that can be displayed.
|
||||
*/
|
||||
maxDelta: React.PropTypes.number,
|
||||
|
||||
/**
|
||||
* Minimum size of area that can be displayed.
|
||||
*/
|
||||
minDelta: React.PropTypes.number,
|
||||
|
||||
/**
|
||||
* Insets for the map's legal label, originally at bottom left of the map.
|
||||
* See `EdgeInsetsPropType.js` for more information.
|
||||
*/
|
||||
legalLabelInsets: EdgeInsetsPropType,
|
||||
|
||||
/**
|
||||
* Callback that is called continuously when the user is dragging the map.
|
||||
*/
|
||||
onRegionChange: React.PropTypes.func,
|
||||
|
||||
/**
|
||||
* Callback that is called once, when the user is done moving the map.
|
||||
*/
|
||||
onRegionChangeComplete: React.PropTypes.func,
|
||||
},
|
||||
|
||||
_onChange: function(event) {
|
||||
if (event.nativeEvent.continuous) {
|
||||
this.props.onRegionChange &&
|
||||
this.props.onRegionChange(event.nativeEvent.region);
|
||||
} else {
|
||||
this.props.onRegionChangeComplete &&
|
||||
this.props.onRegionChangeComplete(event.nativeEvent.region);
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<RKMap
|
||||
style={this.props.style}
|
||||
showsUserLocation={this.props.showsUserLocation}
|
||||
zoomEnabled={this.props.zoomEnabled}
|
||||
rotateEnabled={this.props.rotateEnabled}
|
||||
pitchEnabled={this.props.pitchEnabled}
|
||||
scrollEnabled={this.props.scrollEnabled}
|
||||
region={this.props.region}
|
||||
maxDelta={this.props.maxDelta}
|
||||
minDelta={this.props.minDelta}
|
||||
legalLabelInsets={this.props.legalLabelInsets}
|
||||
onChange={this._onChange}
|
||||
onTouchStart={this.props.onTouchStart}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
var RKMap = createReactIOSNativeComponentClass({
|
||||
validAttributes: merge(
|
||||
ReactIOSViewAttributes.UIView, {
|
||||
showsUserLocation: true,
|
||||
zoomEnabled: true,
|
||||
rotateEnabled: true,
|
||||
pitchEnabled: true,
|
||||
scrollEnabled: true,
|
||||
region: {diff: deepDiffer},
|
||||
maxDelta: true,
|
||||
minDelta: true,
|
||||
legalLabelInsets: {diff: insetsDiffer},
|
||||
}
|
||||
),
|
||||
uiViewClassName: 'RCTMap',
|
||||
});
|
||||
|
||||
module.exports = MapView;
|
|
@ -0,0 +1,124 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule TouchableBounce
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var React = require('React');
|
||||
var POPAnimation = require('POPAnimation');
|
||||
var Animation = require('Animation');
|
||||
var Touchable = require('Touchable');
|
||||
|
||||
var merge = require('merge');
|
||||
var copyProperties = require('copyProperties');
|
||||
var onlyChild = require('onlyChild');
|
||||
|
||||
/**
|
||||
* When the scroll view is disabled, this defines how far your touch may move
|
||||
* off of the button, before deactivating the button. Once deactivated, try
|
||||
* moving it back and you'll see that the button is once again reactivated!
|
||||
* Move it back and forth several times while the scroll view is disabled.
|
||||
*/
|
||||
var PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
|
||||
/**
|
||||
* Example of using the `TouchableMixin` to play well with other responder
|
||||
* locking views including `ScrollView`. `TouchableMixin` provides touchable
|
||||
* hooks (`this.touchableHandle*`) that we forward events to. In turn,
|
||||
* `TouchableMixin` expects us to implement some abstract methods to handle
|
||||
* interesting interactions such as `handleTouchablePress`.
|
||||
*/
|
||||
var TouchableBounce = React.createClass({
|
||||
mixins: [Touchable.Mixin, NativeMethodsMixin],
|
||||
|
||||
propTypes: {
|
||||
onPress: React.PropTypes.func,
|
||||
// The function passed takes a callback to start the animation which should
|
||||
// be run after this onPress handler is done. You can use this (for example)
|
||||
// to update UI before starting the animation.
|
||||
onPressWithCompletion: React.PropTypes.func,
|
||||
// the function passed is called after the animation is complete
|
||||
onPressAnimationComplete: React.PropTypes.func,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return merge(this.touchableGetInitialState(), {animationID: null});
|
||||
},
|
||||
|
||||
bounceTo: function(value, velocity, bounciness, fromValue, callback) {
|
||||
if (POPAnimation) {
|
||||
this.state.animationID && this.removeAnimation(this.state.animationID);
|
||||
var anim = {
|
||||
property: POPAnimation.Properties.scaleXY,
|
||||
dynamicsTension: 0,
|
||||
toValue: [value, value],
|
||||
velocity: [velocity, velocity],
|
||||
springBounciness: bounciness,
|
||||
};
|
||||
if (fromValue) {
|
||||
anim.fromValue = [fromValue, fromValue];
|
||||
}
|
||||
this.state.animationID = POPAnimation.createSpringAnimation(anim);
|
||||
this.addAnimation(this.state.animationID, callback);
|
||||
} else {
|
||||
Animation.startAnimation(this, 300, 0, 'easeOutBack', {scaleXY: [value, value]});
|
||||
if (fromValue && typeof fromValue === 'function') {
|
||||
callback = fromValue;
|
||||
}
|
||||
if (callback) {
|
||||
setTimeout(callback, 300);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
|
||||
* defined on your component.
|
||||
*/
|
||||
touchableHandleActivePressIn: function() {
|
||||
this.bounceTo(0.93, 0.1, 0);
|
||||
},
|
||||
|
||||
touchableHandleActivePressOut: function() {
|
||||
this.bounceTo(1, 0.4, 0);
|
||||
},
|
||||
|
||||
touchableHandlePress: function() {
|
||||
if (this.props.onPressWithCompletion) {
|
||||
this.props.onPressWithCompletion(
|
||||
this.bounceTo.bind(this, 1, 10, 10, 0.93, this.props.onPressAnimationComplete)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.bounceTo(1, 10, 10, undefined, this.props.onPressAnimationComplete);
|
||||
this.props.onPress && this.props.onPress();
|
||||
},
|
||||
|
||||
touchableGetPressRectOffset: function() {
|
||||
return PRESS_RECT_OFFSET; // Always make sure to predeclare a constant!
|
||||
},
|
||||
|
||||
touchableGetHighlightDelayMS: function() {
|
||||
return 0;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// Note(vjeux): use cloneWithProps once React has been upgraded
|
||||
var child = onlyChild(this.props.children);
|
||||
copyProperties(child.props, {
|
||||
accessible: true,
|
||||
testID: this.props.testID,
|
||||
onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
|
||||
onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest,
|
||||
onResponderGrant: this.touchableHandleResponderGrant,
|
||||
onResponderMove: this.touchableHandleResponderMove,
|
||||
onResponderRelease: this.touchableHandleResponderRelease,
|
||||
onResponderTerminate: this.touchableHandleResponderTerminate
|
||||
});
|
||||
return child;
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = TouchableBounce;
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTBridgeModule.h"
|
||||
|
||||
@interface RCTCameraRollManager : NSObject <RCTBridgeModule>
|
||||
|
||||
@end
|
|
@ -0,0 +1,148 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTCameraRollManager.h"
|
||||
|
||||
#import <AssetsLibrary/AssetsLibrary.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTImageLoader.h"
|
||||
#import "RCTLog.h"
|
||||
|
||||
@implementation RCTCameraRollManager
|
||||
|
||||
- (void)saveImageWithTag:(NSString *)imageTag successCallback:(RCTResponseSenderBlock)successCallback errorCallback:(RCTResponseSenderBlock)errorCallback
|
||||
{
|
||||
RCT_EXPORT();
|
||||
|
||||
[RCTImageLoader loadImageWithTag:imageTag callback:^(NSError *loadError, UIImage *loadedImage) {
|
||||
if (loadError) {
|
||||
errorCallback(@[[loadError localizedDescription]]);
|
||||
return;
|
||||
}
|
||||
[[RCTImageLoader assetsLibrary] writeImageToSavedPhotosAlbum:[loadedImage CGImage] metadata:nil completionBlock:^(NSURL *assetURL, NSError *saveError) {
|
||||
if (saveError) {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"Error saving cropped image: %@", saveError];
|
||||
RCTLogWarn(@"%@", errorMessage);
|
||||
errorCallback(@[errorMessage]);
|
||||
return;
|
||||
}
|
||||
successCallback(@[[assetURL absoluteString]]);
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)callCallback:(RCTResponseSenderBlock)callback withAssets:(NSArray *)assets hasNextPage:(BOOL)hasNextPage
|
||||
{
|
||||
if (![assets count]) {
|
||||
callback(@[@{
|
||||
@"edges": assets,
|
||||
@"page_info": @{
|
||||
@"has_next_page": @NO}
|
||||
}]);
|
||||
return;
|
||||
}
|
||||
callback(@[@{
|
||||
@"edges": assets,
|
||||
@"page_info": @{
|
||||
@"start_cursor": assets[0][@"node"][@"image"][@"uri"],
|
||||
@"end_cursor": assets[assets.count - 1][@"node"][@"image"][@"uri"],
|
||||
@"has_next_page": @(hasNextPage)}
|
||||
}]);
|
||||
}
|
||||
|
||||
- (void)getPhotos:(NSDictionary *)params callback:(RCTResponseSenderBlock)callback errorCallback:(RCTResponseSenderBlock)errorCallback
|
||||
{
|
||||
RCT_EXPORT();
|
||||
|
||||
NSUInteger first = [params[@"first"] integerValue];
|
||||
NSString *afterCursor = params[@"after"];
|
||||
NSString *groupTypesStr = params[@"groupTypes"];
|
||||
NSString *groupName = params[@"groupName"];
|
||||
ALAssetsGroupType groupTypes;
|
||||
if ([groupTypesStr isEqualToString:@"Album"]) {
|
||||
groupTypes = ALAssetsGroupAlbum;
|
||||
} else if ([groupTypesStr isEqualToString:@"All"]) {
|
||||
groupTypes = ALAssetsGroupAll;
|
||||
} else if ([groupTypesStr isEqualToString:@"Event"]) {
|
||||
groupTypes = ALAssetsGroupEvent;
|
||||
} else if ([groupTypesStr isEqualToString:@"Faces"]) {
|
||||
groupTypes = ALAssetsGroupFaces;
|
||||
} else if ([groupTypesStr isEqualToString:@"Library"]) {
|
||||
groupTypes = ALAssetsGroupLibrary;
|
||||
} else if ([groupTypesStr isEqualToString:@"PhotoStream"]) {
|
||||
groupTypes = ALAssetsGroupPhotoStream;
|
||||
} else {
|
||||
groupTypes = ALAssetsGroupSavedPhotos;
|
||||
}
|
||||
|
||||
BOOL __block foundAfter = NO;
|
||||
BOOL __block hasNextPage = NO;
|
||||
BOOL __block calledCallback = NO;
|
||||
NSMutableArray *assets = [[NSMutableArray alloc] init];
|
||||
|
||||
[[RCTImageLoader assetsLibrary] enumerateGroupsWithTypes:groupTypes usingBlock:^(ALAssetsGroup *group, BOOL *stopGroups) {
|
||||
if (group && (groupName == nil || [groupName isEqualToString:[group valueForProperty:ALAssetsGroupPropertyName]])) {
|
||||
[group setAssetsFilter:ALAssetsFilter.allPhotos];
|
||||
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stopAssets) {
|
||||
if (result) {
|
||||
NSString *uri = [(NSURL *)[result valueForProperty:ALAssetPropertyAssetURL] absoluteString];
|
||||
if (afterCursor && !foundAfter) {
|
||||
if ([afterCursor isEqualToString:uri]) {
|
||||
foundAfter = YES;
|
||||
}
|
||||
return; // Skip until we get to the first one
|
||||
}
|
||||
if (first == [assets count]) {
|
||||
*stopAssets = YES;
|
||||
*stopGroups = YES;
|
||||
hasNextPage = YES;
|
||||
RCTAssert(calledCallback == NO, @"Called the callback before we finished processing the results.");
|
||||
[self callCallback:callback withAssets:assets hasNextPage:hasNextPage];
|
||||
calledCallback = YES;
|
||||
return;
|
||||
}
|
||||
CGSize dimensions = [result defaultRepresentation].dimensions;
|
||||
CLLocation *loc = [result valueForProperty:ALAssetPropertyLocation];
|
||||
NSDate *date = [result valueForProperty:ALAssetPropertyDate];
|
||||
[assets addObject:@{
|
||||
@"node": @{
|
||||
@"type": [result valueForProperty:ALAssetPropertyType],
|
||||
@"group_name": [group valueForProperty:ALAssetsGroupPropertyName],
|
||||
@"image": @{
|
||||
@"uri": uri,
|
||||
@"height": @(dimensions.height),
|
||||
@"width": @(dimensions.width),
|
||||
@"isStored": @YES,
|
||||
},
|
||||
@"timestamp": @([date timeIntervalSince1970]),
|
||||
@"location": loc ?
|
||||
@{
|
||||
@"latitude": @(loc.coordinate.latitude),
|
||||
@"longitude": @(loc.coordinate.longitude),
|
||||
@"altitude": @(loc.altitude),
|
||||
@"heading": @(loc.course),
|
||||
@"speed": @(loc.speed),
|
||||
} : @{},
|
||||
}
|
||||
}];
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
// Sometimes the enumeration continues even if we set stop above, so we guard against calling the callback
|
||||
// multiple times here.
|
||||
if (!calledCallback) {
|
||||
[self callCallback:callback withAssets:assets hasNextPage:hasNextPage];
|
||||
calledCallback = YES;
|
||||
}
|
||||
}
|
||||
} failureBlock:^(NSError *error) {
|
||||
if (error.code != ALAssetsLibraryAccessUserDeniedError) {
|
||||
RCTLogError(@"Failure while iterating through asset groups %@", error);
|
||||
}
|
||||
errorCallback(@[error.description]);
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
|
@ -10,6 +10,8 @@
|
|||
1304D5AB1AA8C4A30002E2BE /* RCTStaticImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5A81AA8C4A30002E2BE /* RCTStaticImage.m */; };
|
||||
1304D5AC1AA8C4A30002E2BE /* RCTStaticImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5AA1AA8C4A30002E2BE /* RCTStaticImageManager.m */; };
|
||||
1304D5B21AA8C50D0002E2BE /* RCTGIFImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5B11AA8C50D0002E2BE /* RCTGIFImage.m */; };
|
||||
143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */; };
|
||||
143879381AAD32A300F088A5 /* RCTImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879371AAD32A300F088A5 /* RCTImageLoader.m */; };
|
||||
58B5118F1A9E6BD600147676 /* RCTImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 58B5118A1A9E6BD600147676 /* RCTImageDownloader.m */; };
|
||||
58B511901A9E6BD600147676 /* RCTNetworkImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 58B5118C1A9E6BD600147676 /* RCTNetworkImageView.m */; };
|
||||
58B511911A9E6BD600147676 /* RCTNetworkImageViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58B5118E1A9E6BD600147676 /* RCTNetworkImageViewManager.m */; };
|
||||
|
@ -34,6 +36,10 @@
|
|||
1304D5AA1AA8C4A30002E2BE /* RCTStaticImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStaticImageManager.m; sourceTree = "<group>"; };
|
||||
1304D5B01AA8C50D0002E2BE /* RCTGIFImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTGIFImage.h; sourceTree = "<group>"; };
|
||||
1304D5B11AA8C50D0002E2BE /* RCTGIFImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTGIFImage.m; sourceTree = "<group>"; };
|
||||
143879331AAD238D00F088A5 /* RCTCameraRollManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTCameraRollManager.h; sourceTree = "<group>"; };
|
||||
143879341AAD238D00F088A5 /* RCTCameraRollManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCameraRollManager.m; sourceTree = "<group>"; };
|
||||
143879361AAD32A300F088A5 /* RCTImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageLoader.h; sourceTree = "<group>"; };
|
||||
143879371AAD32A300F088A5 /* RCTImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoader.m; sourceTree = "<group>"; };
|
||||
58B5115D1A9E6B3D00147676 /* libRCTImage.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTImage.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
58B511891A9E6BD600147676 /* RCTImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageDownloader.h; sourceTree = "<group>"; };
|
||||
58B5118A1A9E6BD600147676 /* RCTImageDownloader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageDownloader.m; sourceTree = "<group>"; };
|
||||
|
@ -57,6 +63,10 @@
|
|||
58B511541A9E6B3D00147676 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
143879361AAD32A300F088A5 /* RCTImageLoader.h */,
|
||||
143879371AAD32A300F088A5 /* RCTImageLoader.m */,
|
||||
143879331AAD238D00F088A5 /* RCTCameraRollManager.h */,
|
||||
143879341AAD238D00F088A5 /* RCTCameraRollManager.m */,
|
||||
1304D5B01AA8C50D0002E2BE /* RCTGIFImage.h */,
|
||||
1304D5B11AA8C50D0002E2BE /* RCTGIFImage.m */,
|
||||
58B511891A9E6BD600147676 /* RCTImageDownloader.h */,
|
||||
|
@ -142,6 +152,8 @@
|
|||
1304D5AC1AA8C4A30002E2BE /* RCTStaticImageManager.m in Sources */,
|
||||
58B511901A9E6BD600147676 /* RCTNetworkImageView.m in Sources */,
|
||||
1304D5B21AA8C50D0002E2BE /* RCTGIFImage.m in Sources */,
|
||||
143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */,
|
||||
143879381AAD32A300F088A5 /* RCTImageLoader.m in Sources */,
|
||||
1304D5AB1AA8C4A30002E2BE /* RCTStaticImage.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class ALAssetsLibrary;
|
||||
@class UIImage;
|
||||
|
||||
@interface RCTImageLoader : NSObject
|
||||
|
||||
+ (ALAssetsLibrary *)assetsLibrary;
|
||||
+ (void)loadImageWithTag:(NSString *)tag callback:(void (^)(NSError *error, UIImage *image))callback;
|
||||
|
||||
@end
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTImageLoader.h"
|
||||
|
||||
#import <AssetsLibrary/AssetsLibrary.h>
|
||||
#import <Photos/PHAsset.h>
|
||||
#import <Photos/PHFetchResult.h>
|
||||
#import <Photos/PHImageManager.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTImageDownloader.h"
|
||||
#import "RCTLog.h"
|
||||
|
||||
NSError *errorWithMessage(NSString *message) {
|
||||
NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: message};
|
||||
NSError *error = [[NSError alloc] initWithDomain:RCTErrorDomain code:0 userInfo:errorInfo];
|
||||
return error;
|
||||
}
|
||||
|
||||
@implementation RCTImageLoader
|
||||
|
||||
+ (ALAssetsLibrary *)assetsLibrary
|
||||
{
|
||||
static ALAssetsLibrary *assetsLibrary = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
assetsLibrary = [[ALAssetsLibrary alloc] init];
|
||||
});
|
||||
return assetsLibrary;
|
||||
}
|
||||
|
||||
+ (void)loadImageWithTag:(NSString *)imageTag callback:(void (^)(NSError *error, UIImage *image))callback
|
||||
{
|
||||
if ([imageTag hasPrefix:@"assets-library"]) {
|
||||
[[RCTImageLoader assetsLibrary] assetForURL:[NSURL URLWithString:imageTag] resultBlock:^(ALAsset *asset) {
|
||||
if (asset) {
|
||||
ALAssetRepresentation *representation = [asset defaultRepresentation];
|
||||
ALAssetOrientation orientation = [representation orientation];
|
||||
UIImage *image = [UIImage imageWithCGImage:[representation fullResolutionImage] scale:1.0f orientation:(UIImageOrientation)orientation];
|
||||
callback(nil, image);
|
||||
} else {
|
||||
NSString *errorText = [NSString stringWithFormat:@"Failed to load asset at URL %@ with no error message.", imageTag];
|
||||
NSError *error = errorWithMessage(errorText);
|
||||
callback(error, nil);
|
||||
}
|
||||
} failureBlock:^(NSError *loadError) {
|
||||
NSString *errorText = [NSString stringWithFormat:@"Failed to load asset at URL %@.\niOS Error: %@", imageTag, loadError];
|
||||
NSError *error = errorWithMessage(errorText);
|
||||
callback(error, nil);
|
||||
}];
|
||||
} else if ([imageTag hasPrefix:@"ph://"]) {
|
||||
// Using PhotoKit for iOS 8+
|
||||
// 'ph://' prefix is used by FBMediaKit to differentiate between assets-library. It is prepended to the local ID so that it
|
||||
// is in the form of NSURL which is what assets-library is based on.
|
||||
// This means if we use any FB standard photo picker, we will get this prefix =(
|
||||
NSString *phAssetID = [imageTag substringFromIndex:[@"ph://" length]];
|
||||
PHFetchResult *results = [PHAsset fetchAssetsWithLocalIdentifiers:@[phAssetID] options:nil];
|
||||
if (results.count == 0) {
|
||||
NSString *errorText = [NSString stringWithFormat:@"Failed to fetch PHAsset with local identifier %@ with no error message.", phAssetID];
|
||||
NSError *error = errorWithMessage(errorText);
|
||||
callback(error, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
PHAsset *asset = [results firstObject];
|
||||
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:nil resultHandler:^(UIImage *result, NSDictionary *info) {
|
||||
if (result) {
|
||||
callback(nil, result);
|
||||
} else {
|
||||
NSString *errorText = [NSString stringWithFormat:@"Failed to load PHAsset with local identifier %@ with no error message.", phAssetID];
|
||||
NSError *error = errorWithMessage(errorText);
|
||||
callback(error, nil);
|
||||
return;
|
||||
}
|
||||
}];
|
||||
} else if ([imageTag hasPrefix:@"http"]) {
|
||||
NSURL *url = [NSURL URLWithString:imageTag];
|
||||
if (!url) {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"Invalid URL: %@", imageTag];
|
||||
callback(errorWithMessage(errorMessage), nil);
|
||||
return;
|
||||
}
|
||||
[[RCTImageDownloader sharedInstance] downloadDataForURL:url block:^(NSData *data, NSError *error) {
|
||||
if (error) {
|
||||
callback(error, nil);
|
||||
} else {
|
||||
callback(nil, [UIImage imageWithData:data]);
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"Unrecognized tag protocol: %@", imageTag];
|
||||
NSError *error = errorWithMessage(errorMessage);
|
||||
callback(error, nil);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -24,7 +24,7 @@
|
|||
// Apply trilinear filtering to smooth out mis-sized images
|
||||
self.layer.minificationFilter = kCAFilterTrilinear;
|
||||
self.layer.magnificationFilter = kCAFilterTrilinear;
|
||||
|
||||
|
||||
super.image = image;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTGIFImage.h"
|
||||
#import "RCTImageLoader.h"
|
||||
#import "RCTStaticImage.h"
|
||||
|
||||
@implementation RCTStaticImageManager
|
||||
|
@ -39,5 +40,19 @@ RCT_CUSTOM_VIEW_PROPERTY(tintColor, RCTStaticImage *)
|
|||
view.tintColor = defaultView.tintColor;
|
||||
}
|
||||
}
|
||||
RCT_CUSTOM_VIEW_PROPERTY(imageTag, RCTStaticImage *)
|
||||
{
|
||||
if (json) {
|
||||
[RCTImageLoader loadImageWithTag:[RCTConvert NSString:json] callback:^(NSError *error, UIImage *image) {
|
||||
if (error) {
|
||||
RCTLogWarn(@"%@", error.localizedDescription);
|
||||
} else {
|
||||
view.image = image;
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
view.image = defaultView.image;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule PickerIOS
|
||||
*
|
||||
* This is a controlled component version of RKPickerIOS
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
module.exports = require('UnimplementedView');
|
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule PickerIOS
|
||||
*
|
||||
* This is a controlled component version of RKPickerIOS
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var React = require('React');
|
||||
var ReactChildren = require('ReactChildren');
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
var RKPickerIOSConsts = require('NativeModules').RKUIManager.RCTPicker.Constants;
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var View = require('View');
|
||||
|
||||
var createReactIOSNativeComponentClass =
|
||||
require('createReactIOSNativeComponentClass');
|
||||
var merge = require('merge');
|
||||
|
||||
var PICKER = 'picker';
|
||||
|
||||
var PickerIOS = React.createClass({
|
||||
mixins: [NativeMethodsMixin],
|
||||
|
||||
propTypes: {
|
||||
onValueChange: React.PropTypes.func,
|
||||
selectedValue: React.PropTypes.any, // string or integer basically
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this._stateFromProps(this.props);
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
this.setState(this._stateFromProps(nextProps));
|
||||
},
|
||||
|
||||
// Translate PickerIOS prop and children into stuff that RKPickerIOS understands.
|
||||
_stateFromProps: function(props) {
|
||||
var selectedIndex = 0;
|
||||
var items = [];
|
||||
ReactChildren.forEach(props.children, function (child, index) {
|
||||
if (child.props.value === props.selectedValue) {
|
||||
selectedIndex = index;
|
||||
}
|
||||
items.push({value: child.props.value, label: child.props.label});
|
||||
});
|
||||
return {selectedIndex, items};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<View style={this.props.style}>
|
||||
<RKPickerIOS
|
||||
ref={PICKER}
|
||||
style={styles.rkPickerIOS}
|
||||
items={this.state.items}
|
||||
selectedIndex={this.state.selectedIndex}
|
||||
onChange={this._onChange}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
|
||||
_onChange: function(event) {
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(event);
|
||||
}
|
||||
if (this.props.onValueChange) {
|
||||
this.props.onValueChange(event.nativeEvent.newValue);
|
||||
}
|
||||
|
||||
// The picker is a controlled component. This means we expect the
|
||||
// on*Change handlers to be in charge of updating our
|
||||
// `selectedValue` prop. That way they can also
|
||||
// disallow/undo/mutate the selection of certain values. In other
|
||||
// words, the embedder of this component should be the source of
|
||||
// truth, not the native component.
|
||||
if (this.state.selectedIndex !== event.nativeEvent.newIndex) {
|
||||
this.refs[PICKER].setNativeProps({
|
||||
selectedIndex: this.state.selectedIndex
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
PickerIOS.Item = React.createClass({
|
||||
propTypes: {
|
||||
value: React.PropTypes.any, // string or integer basically
|
||||
label: React.PropTypes.string,
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// These items don't get rendered directly.
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
rkPickerIOS: {
|
||||
// The picker will conform to whatever width is given, but we do
|
||||
// have to set the component's height explicitly on the
|
||||
// surrounding view to ensure it gets rendered.
|
||||
height: RKPickerIOSConsts.ComponentHeight,
|
||||
},
|
||||
});
|
||||
|
||||
var rkPickerIOSAttributes = merge(ReactIOSViewAttributes.UIView, {
|
||||
items: true,
|
||||
selectedIndex: true,
|
||||
});
|
||||
|
||||
var RKPickerIOS = createReactIOSNativeComponentClass({
|
||||
validAttributes: rkPickerIOSAttributes,
|
||||
uiViewClassName: 'RCTPicker',
|
||||
});
|
||||
|
||||
module.exports = PickerIOS;
|
|
@ -74,6 +74,7 @@ var ReactIOS = {
|
|||
count: ReactChildren.count,
|
||||
only: onlyChild
|
||||
},
|
||||
Component: ReactComponent,
|
||||
PropTypes: ReactPropTypes,
|
||||
createClass: ReactClass.createClass,
|
||||
createElement: createElement,
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule groupByEveryN
|
||||
*/
|
||||
|
||||
/**
|
||||
* Useful method to split an array into groups of the same number of elements.
|
||||
* You can use it to generate grids, rows, pages...
|
||||
*
|
||||
* If the input length is not a multiple of the count, it'll fill the last
|
||||
* array with null so you can display a placeholder.
|
||||
*
|
||||
* Example:
|
||||
* groupByEveryN([1, 2, 3, 4, 5], 3)
|
||||
* => [[1, 2, 3], [4, 5, null]]
|
||||
*
|
||||
* groupByEveryN([1, 2, 3], 2).map(elems => {
|
||||
* return <Row>{elems.map(elem => <Elem>{elem}</Elem>)}</Row>;
|
||||
* })
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
function groupByEveryN(array, n) {
|
||||
var result = [];
|
||||
var temp = [];
|
||||
|
||||
for (var i = 0; i < array.length; ++i) {
|
||||
if (i > 0 && i % n === 0) {
|
||||
result.push(temp);
|
||||
temp = [];
|
||||
}
|
||||
temp.push(array[i]);
|
||||
}
|
||||
|
||||
if (temp.length > 0) {
|
||||
while (temp.length !== n) {
|
||||
temp.push(null);
|
||||
}
|
||||
result.push(temp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = groupByEveryN;
|
|
@ -7,14 +7,18 @@
|
|||
|
||||
var ReactNative = {
|
||||
...require('React'),
|
||||
Animation: require('Animation'),
|
||||
AppRegistry: require('AppRegistry'),
|
||||
CameraRoll: require('CameraRoll'),
|
||||
DatePickerIOS: require('DatePickerIOS'),
|
||||
ExpandingText: require('ExpandingText'),
|
||||
MapView: require('MapView'),
|
||||
Image: require('Image'),
|
||||
LayoutAnimation: require('LayoutAnimation'),
|
||||
ListView: require('ListView'),
|
||||
ListViewDataSource: require('ListViewDataSource'),
|
||||
NavigatorIOS: require('NavigatorIOS'),
|
||||
PickerIOS: require('PickerIOS'),
|
||||
PixelRatio: require('PixelRatio'),
|
||||
ScrollView: require('ScrollView'),
|
||||
ActivityIndicatorIOS: require('ActivityIndicatorIOS'),
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#define RCTErrorDomain @"RCTErrorDomain"
|
||||
|
||||
#define RCTAssert(condition, message, ...) _RCTAssert(condition, message, ##__VA_ARGS__)
|
||||
#define RCTCAssert(condition, message, ...) _RCTCAssert(condition, message, ##__VA_ARGS__)
|
||||
#define RCTAssert(condition, message, ...) _RCTAssert((condition) != 0, message, ##__VA_ARGS__)
|
||||
#define RCTCAssert(condition, message, ...) _RCTCAssert((condition) != 0, message, ##__VA_ARGS__)
|
||||
|
||||
typedef void (^RCTAssertFunction)(BOOL condition, NSString *message, ...);
|
||||
|
||||
|
|
|
@ -88,6 +88,12 @@ BOOL RCTSetProperty(id target, NSString *keypath, id json);
|
|||
*/
|
||||
BOOL RCTCopyProperty(id target, id source, NSString *keypath);
|
||||
|
||||
/**
|
||||
* This function attempts to convert a JSON value to an object that can be used
|
||||
* in KVC with the specific target and key path.
|
||||
*/
|
||||
id RCTConvertValue(id target, NSString *keypath, id json);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -608,7 +608,7 @@ static NSString *RCTGuessTypeEncoding(id target, NSString *key, id value, NSStri
|
|||
return nil;
|
||||
}
|
||||
|
||||
static NSDictionary *RCTConvertValue(id value, NSString *encoding)
|
||||
static id RCTConvertValueWithEncoding(id value, NSString *encoding)
|
||||
{
|
||||
static NSDictionary *converters = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
|
@ -690,18 +690,7 @@ static NSDictionary *RCTConvertValue(id value, NSString *encoding)
|
|||
return converter ? converter(value) : value;
|
||||
}
|
||||
|
||||
BOOL RCTSetProperty(id target, NSString *keypath, id value)
|
||||
{
|
||||
// Split keypath
|
||||
NSArray *parts = [keypath componentsSeparatedByString:@"."];
|
||||
NSString *key = [parts lastObject];
|
||||
for (NSUInteger i = 0; i < parts.count - 1; i++) {
|
||||
target = [target valueForKey:parts[i]];
|
||||
if (!target) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
static NSString *RCTPropertyEncoding(id target, NSString *key, id value) {
|
||||
// Check target class for property definition
|
||||
NSString *encoding = nil;
|
||||
objc_property_t property = class_getProperty([target class], [key UTF8String]);
|
||||
|
@ -720,7 +709,7 @@ BOOL RCTSetProperty(id target, NSString *keypath, id value)
|
|||
[key substringFromIndex:1]]);
|
||||
|
||||
if (![target respondsToSelector:setter]) {
|
||||
return NO;
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Get type of first method argument
|
||||
|
@ -730,17 +719,92 @@ BOOL RCTSetProperty(id target, NSString *keypath, id value)
|
|||
encoding = @(typeEncoding);
|
||||
free(typeEncoding);
|
||||
}
|
||||
|
||||
if (encoding.length == 0 || [encoding isEqualToString:@(@encode(id))]) {
|
||||
// Not enough info about the type encoding to be useful, so
|
||||
// try to guess the type from the value and property name
|
||||
encoding = RCTGuessTypeEncoding(target, key, value, encoding);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (encoding.length == 0 || [encoding isEqualToString:@(@encode(id))]) {
|
||||
// Not enough info about the type encoding to be useful, so
|
||||
// try to guess the type from the value and property name
|
||||
encoding = RCTGuessTypeEncoding(target, key, value, encoding);
|
||||
return encoding;
|
||||
}
|
||||
|
||||
static id RCTConvertValueWithExplicitEncoding(id target, NSString *key, id json, NSString *encoding) {
|
||||
if (!encoding) return nil;
|
||||
|
||||
// Special case for numeric encodings, which may be enums
|
||||
if ([json isKindOfClass:[NSString class]] &&
|
||||
[@"iIsSlLqQ" rangeOfString:[encoding substringToIndex:1]].length) {
|
||||
|
||||
/**
|
||||
* NOTE: the property names below may seem weird, but it's
|
||||
* because they are tested as case-sensitive suffixes, so
|
||||
* "apitalizationType" will match any of the following
|
||||
*
|
||||
* - capitalizationType
|
||||
* - autocapitalizationType
|
||||
* - autoCapitalizationType
|
||||
* - titleCapitalizationType
|
||||
* - etc.
|
||||
*/
|
||||
static NSDictionary *converters = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
converters =
|
||||
@{
|
||||
@"apitalizationType": ^(id val) {
|
||||
return [RCTConvert UITextAutocapitalizationType:val];
|
||||
},
|
||||
@"eyboardType": ^(id val) {
|
||||
return [RCTConvert UIKeyboardType:val];
|
||||
},
|
||||
@"extAlignment": ^(id val) {
|
||||
return [RCTConvert NSTextAlignment:val];
|
||||
},
|
||||
@"ointerEvents": ^(id val) {
|
||||
return [RCTConvert RCTPointerEvents:val];
|
||||
},
|
||||
};
|
||||
});
|
||||
for (NSString *subkey in converters) {
|
||||
if ([key hasSuffix:subkey]) {
|
||||
NSInteger (^converter)(NSString *) = converters[subkey];
|
||||
json = @(converter(json));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RCTConvertValueWithEncoding(json, encoding);
|
||||
}
|
||||
|
||||
id RCTConvertValue(id target, NSString *key, id json) {
|
||||
NSString *encoding = RCTPropertyEncoding(target, key, json);
|
||||
return RCTConvertValueWithExplicitEncoding(target, key, json, encoding);
|
||||
}
|
||||
|
||||
BOOL RCTSetProperty(id target, NSString *keypath, id value)
|
||||
{
|
||||
// Split keypath
|
||||
NSArray *parts = [keypath componentsSeparatedByString:@"."];
|
||||
NSString *key = [parts lastObject];
|
||||
for (NSUInteger i = 0; i < parts.count - 1; i++) {
|
||||
target = [target valueForKey:parts[i]];
|
||||
if (!target) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
NSString *encoding = RCTPropertyEncoding(target, key, value);
|
||||
if (!encoding) return NO;
|
||||
|
||||
value = RCTConvertValueWithExplicitEncoding(target, keypath, value, encoding);
|
||||
|
||||
// Special case for numeric encodings, which may be enums
|
||||
if ([value isKindOfClass:[NSString class]] &&
|
||||
[@"iIsSlLqQ" rangeOfString:[encoding substringToIndex:1]].length) {
|
||||
[@"iIsSlLqQ" rangeOfString:[encoding substringToIndex:1]].location != NSNotFound) {
|
||||
|
||||
/**
|
||||
* NOTE: the property names below may seem weird, but it's
|
||||
|
@ -798,15 +862,15 @@ BOOL RCTSetProperty(id target, NSString *keypath, id value)
|
|||
});
|
||||
|
||||
void (^block)(UITextField *f, NSInteger v) = specialCases[key];
|
||||
if (block)
|
||||
{
|
||||
if (block) {
|
||||
block(target, [value integerValue]);
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
// Set converted value
|
||||
[target setValue:RCTConvertValue(value, encoding) forKey:key];
|
||||
[target setValue:value forKey:key];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,15 @@
|
|||
|
||||
#import "RCTUtils.h"
|
||||
|
||||
#import <CommonCrypto/CommonCrypto.h>
|
||||
#import <mach/mach_time.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <CommonCrypto/CommonCrypto.h>
|
||||
|
||||
#import "RCTLog.h"
|
||||
|
||||
NSString *RCTJSONStringify(id jsonObject, NSError **error)
|
||||
{
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonObject options:0 error:error];
|
||||
|
@ -15,7 +19,14 @@ NSString *RCTJSONStringify(id jsonObject, NSError **error)
|
|||
|
||||
id RCTJSONParse(NSString *jsonString, NSError **error)
|
||||
{
|
||||
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (!jsonString) {
|
||||
return nil;
|
||||
}
|
||||
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO];
|
||||
if (!jsonData) {
|
||||
RCTLog(@"RCTJSONParse received the following string, which could not be losslessly converted to UTF8 data: '%@'", jsonString);
|
||||
jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
|
||||
}
|
||||
return [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:error];
|
||||
}
|
||||
|
||||
|
@ -63,7 +74,7 @@ CGSize RCTScreenSize()
|
|||
size = [UIScreen mainScreen].bounds.size;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -93,7 +104,7 @@ NSTimeInterval RCTTGetAbsoluteTime(void)
|
|||
int ret = mach_timebase_info(&tb_info);
|
||||
assert(0 == ret);
|
||||
});
|
||||
|
||||
|
||||
uint64_t timeInNanoseconds = (mach_absolute_time() * tb_info.numer) / tb_info.denom;
|
||||
return ((NSTimeInterval)timeInNanoseconds) / 1000000;
|
||||
}
|
||||
|
@ -103,11 +114,11 @@ void RCTSwapClassMethods(Class cls, SEL original, SEL replacement)
|
|||
Method originalMethod = class_getClassMethod(cls, original);
|
||||
IMP originalImplementation = method_getImplementation(originalMethod);
|
||||
const char *originalArgTypes = method_getTypeEncoding(originalMethod);
|
||||
|
||||
|
||||
Method replacementMethod = class_getClassMethod(cls, replacement);
|
||||
IMP replacementImplementation = method_getImplementation(replacementMethod);
|
||||
const char *replacementArgTypes = method_getTypeEncoding(replacementMethod);
|
||||
|
||||
|
||||
if (class_addMethod(cls, original, replacementImplementation, replacementArgTypes))
|
||||
{
|
||||
class_replaceMethod(cls, replacement, originalImplementation, originalArgTypes);
|
||||
|
@ -123,11 +134,11 @@ void RCTSwapInstanceMethods(Class cls, SEL original, SEL replacement)
|
|||
Method originalMethod = class_getInstanceMethod(cls, original);
|
||||
IMP originalImplementation = method_getImplementation(originalMethod);
|
||||
const char *originalArgTypes = method_getTypeEncoding(originalMethod);
|
||||
|
||||
|
||||
Method replacementMethod = class_getInstanceMethod(cls, replacement);
|
||||
IMP replacementImplementation = method_getImplementation(replacementMethod);
|
||||
const char *replacementArgTypes = method_getTypeEncoding(replacementMethod);
|
||||
|
||||
|
||||
if (class_addMethod(cls, original, replacementImplementation, replacementArgTypes))
|
||||
{
|
||||
class_replaceMethod(cls, replacement, originalImplementation, originalArgTypes);
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "RCTBridgeModule.h"
|
||||
|
||||
@interface RCTAnimationManager : NSObject <RCTBridgeModule>
|
||||
|
||||
@end
|
|
@ -0,0 +1,203 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTAnimationManager.h"
|
||||
|
||||
#import <Accelerate/Accelerate.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTSparseArray.h"
|
||||
#import "RCTUIManager.h"
|
||||
|
||||
#if CGFLOAT_IS_DOUBLE
|
||||
#define CG_APPEND(PREFIX, SUFFIX_F, SUFFIX_D) PREFIX##SUFFIX_D
|
||||
#else
|
||||
#define CG_APPEND(PREFIX, SUFFIX_F, SUFFIX_D) PREFIX##SUFFIX_F
|
||||
#endif
|
||||
|
||||
@implementation RCTAnimationManager
|
||||
{
|
||||
RCTSparseArray *_animationRegistry; // Main thread only; animation tag -> view tag
|
||||
}
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_animationRegistry = [[RCTSparseArray alloc] init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id (^)(CGFloat))interpolateFrom:(CGFloat[])fromArray to:(CGFloat[])toArray count:(NSUInteger)count typeName:(const char *)typeName
|
||||
{
|
||||
if (count == 1) {
|
||||
CGFloat from = *fromArray, to = *toArray, delta = to - from;
|
||||
return ^(CGFloat t) {
|
||||
return @(from + t * delta);
|
||||
};
|
||||
}
|
||||
|
||||
CG_APPEND(vDSP_vsub,,D)(fromArray, 1, toArray, 1, toArray, 1, count);
|
||||
|
||||
const size_t size = count * sizeof(CGFloat);
|
||||
NSData *deltaData = [NSData dataWithBytes:toArray length:size];
|
||||
NSData *fromData = [NSData dataWithBytes:fromArray length:size];
|
||||
|
||||
return ^(CGFloat t) {
|
||||
const CGFloat *delta = deltaData.bytes;
|
||||
const CGFloat *fromArray = fromData.bytes;
|
||||
|
||||
CGFloat value[count];
|
||||
CG_APPEND(vDSP_vma,,D)(delta, 1, &t, 0, fromArray, 1, value, 1, count);
|
||||
return [NSValue valueWithBytes:value objCType:typeName];
|
||||
};
|
||||
}
|
||||
|
||||
- (void)startAnimationForTag:(NSNumber *)reactTag animationTag:(NSNumber *)animationTag duration:(double)duration delay:(double)delay easingSample:(NSArray *)easingSample properties:(NSDictionary *)properties
|
||||
{
|
||||
RCT_EXPORT(startAnimation);
|
||||
|
||||
__weak RCTAnimationManager *weakSelf = self;
|
||||
[_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||
RCTAnimationManager *strongSelf = weakSelf;
|
||||
|
||||
UIView *view = viewRegistry[reactTag];
|
||||
if (!view) {
|
||||
RCTLogWarn(@"React tag %@ is not registered with the view registry", reactTag);
|
||||
return;
|
||||
}
|
||||
|
||||
[properties enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
|
||||
NSValue *toValue = nil;
|
||||
if ([key isEqualToString:@"scaleXY"]) {
|
||||
key = @"transform.scale";
|
||||
toValue = obj[0];
|
||||
} else if ([obj respondsToSelector:@selector(count)]) {
|
||||
switch ([obj count]) {
|
||||
case 2:
|
||||
if ([obj respondsToSelector:@selector(objectForKey:)] && [obj objectForKey:@"w"]) {
|
||||
toValue = [NSValue valueWithCGSize:[RCTConvert CGSize:obj]];
|
||||
} else {
|
||||
toValue = [NSValue valueWithCGPoint:[RCTConvert CGPoint:obj]];
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
toValue = [NSValue valueWithCGRect:[RCTConvert CGRect:obj]];
|
||||
break;
|
||||
case 16:
|
||||
toValue = [NSValue valueWithCGAffineTransform:[RCTConvert CGAffineTransform:obj]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!toValue) toValue = obj;
|
||||
|
||||
const char *typeName = toValue.objCType;
|
||||
|
||||
size_t count;
|
||||
switch (typeName[0]) {
|
||||
case 'i':
|
||||
case 'I':
|
||||
case 's':
|
||||
case 'S':
|
||||
case 'l':
|
||||
case 'L':
|
||||
case 'q':
|
||||
case 'Q':
|
||||
count = 1;
|
||||
break;
|
||||
|
||||
default: {
|
||||
NSUInteger size;
|
||||
NSGetSizeAndAlignment(typeName, &size, NULL);
|
||||
count = size / sizeof(CGFloat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CGFloat toFields[count];
|
||||
|
||||
switch (typeName[0]) {
|
||||
#define CASE(encoding, type) \
|
||||
case encoding: { \
|
||||
type value; \
|
||||
[toValue getValue:&value]; \
|
||||
toFields[0] = value; \
|
||||
break; \
|
||||
}
|
||||
|
||||
CASE('i', int)
|
||||
CASE('I', unsigned int)
|
||||
CASE('s', short)
|
||||
CASE('S', unsigned short)
|
||||
CASE('l', long)
|
||||
CASE('L', unsigned long)
|
||||
CASE('q', long long)
|
||||
CASE('Q', unsigned long long)
|
||||
|
||||
#undef CASE
|
||||
|
||||
default:
|
||||
[toValue getValue:toFields];
|
||||
break;
|
||||
}
|
||||
|
||||
NSValue *fromValue = [view.layer.presentationLayer valueForKeyPath:key];
|
||||
CGFloat fromFields[count];
|
||||
[fromValue getValue:fromFields];
|
||||
|
||||
id (^interpolationBlock)(CGFloat t) = [strongSelf interpolateFrom:fromFields to:toFields count:count typeName:typeName];
|
||||
|
||||
NSMutableArray *sampledValues = [NSMutableArray arrayWithCapacity:easingSample.count];
|
||||
for (NSNumber *sample in easingSample) {
|
||||
CGFloat t = sample.CG_APPEND(, floatValue, doubleValue);
|
||||
[sampledValues addObject:interpolationBlock(t)];
|
||||
}
|
||||
|
||||
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:key];
|
||||
animation.beginTime = CACurrentMediaTime() + delay / 1000.0;
|
||||
animation.duration = duration / 1000.0;
|
||||
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
|
||||
animation.values = sampledValues;
|
||||
|
||||
[view.layer setValue:toValue forKey:key];
|
||||
|
||||
NSString *animationKey = [NSString stringWithFormat:@"RCT.%@.%@", animationTag, key];
|
||||
[view.layer addAnimation:animation forKey:animationKey];
|
||||
}];
|
||||
|
||||
strongSelf->_animationRegistry[animationTag] = reactTag;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)stopAnimation:(NSNumber *)animationTag
|
||||
{
|
||||
RCT_EXPORT(stopAnimation);
|
||||
|
||||
__weak RCTAnimationManager *weakSelf = self;
|
||||
[_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||
RCTAnimationManager *strongSelf = weakSelf;
|
||||
|
||||
NSNumber *reactTag = strongSelf->_animationRegistry[animationTag];
|
||||
if (!reactTag) return;
|
||||
|
||||
UIView *view = viewRegistry[reactTag];
|
||||
for (NSString *animationKey in view.layer.animationKeys) {
|
||||
if ([animationKey hasPrefix:@"RCT"]) {
|
||||
NSRange periodLocation = [animationKey rangeOfString:@"." options:0 range:NSMakeRange(3, animationKey.length - 3)];
|
||||
if (periodLocation.location != NSNotFound) {
|
||||
NSInteger integerTag = [[animationKey substringWithRange:NSMakeRange(3, periodLocation.location)] integerValue];
|
||||
if (animationTag.integerValue == integerTag) {
|
||||
[view.layer removeAnimationForKey:animationKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf->_animationRegistry[animationTag] = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
|
@ -2,24 +2,25 @@
|
|||
|
||||
#import "RCTUIManager.h"
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <objc/message.h>
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
#import "Layout.h"
|
||||
#import "RCTAnimationType.h"
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTRootView.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTNavigator.h"
|
||||
#import "RCTRootView.h"
|
||||
#import "RCTScrollableProtocol.h"
|
||||
#import "RCTShadowView.h"
|
||||
#import "RCTSparseArray.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "RCTView.h"
|
||||
#import "RCTViewNodeProtocol.h"
|
||||
#import "RCTViewManager.h"
|
||||
#import "RCTViewNodeProtocol.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
typedef void (^react_view_node_block_t)(id<RCTViewNodeProtocol>);
|
||||
|
|
|
@ -34,13 +34,18 @@
|
|||
13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */; };
|
||||
13E067571A70F44B002CDEE1 /* RCTView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067501A70F44B002CDEE1 /* RCTView.m */; };
|
||||
13E067591A70F44B002CDEE1 /* UIView+ReactKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067541A70F44B002CDEE1 /* UIView+ReactKit.m */; };
|
||||
58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */; };
|
||||
14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F362081AABD06A001CE568 /* RCTSwitch.m */; };
|
||||
14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */; };
|
||||
14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */; };
|
||||
14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 14435CE21AAC4AE100FC20F4 /* RCTMap.m */; };
|
||||
14435CE61AAC4AE100FC20F4 /* RCTMapManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14435CE41AAC4AE100FC20F4 /* RCTMapManager.m */; };
|
||||
58114A161AAE854800E7D092 /* RCTPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A131AAE854800E7D092 /* RCTPicker.m */; };
|
||||
58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A151AAE854800E7D092 /* RCTPickerManager.m */; };
|
||||
58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */; };
|
||||
830A229E1A66C68A008503DA /* RCTRootView.m in Sources */ = {isa = PBXBuildFile; fileRef = 830A229D1A66C68A008503DA /* RCTRootView.m */; };
|
||||
830BA4551A8E3BDA00D53203 /* RCTCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 830BA4541A8E3BDA00D53203 /* RCTCache.m */; };
|
||||
832348161A77A5AA00B55238 /* Layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FC71A68125100A75B9A /* Layout.c */; };
|
||||
83C911101AAE6521001323A3 /* RCTAnimationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 83C9110F1AAE6521001323A3 /* RCTAnimationManager.m */; };
|
||||
83CBBA511A601E3B00E9B192 /* RCTAssert.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA4B1A601E3B00E9B192 /* RCTAssert.m */; };
|
||||
83CBBA521A601E3B00E9B192 /* RCTLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA4E1A601E3B00E9B192 /* RCTLog.m */; };
|
||||
83CBBA531A601E3B00E9B192 /* RCTUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA501A601E3B00E9B192 /* RCTUtils.m */; };
|
||||
|
@ -126,14 +131,22 @@
|
|||
13E067531A70F44B002CDEE1 /* UIView+ReactKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+ReactKit.h"; sourceTree = "<group>"; };
|
||||
13E067541A70F44B002CDEE1 /* UIView+ReactKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+ReactKit.m"; sourceTree = "<group>"; };
|
||||
13EFFCCF1A98E6FE002607DC /* RCTJSMethodRegistrar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSMethodRegistrar.h; sourceTree = "<group>"; };
|
||||
58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDatePickerManager.m; sourceTree = "<group>"; };
|
||||
58C571C01AA56C1900CDF9C8 /* RCTDatePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDatePickerManager.h; sourceTree = "<group>"; };
|
||||
14F362071AABD06A001CE568 /* RCTSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSwitch.h; sourceTree = "<group>"; };
|
||||
14F362081AABD06A001CE568 /* RCTSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSwitch.m; sourceTree = "<group>"; };
|
||||
14F362091AABD06A001CE568 /* RCTSwitchManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSwitchManager.h; sourceTree = "<group>"; };
|
||||
14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSwitchManager.m; sourceTree = "<group>"; };
|
||||
14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSliderManager.h; sourceTree = "<group>"; };
|
||||
14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSliderManager.m; sourceTree = "<group>"; };
|
||||
14435CE11AAC4AE100FC20F4 /* RCTMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMap.h; sourceTree = "<group>"; };
|
||||
14435CE21AAC4AE100FC20F4 /* RCTMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMap.m; sourceTree = "<group>"; };
|
||||
14435CE31AAC4AE100FC20F4 /* RCTMapManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMapManager.h; sourceTree = "<group>"; };
|
||||
14435CE41AAC4AE100FC20F4 /* RCTMapManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapManager.m; sourceTree = "<group>"; };
|
||||
58114A121AAE854800E7D092 /* RCTPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPicker.h; sourceTree = "<group>"; };
|
||||
58114A131AAE854800E7D092 /* RCTPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPicker.m; sourceTree = "<group>"; };
|
||||
58114A141AAE854800E7D092 /* RCTPickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPickerManager.h; sourceTree = "<group>"; };
|
||||
58114A151AAE854800E7D092 /* RCTPickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPickerManager.m; sourceTree = "<group>"; };
|
||||
58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDatePickerManager.m; sourceTree = "<group>"; };
|
||||
58C571C01AA56C1900CDF9C8 /* RCTDatePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDatePickerManager.h; sourceTree = "<group>"; };
|
||||
830213F31A654E0800B993E6 /* RCTBridgeModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBridgeModule.h; sourceTree = "<group>"; };
|
||||
830A229C1A66C68A008503DA /* RCTRootView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRootView.h; sourceTree = "<group>"; };
|
||||
830A229D1A66C68A008503DA /* RCTRootView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootView.m; sourceTree = "<group>"; };
|
||||
|
@ -141,6 +154,8 @@
|
|||
830BA4541A8E3BDA00D53203 /* RCTCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCache.m; sourceTree = "<group>"; };
|
||||
83BEE46C1A6D19BC00B5863B /* RCTSparseArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSparseArray.h; sourceTree = "<group>"; };
|
||||
83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSparseArray.m; sourceTree = "<group>"; };
|
||||
83C9110E1AAE6521001323A3 /* RCTAnimationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationManager.h; sourceTree = "<group>"; };
|
||||
83C9110F1AAE6521001323A3 /* RCTAnimationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimationManager.m; sourceTree = "<group>"; };
|
||||
83CBBA2E1A601D0E00E9B192 /* libReactKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactKit.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
83CBBA4A1A601E3B00E9B192 /* RCTAssert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAssert.h; sourceTree = "<group>"; };
|
||||
83CBBA4B1A601E3B00E9B192 /* RCTAssert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAssert.m; sourceTree = "<group>"; };
|
||||
|
@ -198,8 +213,12 @@
|
|||
children = (
|
||||
13B07FE71A69327A00A75B9A /* RCTAlertManager.h */,
|
||||
13B07FE81A69327A00A75B9A /* RCTAlertManager.m */,
|
||||
83C9110E1AAE6521001323A3 /* RCTAnimationManager.h */,
|
||||
83C9110F1AAE6521001323A3 /* RCTAnimationManager.m */,
|
||||
13B07FE91A69327A00A75B9A /* RCTExceptionsManager.h */,
|
||||
13B07FEA1A69327A00A75B9A /* RCTExceptionsManager.m */,
|
||||
5F5F0D971A9E456B001279FA /* RCTLocationObserver.h */,
|
||||
5F5F0D981A9E456B001279FA /* RCTLocationObserver.m */,
|
||||
13723B4E1A82FD3C00F88898 /* RCTStatusBarManager.h */,
|
||||
13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */,
|
||||
13B07FED1A69327A00A75B9A /* RCTTiming.h */,
|
||||
|
@ -213,20 +232,14 @@
|
|||
13B07FF31A6947C200A75B9A /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
14F362071AABD06A001CE568 /* RCTSwitch.h */,
|
||||
14F362081AABD06A001CE568 /* RCTSwitch.m */,
|
||||
14F362091AABD06A001CE568 /* RCTSwitchManager.h */,
|
||||
14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */,
|
||||
14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */,
|
||||
14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */,
|
||||
13442BF21AA90E0B0037E5B0 /* RCTAnimationType.h */,
|
||||
13C325261AA63B6A0048765F /* RCTAutoInsetsProtocol.h */,
|
||||
58C571C01AA56C1900CDF9C8 /* RCTDatePickerManager.h */,
|
||||
58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */,
|
||||
13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */,
|
||||
13442BF41AA90E0B0037E5B0 /* RCTViewControllerProtocol.h */,
|
||||
13C325261AA63B6A0048765F /* RCTAutoInsetsProtocol.h */,
|
||||
13C325271AA63B6A0048765F /* RCTScrollableProtocol.h */,
|
||||
13C325281AA63B6A0048765F /* RCTViewNodeProtocol.h */,
|
||||
14435CE11AAC4AE100FC20F4 /* RCTMap.h */,
|
||||
14435CE21AAC4AE100FC20F4 /* RCTMap.m */,
|
||||
14435CE31AAC4AE100FC20F4 /* RCTMapManager.h */,
|
||||
14435CE41AAC4AE100FC20F4 /* RCTMapManager.m */,
|
||||
13B0800C1A69489C00A75B9A /* RCTNavigator.h */,
|
||||
13B0800D1A69489C00A75B9A /* RCTNavigator.m */,
|
||||
13B0800E1A69489C00A75B9A /* RCTNavigatorManager.h */,
|
||||
|
@ -235,24 +248,24 @@
|
|||
13B080111A69489C00A75B9A /* RCTNavItem.m */,
|
||||
13B080121A69489C00A75B9A /* RCTNavItemManager.h */,
|
||||
13B080131A69489C00A75B9A /* RCTNavItemManager.m */,
|
||||
58114A121AAE854800E7D092 /* RCTPicker.h */,
|
||||
58114A131AAE854800E7D092 /* RCTPicker.m */,
|
||||
58114A141AAE854800E7D092 /* RCTPickerManager.h */,
|
||||
58114A151AAE854800E7D092 /* RCTPickerManager.m */,
|
||||
13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */,
|
||||
13B07FF61A6947C200A75B9A /* RCTScrollView.h */,
|
||||
13B07FF71A6947C200A75B9A /* RCTScrollView.m */,
|
||||
13B07FF81A6947C200A75B9A /* RCTScrollViewManager.h */,
|
||||
13B07FF91A6947C200A75B9A /* RCTScrollViewManager.m */,
|
||||
13C325271AA63B6A0048765F /* RCTScrollableProtocol.h */,
|
||||
13E0674B1A70F44B002CDEE1 /* RCTShadowView.h */,
|
||||
13E0674C1A70F44B002CDEE1 /* RCTShadowView.m */,
|
||||
13B080141A69489C00A75B9A /* RCTTextField.h */,
|
||||
13B080151A69489C00A75B9A /* RCTTextField.m */,
|
||||
13B080161A69489C00A75B9A /* RCTTextFieldManager.h */,
|
||||
13B080171A69489C00A75B9A /* RCTTextFieldManager.m */,
|
||||
13B080181A69489C00A75B9A /* RCTUIActivityIndicatorViewManager.h */,
|
||||
13B080191A69489C00A75B9A /* RCTUIActivityIndicatorViewManager.m */,
|
||||
13E0674F1A70F44B002CDEE1 /* RCTView.h */,
|
||||
13E067501A70F44B002CDEE1 /* RCTView.m */,
|
||||
13E0674D1A70F44B002CDEE1 /* RCTViewManager.h */,
|
||||
13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */,
|
||||
13B080231A694A8400A75B9A /* RCTWrapperViewController.h */,
|
||||
13B080241A694A8400A75B9A /* RCTWrapperViewController.m */,
|
||||
14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */,
|
||||
14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */,
|
||||
14F362071AABD06A001CE568 /* RCTSwitch.h */,
|
||||
14F362081AABD06A001CE568 /* RCTSwitch.m */,
|
||||
14F362091AABD06A001CE568 /* RCTSwitchManager.h */,
|
||||
14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */,
|
||||
137327DF1AA5CF210034F82E /* RCTTabBar.h */,
|
||||
137327E01AA5CF210034F82E /* RCTTabBar.m */,
|
||||
137327E11AA5CF210034F82E /* RCTTabBarItem.h */,
|
||||
|
@ -261,6 +274,20 @@
|
|||
137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */,
|
||||
137327E51AA5CF210034F82E /* RCTTabBarManager.h */,
|
||||
137327E61AA5CF210034F82E /* RCTTabBarManager.m */,
|
||||
13B080141A69489C00A75B9A /* RCTTextField.h */,
|
||||
13B080151A69489C00A75B9A /* RCTTextField.m */,
|
||||
13B080161A69489C00A75B9A /* RCTTextFieldManager.h */,
|
||||
13B080171A69489C00A75B9A /* RCTTextFieldManager.m */,
|
||||
13B080181A69489C00A75B9A /* RCTUIActivityIndicatorViewManager.h */,
|
||||
13B080191A69489C00A75B9A /* RCTUIActivityIndicatorViewManager.m */,
|
||||
13E0674F1A70F44B002CDEE1 /* RCTView.h */,
|
||||
13E067501A70F44B002CDEE1 /* RCTView.m */,
|
||||
13442BF41AA90E0B0037E5B0 /* RCTViewControllerProtocol.h */,
|
||||
13E0674D1A70F44B002CDEE1 /* RCTViewManager.h */,
|
||||
13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */,
|
||||
13C325281AA63B6A0048765F /* RCTViewNodeProtocol.h */,
|
||||
13B080231A694A8400A75B9A /* RCTWrapperViewController.h */,
|
||||
13B080241A694A8400A75B9A /* RCTWrapperViewController.m */,
|
||||
13E067531A70F44B002CDEE1 /* UIView+ReactKit.h */,
|
||||
13E067541A70F44B002CDEE1 /* UIView+ReactKit.m */,
|
||||
);
|
||||
|
@ -435,12 +462,17 @@
|
|||
134FCB361A6D42D900051CC8 /* RCTSparseArray.m in Sources */,
|
||||
13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */,
|
||||
83CBBA531A601E3B00E9B192 /* RCTUtils.m in Sources */,
|
||||
14435CE61AAC4AE100FC20F4 /* RCTMapManager.m in Sources */,
|
||||
83C911101AAE6521001323A3 /* RCTAnimationManager.m in Sources */,
|
||||
83CBBA601A601EAA00E9B192 /* RCTBridge.m in Sources */,
|
||||
58114A161AAE854800E7D092 /* RCTPicker.m in Sources */,
|
||||
137327E81AA5CF210034F82E /* RCTTabBarItem.m in Sources */,
|
||||
13E067551A70F44B002CDEE1 /* RCTShadowView.m in Sources */,
|
||||
58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */,
|
||||
13B0801A1A69489C00A75B9A /* RCTNavigator.m in Sources */,
|
||||
830BA4551A8E3BDA00D53203 /* RCTCache.m in Sources */,
|
||||
137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */,
|
||||
14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */,
|
||||
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */,
|
||||
13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
|
||||
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */,
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <MapKit/MapKit.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
extern const CLLocationDegrees RCTMapDefaultSpan;
|
||||
extern const NSTimeInterval RCTMapRegionChangeObserveInterval;
|
||||
extern const CGFloat RCTMapZoomBoundBuffer;
|
||||
|
||||
@class RCTEventDispatcher;
|
||||
|
||||
@interface RCTMap: MKMapView
|
||||
|
||||
@property (nonatomic, assign) BOOL followUserLocation;
|
||||
@property (nonatomic, copy) NSDictionary *JSONRegion;
|
||||
@property (nonatomic, assign) CGFloat minDelta;
|
||||
@property (nonatomic, assign) CGFloat maxDelta;
|
||||
@property (nonatomic, assign) UIEdgeInsets legalLabelInsets;
|
||||
@property (nonatomic, strong) NSTimer *regionChangeObserveTimer;
|
||||
|
||||
@end
|
||||
|
||||
#define FLUSH_NAN(value) \
|
||||
(isnan(value) ? 0 : value)
|
|
@ -0,0 +1,130 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTMap.h"
|
||||
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
const CLLocationDegrees RCTMapDefaultSpan = 0.005;
|
||||
const NSTimeInterval RCTMapRegionChangeObserveInterval = 0.1;
|
||||
const CGFloat RCTMapZoomBoundBuffer = 0.01;
|
||||
|
||||
@interface RCTMap()
|
||||
|
||||
@property (nonatomic, strong) UIView *legalLabel;
|
||||
@property (nonatomic, strong) CLLocationManager *locationManager;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTMap
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
// Find Apple link label
|
||||
for (UIView *subview in self.subviews) {
|
||||
if ([NSStringFromClass(subview.class) isEqualToString:@"MKAttributionLabel"]) {
|
||||
// This check is super hacky, but the whole premise of moving around Apple's internal subviews is super hacky
|
||||
_legalLabel = subview;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self.regionChangeObserveTimer invalidate];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
// Force resize subviews - only the layer is resized by default
|
||||
CGRect mapFrame = self.frame;
|
||||
self.frame = CGRectZero;
|
||||
self.frame = mapFrame;
|
||||
|
||||
if (_legalLabel) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
CGRect frame = _legalLabel.frame;
|
||||
if (_legalLabelInsets.left) {
|
||||
frame.origin.x = _legalLabelInsets.left;
|
||||
} else if (_legalLabelInsets.right) {
|
||||
frame.origin.x = mapFrame.size.width - _legalLabelInsets.right - frame.size.width;
|
||||
}
|
||||
if (_legalLabelInsets.top) {
|
||||
frame.origin.y = _legalLabelInsets.top;
|
||||
} else if (_legalLabelInsets.bottom) {
|
||||
frame.origin.y = mapFrame.size.height - _legalLabelInsets.bottom - frame.size.height;
|
||||
}
|
||||
_legalLabel.frame = frame;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setShowsUserLocation:(BOOL)showsUserLocation
|
||||
{
|
||||
if (self.showsUserLocation != showsUserLocation) {
|
||||
if (showsUserLocation && !_locationManager) {
|
||||
_locationManager = [[CLLocationManager alloc] init];
|
||||
if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
|
||||
[_locationManager requestWhenInUseAuthorization];
|
||||
}
|
||||
}
|
||||
[super setShowsUserLocation:showsUserLocation];
|
||||
|
||||
// If it needs to show user location, force map view centered
|
||||
// on user's current location on user location updates
|
||||
self.followUserLocation = showsUserLocation;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setJSONRegion:(NSDictionary *)region
|
||||
{
|
||||
if (region) {
|
||||
MKCoordinateRegion coordinateRegion = self.region;
|
||||
if ([region[@"latitude"] isKindOfClass:[NSNumber class]]) {
|
||||
coordinateRegion.center.latitude = [region[@"latitude"] doubleValue];
|
||||
} else {
|
||||
RCTLogError(@"region must include numeric latitude, got: %@", region);
|
||||
return;
|
||||
}
|
||||
if ([region[@"longitude"] isKindOfClass:[NSNumber class]]) {
|
||||
coordinateRegion.center.longitude = [region[@"longitude"] doubleValue];
|
||||
} else {
|
||||
RCTLogError(@"region must include numeric longitude, got: %@", region);
|
||||
return;
|
||||
}
|
||||
if ([region[@"latitudeDelta"] isKindOfClass:[NSNumber class]]) {
|
||||
coordinateRegion.span.latitudeDelta = [region[@"latitudeDelta"] doubleValue];
|
||||
}
|
||||
if ([region[@"longitudeDelta"] isKindOfClass:[NSNumber class]]) {
|
||||
coordinateRegion.span.longitudeDelta = [region[@"longitudeDelta"] doubleValue];
|
||||
}
|
||||
|
||||
[self setRegion:coordinateRegion animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *)JSONRegion
|
||||
{
|
||||
MKCoordinateRegion region = self.region;
|
||||
if (!CLLocationCoordinate2DIsValid(region.center)) {
|
||||
return nil;
|
||||
}
|
||||
return @{
|
||||
@"latitude": @(FLUSH_NAN(region.center.latitude)),
|
||||
@"longitude": @(FLUSH_NAN(region.center.longitude)),
|
||||
@"latitudeDelta": @(FLUSH_NAN(region.span.latitudeDelta)),
|
||||
@"longitudeDelta": @(FLUSH_NAN(region.span.longitudeDelta)),
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTViewManager.h"
|
||||
|
||||
@interface RCTMapManager : RCTViewManager
|
||||
|
||||
@end
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTMapManager.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTMap.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@interface RCTMapManager() <MKMapViewDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTMapManager
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
RCTMap *map = [[RCTMap alloc] init];
|
||||
map.delegate = self;
|
||||
return map;
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(showsUserLocation);
|
||||
RCT_EXPORT_VIEW_PROPERTY(zoomEnabled);
|
||||
RCT_EXPORT_VIEW_PROPERTY(rotateEnabled);
|
||||
RCT_EXPORT_VIEW_PROPERTY(pitchEnabled);
|
||||
RCT_EXPORT_VIEW_PROPERTY(scrollEnabled);
|
||||
RCT_EXPORT_VIEW_PROPERTY(maxDelta);
|
||||
RCT_EXPORT_VIEW_PROPERTY(minDelta);
|
||||
RCT_EXPORT_VIEW_PROPERTY(legalLabelInsets);
|
||||
RCT_REMAP_VIEW_PROPERTY(region, JSONRegion)
|
||||
|
||||
#pragma mark MKMapViewDelegate
|
||||
|
||||
- (void)mapView:(RCTMap *)mapView didUpdateUserLocation:(MKUserLocation *)location
|
||||
{
|
||||
if (mapView.followUserLocation) {
|
||||
MKCoordinateRegion region;
|
||||
region.span.latitudeDelta = RCTMapDefaultSpan;
|
||||
region.span.longitudeDelta = RCTMapDefaultSpan;
|
||||
region.center = location.coordinate;
|
||||
[mapView setRegion:region animated:YES];
|
||||
|
||||
// Move to user location only for the first time it loads up.
|
||||
mapView.followUserLocation = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mapView:(RCTMap *)mapView regionWillChangeAnimated:(BOOL)animated
|
||||
{
|
||||
[self _regionChanged:mapView];
|
||||
|
||||
mapView.regionChangeObserveTimer = [NSTimer timerWithTimeInterval:RCTMapRegionChangeObserveInterval
|
||||
target:self
|
||||
selector:@selector(_onTick:)
|
||||
userInfo:@{ @"mapView": mapView }
|
||||
repeats:YES];
|
||||
[[NSRunLoop mainRunLoop] addTimer:mapView.regionChangeObserveTimer forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
|
||||
- (void)mapView:(RCTMap *)mapView regionDidChangeAnimated:(BOOL)animated
|
||||
{
|
||||
[self _regionChanged:mapView];
|
||||
[self _emitRegionChangeEvent:mapView continuous:NO];
|
||||
|
||||
[mapView.regionChangeObserveTimer invalidate];
|
||||
mapView.regionChangeObserveTimer = nil;
|
||||
}
|
||||
|
||||
#pragma mark Private
|
||||
|
||||
- (void)_onTick:(NSTimer *)timer
|
||||
{
|
||||
[self _regionChanged:timer.userInfo[@"mapView"]];
|
||||
}
|
||||
|
||||
- (void)_regionChanged:(RCTMap *)mapView
|
||||
{
|
||||
BOOL needZoom = NO;
|
||||
CGFloat newLongitudeDelta = 0.0f;
|
||||
MKCoordinateRegion region = mapView.region;
|
||||
// On iOS 7, it's possible that we observe invalid locations during initialization of the map.
|
||||
// Filter those out.
|
||||
if (!CLLocationCoordinate2DIsValid(region.center)) {
|
||||
return;
|
||||
}
|
||||
// Calculation on float is not 100% accurate. If user zoom to max/min and then move, it's likely the map will auto zoom to max/min from time to time.
|
||||
// So let's try to make map zoom back to 99% max or 101% min so that there are some buffer that moving the map won't constantly hitting the max/min bound.
|
||||
if (mapView.maxDelta > FLT_EPSILON && region.span.longitudeDelta > mapView.maxDelta) {
|
||||
needZoom = YES;
|
||||
newLongitudeDelta = mapView.maxDelta * (1 - RCTMapZoomBoundBuffer);
|
||||
} else if (mapView.minDelta > FLT_EPSILON && region.span.longitudeDelta < mapView.minDelta) {
|
||||
needZoom = YES;
|
||||
newLongitudeDelta = mapView.minDelta * (1 + RCTMapZoomBoundBuffer);
|
||||
}
|
||||
if (needZoom) {
|
||||
region.span.latitudeDelta = region.span.latitudeDelta / region.span.longitudeDelta * newLongitudeDelta;
|
||||
region.span.longitudeDelta = newLongitudeDelta;
|
||||
mapView.region = region;
|
||||
}
|
||||
|
||||
// Continously observe region changes
|
||||
[self _emitRegionChangeEvent:mapView continuous:YES];
|
||||
}
|
||||
|
||||
- (void)_emitRegionChangeEvent:(RCTMap *)mapView continuous:(BOOL)continuous
|
||||
{
|
||||
NSDictionary *region = mapView.JSONRegion;
|
||||
if (region) {
|
||||
NSDictionary *event = @{
|
||||
@"target": [mapView reactTag],
|
||||
@"continuous": @(continuous),
|
||||
@"region": mapView.JSONRegion,
|
||||
};
|
||||
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RCTEventDispatcher;
|
||||
|
||||
@interface RCTPicker : UIPickerView
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTPicker.h"
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
const NSInteger UNINITIALIZED_INDEX = -1;
|
||||
|
||||
@interface RCTPicker() <UIPickerViewDataSource, UIPickerViewDelegate>
|
||||
{
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
NSArray *_items;
|
||||
NSInteger _selectedIndex;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation RCTPicker
|
||||
|
||||
- (id)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
if (self = [super initWithFrame:CGRectZero]) {
|
||||
_eventDispatcher = eventDispatcher;
|
||||
_selectedIndex = UNINITIALIZED_INDEX;
|
||||
self.delegate = self;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setItems:(NSArray *)items
|
||||
{
|
||||
if (_items != items) {
|
||||
_items = [items copy];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSelectedIndex:(NSInteger)selectedIndex
|
||||
{
|
||||
if (_selectedIndex != selectedIndex) {
|
||||
BOOL animated = _selectedIndex != UNINITIALIZED_INDEX; // Don't animate the initial value
|
||||
_selectedIndex = selectedIndex;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self selectRow:selectedIndex inComponent:0 animated:animated];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UIPickerViewDataSource protocol
|
||||
|
||||
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
|
||||
{
|
||||
return [_items count];
|
||||
}
|
||||
|
||||
#pragma mark - UIPickerViewDelegate methods
|
||||
|
||||
- (NSDictionary *)itemForRow:(NSInteger)row
|
||||
{
|
||||
return (NSDictionary*)[_items objectAtIndex:row];
|
||||
}
|
||||
|
||||
- (id)valueForRow:(NSInteger)row
|
||||
{
|
||||
return [self itemForRow:row][@"value"];
|
||||
}
|
||||
|
||||
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
|
||||
{
|
||||
return [self itemForRow:row][@"label"];
|
||||
}
|
||||
|
||||
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
|
||||
{
|
||||
_selectedIndex = row;
|
||||
NSDictionary *event = @{
|
||||
@"target": self.reactTag,
|
||||
@"newIndex": @(row),
|
||||
@"newValue": [self valueForRow:row]
|
||||
};
|
||||
|
||||
[_eventDispatcher sendInputEventWithName:@"topChange" body:event];
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTViewManager.h"
|
||||
|
||||
@interface RCTPickerManager : RCTViewManager
|
||||
|
||||
@end
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTPickerManager.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTPicker.h"
|
||||
|
||||
@implementation RCTPickerManager
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [[RCTPicker alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(items)
|
||||
RCT_EXPORT_VIEW_PROPERTY(selectedIndex)
|
||||
|
||||
- (NSDictionary *)constantsToExport
|
||||
{
|
||||
RCTPicker *pv = [[RCTPicker alloc] init];
|
||||
return @{
|
||||
@"ComponentHeight": @(CGRectGetHeight(pv.frame)),
|
||||
@"ComponentWidth": @(CGRectGetWidth(pv.frame))
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
|
@ -17,7 +17,7 @@
|
|||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
if ((self = [super initWithFrame:CGRectZero])) {
|
||||
|
||||
|
||||
_eventDispatcher = eventDispatcher;
|
||||
[self addTarget:self action:@selector(_textFieldDidChange) forControlEvents:UIControlEventEditingChanged];
|
||||
[self addTarget:self action:@selector(_textFieldBeginEditing) forControlEvents:UIControlEventEditingDidBegin];
|
||||
|
@ -40,7 +40,7 @@
|
|||
- (void)removeReactSubview:(UIView *)subview
|
||||
{
|
||||
// TODO: this is a bit broken - if the TextField inserts any of
|
||||
// it's own views below or between React's, the indices won't match
|
||||
// its own views below or between React's, the indices won't match
|
||||
[_reactSubviews removeObject:subview];
|
||||
[subview removeFromSuperview];
|
||||
}
|
||||
|
@ -48,7 +48,7 @@
|
|||
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
|
||||
{
|
||||
// TODO: this is a bit broken - if the TextField inserts any of
|
||||
// it's own views below or between React's, the indices won't match
|
||||
// its own views below or between React's, the indices won't match
|
||||
[_reactSubviews insertObject:view atIndex:atIndex];
|
||||
[super insertSubview:view atIndex:atIndex];
|
||||
}
|
||||
|
@ -74,7 +74,7 @@
|
|||
|
||||
- (void)setAutoCorrect:(BOOL)autoCorrect
|
||||
{
|
||||
[super setAutocorrectionType:(autoCorrect ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo)];
|
||||
self.autocorrectionType = (autoCorrect ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo);
|
||||
}
|
||||
|
||||
- (BOOL)autoCorrect
|
||||
|
@ -117,7 +117,6 @@ RCT_TEXT_EVENT_HANDLER(_textFieldSubmitEditing, RCTTextEventTypeSubmit)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Prevent native from becoming first responder (TODO: why?)
|
||||
- (BOOL)canBecomeFirstResponder
|
||||
{
|
||||
return _jsRequestingFirstResponder;
|
||||
|
|
|
@ -20,7 +20,6 @@ RCT_REMAP_VIEW_PROPERTY(autoCapitalize, autocapitalizationType)
|
|||
RCT_EXPORT_VIEW_PROPERTY(enabled)
|
||||
RCT_EXPORT_VIEW_PROPERTY(placeholder)
|
||||
RCT_EXPORT_VIEW_PROPERTY(text)
|
||||
RCT_EXPORT_VIEW_PROPERTY(font)
|
||||
RCT_EXPORT_VIEW_PROPERTY(clearButtonMode)
|
||||
RCT_EXPORT_VIEW_PROPERTY(keyboardType)
|
||||
RCT_REMAP_VIEW_PROPERTY(color, textColor)
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
"scriptPreprocessor": "jestSupport/scriptPreprocess.js",
|
||||
"setupEnvScriptFile": "jestSupport/env.js",
|
||||
"testPathIgnorePatterns": [
|
||||
"/node_modules/"
|
||||
"/node_modules/",
|
||||
"packager/react-packager/src/Activity/"
|
||||
],
|
||||
"testFileExtensions": [
|
||||
"js"
|
||||
|
|
Загрузка…
Ссылка в новой задаче