Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41eaf60e6f | ||
|
|
98263c4f8f | ||
|
|
0293def7a9 | ||
|
|
bb95400f24 | ||
|
|
45d8fb0ef6 | ||
|
|
f90fa53df9 | ||
|
|
1a564eed77 | ||
|
|
7009f0a47b | ||
|
|
f744c7c444 | ||
|
|
30fc7389d1 | ||
|
|
53b2c39cc0 | ||
|
|
015b5cf8e5 | ||
|
|
7ffa7bd1f1 | ||
|
|
9fe7128493 | ||
|
|
63b8262843 | ||
|
|
fa3491e9f5 | ||
|
|
6d25ff83ec | ||
|
|
856469a24b | ||
|
|
89a1e94a15 | ||
|
|
b2b89c0b68 | ||
|
|
074fa759a6 | ||
|
|
7be471d1fe | ||
|
|
5a191dadfc | ||
|
|
435125f4a0 | ||
|
|
ca7a764c8c | ||
|
|
bba576a172 | ||
|
|
8b93b99d4a | ||
|
|
0d29a69948 | ||
|
|
e68f89bfad | ||
|
|
b63a0a111d | ||
|
|
e1454c29c5 | ||
|
|
158d8b64ff | ||
|
|
10b13512b9 | ||
|
|
95d2843362 | ||
|
|
a76647334f | ||
|
|
c4457f8e6f | ||
|
|
b243236404 | ||
|
|
1c82de4db2 | ||
|
|
d796584b6c | ||
|
|
d90999a989 | ||
|
|
78f83acdc2 | ||
|
|
aa7e318a3f | ||
|
|
613e561751 | ||
|
|
4d4f2dfe09 | ||
|
|
9b455c8677 | ||
|
|
c094a156d6 | ||
|
|
0f16d15d64 | ||
|
|
2dfa3b34a1 | ||
|
|
0aa7f3f8d5 | ||
|
|
777363fdd7 | ||
|
|
dc6fd82231 | ||
|
|
570597c4ac | ||
|
|
1ed2542b46 | ||
|
|
e6c04df5a1 | ||
|
|
219a7c1bfd | ||
|
|
2a6fe079c0 | ||
|
|
38f57ee18c | ||
|
|
43adb7b02c | ||
|
|
34cef28a10 | ||
|
|
d723e17629 | ||
|
|
c700f71cb5 | ||
|
|
0c8c57503e | ||
|
|
d548c85da6 | ||
|
|
2b4daf228d | ||
|
|
57ce9fb11a | ||
|
|
49e87af934 | ||
|
|
a2db4a4a5b | ||
|
|
2deff61bde | ||
|
|
6e24a71d3d | ||
|
|
b03446e27e | ||
|
|
df58789f22 | ||
|
|
595eae8b67 | ||
|
|
c37509727f | ||
|
|
09cef03cd3 | ||
|
|
62fef10755 | ||
|
|
53a7e070b8 | ||
|
|
13316ef380 | ||
|
|
d6ac633de5 | ||
|
|
69ce448de9 | ||
|
|
597f9d94fd | ||
|
|
e65eff8df6 | ||
|
|
47e56d778a | ||
|
|
1c692e2eb6 | ||
|
|
39b2342ab9 | ||
|
|
5918be2325 | ||
|
|
2429324e79 | ||
|
|
c60c1c0415 | ||
|
|
8976a05fe1 | ||
|
|
3b6ed00ace | ||
|
|
f8b3c98bc6 | ||
|
|
b9a47062a6 | ||
|
|
74c337f770 | ||
|
|
6bffa6c8a8 | ||
|
|
1567e8224a | ||
|
|
ef4f143ae0 | ||
|
|
bb7ae59a12 | ||
|
|
f9b3f9121f | ||
|
|
e2dc2db9dc | ||
|
|
ff48f78742 | ||
|
|
1a4f270931 | ||
|
|
ee8ba19ab1 | ||
|
|
1a3ee99365 | ||
|
|
228dc5f936 | ||
|
|
36c33b4a60 | ||
|
|
4097459dc9 | ||
|
|
40da2c7e08 | ||
|
|
1efd2c87c8 | ||
|
|
18a3d715ce | ||
|
|
03889780b9 | ||
|
|
7e0064f097 | ||
|
|
3c1eaf7a6e | ||
|
|
474ac651d5 | ||
|
|
45c1dc1c65 | ||
|
|
656c5e4e27 | ||
|
|
ff49d86aed | ||
|
|
3b24f52a20 | ||
|
|
41859e594d | ||
|
|
9d1960948c | ||
|
|
ebae151f24 | ||
|
|
2b8f44d446 | ||
|
|
d63440576d | ||
|
|
6075cef070 | ||
|
|
71216de931 | ||
|
|
21b3304a95 | ||
|
|
7c0756fba6 | ||
|
|
3af55b58ad | ||
|
|
4fc15dbf17 | ||
|
|
17e9cd6297 | ||
|
|
380ba2aab4 | ||
|
|
626e435c12 | ||
|
|
acc42e193d | ||
|
|
455281e44d | ||
|
|
731335eb7c | ||
|
|
8d992262ed | ||
|
|
a4442e4576 | ||
|
|
0689c0790e | ||
|
|
95517fca41 | ||
|
|
76ea00483d | ||
|
|
84783dbac4 | ||
|
|
b839ab32be | ||
|
|
2a76ca635e | ||
|
|
769efdfcef | ||
|
|
e5b134368b | ||
|
|
3269af227f | ||
|
|
cfa4b13472 | ||
|
|
4273af9e29 | ||
|
|
7069e4cd3f | ||
|
|
b7c669aa73 | ||
|
|
81401064e5 | ||
|
|
64ae42c10a | ||
|
|
0466bbd616 | ||
|
|
1586f3114c | ||
|
|
c2aa16607f | ||
|
|
68718fd3bc | ||
|
|
9062bda79b | ||
|
|
ffcdf21004 | ||
|
|
eb3bdd997e | ||
|
|
571aa55ef5 | ||
|
|
90f15940fa | ||
|
|
c91e2eb567 | ||
|
|
82a082a794 | ||
|
|
c6ed85afcc | ||
|
|
53ea27c7b8 | ||
|
|
c2854dc397 | ||
|
|
55caeadd8e | ||
|
|
aad54006e3 | ||
|
|
56d6ee3f0f | ||
|
|
5bad316678 | ||
|
|
62c556c785 | ||
|
|
52725437d4 | ||
|
|
bd11de1b51 | ||
|
|
6cb31bb19d | ||
|
|
4673dca0b0 | ||
|
|
800c62bb8b | ||
|
|
eec67aff4d | ||
|
|
fe4b4c2d83 | ||
|
|
7f51f9c8a9 | ||
|
|
c6670658f4 | ||
|
|
d20a6e9d2d | ||
|
|
b46c94aaf9 | ||
|
|
08844e3ddc | ||
|
|
1d5d01c3c9 | ||
|
|
9a76f224af | ||
|
|
8bb65215b1 | ||
|
|
0d227c0eb2 | ||
|
|
1b2975803b | ||
|
|
4cd5cad599 | ||
|
|
d211359aeb | ||
|
|
32666f0aa2 | ||
|
|
c1609bcab8 | ||
|
|
97137e8bcc | ||
|
|
11b515b1b0 | ||
|
|
a4f92ba3db | ||
|
|
1c70f33511 | ||
|
|
33ac55b2bd | ||
|
|
de27f1db54 | ||
|
|
a1193b7a93 | ||
|
|
214ae2062c | ||
|
|
f2b76566f3 | ||
|
|
f2ffaed4ca | ||
|
|
03905e69f4 | ||
|
|
6ef7eaf663 | ||
|
|
7219fcefc6 | ||
|
|
eedb880f6e | ||
|
|
a4e89d71a3 | ||
|
|
424d1318c8 | ||
|
|
407d8d4cf6 | ||
|
|
545edba913 | ||
|
|
5a83ffab94 | ||
|
|
d63eac4014 | ||
|
|
367638053a | ||
|
|
08d30e751b | ||
|
|
c668fd5be0 | ||
|
|
5f841a950e | ||
|
|
64c0bb0bd4 | ||
|
|
723e988416 | ||
|
|
7a1c52c8e9 | ||
|
|
7947f04b43 | ||
|
|
d43d093bf7 | ||
|
|
35590440d6 | ||
|
|
962d88cb4a |
@@ -1,3 +1,5 @@
|
||||
**/node_modules/**/.*js
|
||||
# node_modules ignored by default
|
||||
|
||||
**/staticBundle.js
|
||||
**/main.js
|
||||
Libraries/vendor/**/*
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
{
|
||||
"parser": "babel-eslint",
|
||||
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
},
|
||||
|
||||
"env": {
|
||||
"es6": true,
|
||||
"jasmine": true,
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
|
||||
// Map from global var to bool specifying if it can be redefined
|
||||
"globals": {
|
||||
"__DEV__": true,
|
||||
@@ -36,10 +47,10 @@
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"comma-dangle": 0, // disallow trailing commas in object literals
|
||||
"no-cond-assign": 1, // disallow assignment in conditional expressions
|
||||
"no-console": 0, // disallow use of console (off by default in the node environment)
|
||||
"no-constant-condition": 0, // disallow use of constant expressions in conditions
|
||||
"no-comma-dangle": 0, // disallow trailing commas in object literals
|
||||
"no-control-regex": 1, // disallow control characters in regular expressions
|
||||
"no-debugger": 1, // disallow use of debugger
|
||||
"no-dupe-keys": 1, // disallow duplicate keys when creating object literals
|
||||
@@ -107,6 +118,7 @@
|
||||
"no-warning-comments": 0, // disallow usage of configurable warning terms in comments": 1, // e.g. TODO or FIXME (off by default)
|
||||
"no-with": 1, // disallow use of the with statement
|
||||
"radix": 1, // require use of the second argument for parseInt() (off by default)
|
||||
"semi-spacing": 1, // require a space after a semi-colon
|
||||
"vars-on-top": 0, // requires to declare all vars on top of their containing scope (off by default)
|
||||
"wrap-iife": 0, // require immediate function invocation to be wrapped in parentheses (off by default)
|
||||
"yoda": 1, // require or disallow Yoda conditions
|
||||
@@ -168,7 +180,7 @@
|
||||
"no-underscore-dangle": 0, // disallow dangling underscores in identifiers
|
||||
"no-wrap-func": 1, // disallow wrapping of non-IIFE statements in parens
|
||||
"no-mixed-spaces-and-tabs": 1, // disallow mixed spaces and tabs for indentation
|
||||
"quotes": [1, "single"], // specify whether double or single quotes should be used
|
||||
"quotes": [1, "single", "avoid-escape"], // specify whether double or single quotes should be used
|
||||
"quote-props": 0, // require quotes around object literal property names (off by default)
|
||||
"semi": 1, // require or disallow use of semicolons instead of ASI
|
||||
"sort-vars": 0, // sort variables within the same declaration block (off by default)
|
||||
@@ -177,7 +189,7 @@
|
||||
"space-in-parens": 0, // require or disallow spaces inside parentheses (off by default)
|
||||
"space-infix-ops": 1, // require spaces around operators
|
||||
"space-return-throw-case": 1, // require a space after return, throw, and case
|
||||
"space-unary-word-ops": 1, // require a space around word operators such as typeof (off by default)
|
||||
"space-unary-ops": [1, { "words": true, "nonwords": false }], // require or disallow spaces before/after unary operators (words on by default, nonwords off by default)
|
||||
"max-nested-callbacks": 0, // specify the maximum depth callbacks can be nested (off by default)
|
||||
"one-var": 0, // allow just one var statement per function (off by default)
|
||||
"wrap-regex": 0, // require regex literals to be wrapped in parentheses (off by default)
|
||||
@@ -190,6 +202,22 @@
|
||||
"max-params": 0, // limits the number of parameters that can be used in the function declaration. (off by default)
|
||||
"max-statements": 0, // specify the maximum number of statement allowed in a function (off by default)
|
||||
"no-bitwise": 1, // disallow use of bitwise operators (off by default)
|
||||
"no-plusplus": 0 // disallow use of unary operators, ++ and -- (off by default)
|
||||
"no-plusplus": 0, // disallow use of unary operators, ++ and -- (off by default)
|
||||
|
||||
"react/display-name": 0,
|
||||
"react/jsx-boolean-value": 0,
|
||||
"react/jsx-quotes": [1, "double", "avoid-escape"],
|
||||
"react/jsx-no-undef": 1,
|
||||
"react/jsx-sort-props": 0,
|
||||
"react/jsx-uses-react": 0,
|
||||
"react/jsx-uses-vars": 1,
|
||||
"react/no-did-mount-set-state": [1, "allow-in-func"],
|
||||
"react/no-did-update-set-state": [1, "allow-in-func"],
|
||||
"react/no-multi-comp": 0,
|
||||
"react/no-unknown-property": 0,
|
||||
"react/prop-types": 0,
|
||||
"react/react-in-jsx-scope": 0,
|
||||
"react/self-closing-comp": 1,
|
||||
"react/wrap-multilines": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
.*/node_modules/react-tools/src/event/EventPropagators.js
|
||||
|
||||
# Ignore commoner tests
|
||||
.*/node_modules/react-tools/node_modules/commoner/test/.*
|
||||
.*/node_modules/commoner/test/.*
|
||||
|
||||
# See https://github.com/facebook/flow/issues/442
|
||||
.*/react-tools/node_modules/commoner/lib/reader.js
|
||||
|
||||
# Ignore jest
|
||||
.*/react-native/node_modules/jest-cli/.*
|
||||
.*/node_modules/jest-cli/.*
|
||||
|
||||
# Ignore Website
|
||||
.*/website/.*
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
language: objective-c
|
||||
|
||||
osx_image: beta-xcode6.3
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
directories:
|
||||
- node_modules
|
||||
- .nvm
|
||||
|
||||
before_install:
|
||||
- brew update
|
||||
install:
|
||||
- brew reinstall flow xctool
|
||||
- brew reinstall flow xctool nvm
|
||||
- mkdir -p .nvm
|
||||
- cp $(brew --prefix nvm)/nvm-exec .nvm/
|
||||
- export NVM_DIR=.nvm
|
||||
- source $(brew --prefix nvm)/nvm.sh
|
||||
- nvm install v0.10
|
||||
- npm config set spin=false
|
||||
- npm install
|
||||
|
||||
script:
|
||||
- |
|
||||
nvm use v0.10
|
||||
|
||||
if [ "$TEST_TYPE" = objc ]
|
||||
then
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ The core team will be monitoring for pull requests. When we get one, we'll run s
|
||||
1. Fork the repo and create your branch from `master`.
|
||||
2. If you've added code that should be tested, add tests!
|
||||
3. If you've changed APIs, update the documentation.
|
||||
4. Ensure the test suite passes.
|
||||
5. Make sure your code lints - we've done our best to make sure these rules match our internal linting guidelines.
|
||||
4. Ensure tests pass on Travis.
|
||||
5. Make sure your code lints (`node linter.js <files touched>`).
|
||||
6. If you haven't already, complete the CLA.
|
||||
|
||||
### Contributor License Agreement ("CLA")
|
||||
@@ -37,7 +37,7 @@ We will be using GitHub Issues for our public bugs. We will keep a close eye on
|
||||
|
||||
### Reporting New Issues
|
||||
|
||||
The best way to get your bug fixed is to provide a reduced test case.
|
||||
The best way to get your bug fixed is to provide a reduced test case. Please provide either a public repository with a runnable example or a [React Native Playground](https://rnplay.org/) snippet.
|
||||
|
||||
### Security Bugs
|
||||
|
||||
|
||||
@@ -34,7 +34,10 @@ var MovieCell = React.createClass({
|
||||
var criticsScore = this.props.movie.ratings.critics_score;
|
||||
return (
|
||||
<View>
|
||||
<TouchableHighlight onPress={this.props.onSelect}>
|
||||
<TouchableHighlight
|
||||
onPress={this.props.onSelect}
|
||||
onShowUnderlay={this.props.onHighlight}
|
||||
onHideUnderlay={this.props.onUnhighlight}>
|
||||
<View style={styles.row}>
|
||||
<Image
|
||||
source={getImageSource(this.props.movie, 'det')}
|
||||
@@ -54,7 +57,6 @@ var MovieCell = React.createClass({
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<View style={styles.cellBorder} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
140D9B661AC36C42004F25EE /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14312D241AC3654D00CDC950 /* libRCTLinking.a */; };
|
||||
14A2D4421AC3E43800CC738A /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A2D4411AC3E41A00CC738A /* libReact.a */; };
|
||||
58C5726B1AA6239E00CDF9C8 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58C5725B1AA6236500CDF9C8 /* libRCTText.a */; };
|
||||
67C95F201B0E64A30040BCE2 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -54,6 +55,13 @@
|
||||
remoteGlobalIDString = 58B5119B1A9E6C1200147676;
|
||||
remoteInfo = RCTText;
|
||||
};
|
||||
67C95F1D1B0E647A0040BCE2 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 3C86DF461ADF2C930047B81A;
|
||||
remoteInfo = RCTWebSocket;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@@ -69,6 +77,7 @@
|
||||
14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../../Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = "<group>"; };
|
||||
14A2D43C1AC3E41A00CC738A /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../../React/React.xcodeproj; sourceTree = "<group>"; };
|
||||
587650F61A9EB120008B8F17 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = SOURCE_ROOT; };
|
||||
67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -76,6 +85,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
67C95F201B0E64A30040BCE2 /* libRCTWebSocket.a in Frameworks */,
|
||||
14A2D4421AC3E43800CC738A /* libReact.a in Frameworks */,
|
||||
140D9B661AC36C42004F25EE /* libRCTLinking.a in Frameworks */,
|
||||
1341801E1AA91750003F314A /* libRCTNetwork.a in Frameworks */,
|
||||
@@ -135,6 +145,7 @@
|
||||
58C571FC1AA6124500CDF9C8 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */,
|
||||
14A2D43C1AC3E41A00CC738A /* React.xcodeproj */,
|
||||
14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */,
|
||||
134180151AA91740003F314A /* RCTNetwork.xcodeproj */,
|
||||
@@ -152,6 +163,14 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67C95F161B0E647A0040BCE2 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -228,6 +247,10 @@
|
||||
ProductGroup = 58C572571AA6236500CDF9C8 /* Products */;
|
||||
ProjectRef = 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 67C95F161B0E647A0040BCE2 /* Products */;
|
||||
ProjectRef = 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 14A2D43D1AC3E41A00CC738A /* Products */;
|
||||
ProjectRef = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */;
|
||||
@@ -276,6 +299,13 @@
|
||||
remoteRef = 58C5725A1AA6236500CDF9C8 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRCTWebSocket.a;
|
||||
remoteRef = 67C95F1D1B0E647A0040BCE2 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
|
||||
@@ -17,6 +17,6 @@
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,10 +237,31 @@ var SearchScreen = React.createClass({
|
||||
return <ActivityIndicatorIOS style={styles.scrollSpinner} />;
|
||||
},
|
||||
|
||||
renderRow: function(movie: Object) {
|
||||
renderSeparator: function(
|
||||
sectionID: number | string,
|
||||
rowID: number | string,
|
||||
adjacentRowHighlighted: boolean
|
||||
) {
|
||||
var style = styles.rowSeparator;
|
||||
if (adjacentRowHighlighted) {
|
||||
style = [style, styles.rowSeparatorHide];
|
||||
}
|
||||
return (
|
||||
<View key={"SEP_" + sectionID + "_" + rowID} style={style}/>
|
||||
);
|
||||
},
|
||||
|
||||
renderRow: function(
|
||||
movie: Object,
|
||||
sectionID: number | string,
|
||||
rowID: number | string,
|
||||
highlightRowFunc: (sectionID: ?number | string, rowID: ?number | string) => void,
|
||||
) {
|
||||
return (
|
||||
<MovieCell
|
||||
onSelect={() => this.selectMovie(movie)}
|
||||
onHighlight={() => highlightRowFunc(sectionID, rowID)}
|
||||
onUnhighlight={() => highlightRowFunc(null, null)}
|
||||
movie={movie}
|
||||
/>
|
||||
);
|
||||
@@ -254,12 +275,13 @@ var SearchScreen = React.createClass({
|
||||
/> :
|
||||
<ListView
|
||||
ref="listview"
|
||||
renderSeparator={this.renderSeparator}
|
||||
dataSource={this.state.dataSource}
|
||||
renderFooter={this.renderFooter}
|
||||
renderRow={this.renderRow}
|
||||
onEndReached={this.onEndReached}
|
||||
automaticallyAdjustContentInsets={false}
|
||||
keyboardDismissMode="onDrag"
|
||||
keyboardDismissMode="on-drag"
|
||||
keyboardShouldPersistTaps={true}
|
||||
showsVerticalScrollIndicator={false}
|
||||
/>;
|
||||
@@ -352,6 +374,14 @@ var styles = StyleSheet.create({
|
||||
scrollSpinner: {
|
||||
marginVertical: 20,
|
||||
},
|
||||
rowSeparator: {
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.1)',
|
||||
height: 1,
|
||||
marginLeft: 4,
|
||||
},
|
||||
rowSeparatorHide: {
|
||||
opacity: 0.0,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = SearchScreen;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
008F07F31AC5B25A0029DE68 /* main.jsbundle in Resources */ = {isa = PBXBuildFile; fileRef = 008F07F21AC5B25A0029DE68 /* main.jsbundle */; };
|
||||
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
|
||||
00C302E61ABCBA2D00DB3ED1 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302B41ABCB8E700DB3ED1 /* libRCTAdSupport.a */; };
|
||||
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
|
||||
00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
|
||||
00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
|
||||
@@ -34,13 +33,6 @@
|
||||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = RCTActionSheet;
|
||||
};
|
||||
00C302B31ABCB8E700DB3ED1 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 00C302AF1ABCB8E700DB3ED1 /* RCTAdSupport.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
|
||||
remoteInfo = RCTAdSupport;
|
||||
};
|
||||
00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
|
||||
@@ -116,7 +108,6 @@
|
||||
/* Begin PBXFileReference section */
|
||||
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = main.jsbundle; path = iOS/main.jsbundle; sourceTree = "<group>"; };
|
||||
00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../../Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = "<group>"; };
|
||||
00C302AF1ABCB8E700DB3ED1 /* RCTAdSupport.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAdSupport.xcodeproj; path = ../../Libraries/AdSupport/RCTAdSupport.xcodeproj; sourceTree = "<group>"; };
|
||||
00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../../Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
|
||||
00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = "<group>"; };
|
||||
00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
|
||||
@@ -152,7 +143,6 @@
|
||||
files = (
|
||||
146834051AC3E58100842450 /* libReact.a in Frameworks */,
|
||||
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
|
||||
00C302E61ABCBA2D00DB3ED1 /* libRCTAdSupport.a in Frameworks */,
|
||||
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
|
||||
00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,
|
||||
133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */,
|
||||
@@ -175,14 +165,6 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
00C302B01ABCB8E700DB3ED1 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
00C302B41ABCB8E700DB3ED1 /* libRCTAdSupport.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
00C302B61ABCB90400DB3ED1 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -283,7 +265,6 @@
|
||||
children = (
|
||||
146833FF1AC3E56700842450 /* React.xcodeproj */,
|
||||
00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,
|
||||
00C302AF1ABCB8E700DB3ED1 /* RCTAdSupport.xcodeproj */,
|
||||
00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,
|
||||
00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */,
|
||||
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */,
|
||||
@@ -394,10 +375,6 @@
|
||||
ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
|
||||
ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 00C302B01ABCB8E700DB3ED1 /* Products */;
|
||||
ProjectRef = 00C302AF1ABCB8E700DB3ED1 /* RCTAdSupport.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */;
|
||||
ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
|
||||
@@ -451,13 +428,6 @@
|
||||
remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
00C302B41ABCB8E700DB3ED1 /* libRCTAdSupport.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRCTAdSupport.a;
|
||||
remoteRef = 00C302B31ABCB8E700DB3ED1 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
|
||||
@@ -50,18 +50,15 @@
|
||||
redboxError = [[RCTRedBox sharedInstance] currentErrorMessage];
|
||||
|
||||
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
|
||||
if ([view respondsToSelector:@selector(attributedText)]) {
|
||||
NSString *text = [(id)view attributedText].string;
|
||||
if ([text isEqualToString:TEXT_TO_LOOK_FOR]) {
|
||||
return YES;
|
||||
}
|
||||
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}];
|
||||
}
|
||||
|
||||
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
|
||||
XCTAssertTrue(foundElement, @"Cound't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
|
||||
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.*/node_modules/react-tools/src/event/EventPropagators.js
|
||||
|
||||
# Ignore commoner tests
|
||||
.*/node_modules/react-tools/node_modules/commoner/test/.*
|
||||
.*/node_modules/commoner/test/.*
|
||||
|
||||
# See https://github.com/facebook/flow/issues/442
|
||||
.*/react-tools/node_modules/commoner/lib/reader.js
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var AccessibilityIOSExample = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<View
|
||||
onAccessibilityTap={() => alert('onAccessibilityTap success')}
|
||||
accessible={true}>
|
||||
<Text>
|
||||
Accessibility normal tap example
|
||||
</Text>
|
||||
</View>
|
||||
<View onMagicTap={() => alert('onMagicTap success')}
|
||||
accessible={true}>
|
||||
<Text>
|
||||
Accessibility magic tap example
|
||||
</Text>
|
||||
</View>
|
||||
<View accessibilityLabel="Some announcement"
|
||||
accessible={true}>
|
||||
<Text>
|
||||
Accessibility label example
|
||||
</Text>
|
||||
</View>
|
||||
<View accessibilityTraits={["button", "selected"]}
|
||||
accessible={true}>
|
||||
<Text>
|
||||
Accessibility traits example
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
exports.title = 'AcccessibilityIOS';
|
||||
exports.description = 'Interface to show iOS\' accessibility samples';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'Accessibility elements',
|
||||
render(): ReactElement { return <AccessibilityIOSExample />; }
|
||||
},
|
||||
];
|
||||
@@ -28,13 +28,19 @@ var AppStateSubscription = React.createClass({
|
||||
return {
|
||||
appState: AppStateIOS.currentState,
|
||||
previousAppStates: [],
|
||||
memoryWarnings: 0,
|
||||
};
|
||||
},
|
||||
componentDidMount: function() {
|
||||
AppStateIOS.addEventListener('change', this._handleAppStateChange);
|
||||
AppStateIOS.addEventListener('memoryWarning', this._handleMemoryWarning);
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
AppStateIOS.removeEventListener('change', this._handleAppStateChange);
|
||||
AppStateIOS.removeEventListener('memoryWarning', this._handleMemoryWarning);
|
||||
},
|
||||
_handleMemoryWarning: function() {
|
||||
this.setState({memoryWarnings: this.state.memoryWarnings + 1})
|
||||
},
|
||||
_handleAppStateChange: function(appState) {
|
||||
var previousAppStates = this.state.previousAppStates.slice();
|
||||
@@ -45,6 +51,13 @@ var AppStateSubscription = React.createClass({
|
||||
});
|
||||
},
|
||||
render() {
|
||||
if (this.props.showMemoryWarnings) {
|
||||
return (
|
||||
<View>
|
||||
<Text>{this.state.memoryWarnings}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
if (this.props.showCurrentOnly) {
|
||||
return (
|
||||
<View>
|
||||
@@ -77,4 +90,9 @@ exports.examples = [
|
||||
title: 'Previous states:',
|
||||
render(): ReactElement { return <AppStateSubscription showCurrentOnly={false} />; }
|
||||
},
|
||||
{
|
||||
title: 'Memory Warnings',
|
||||
description: "In the simulator, hit Shift+Command+M to simulate a memory warning.",
|
||||
render(): ReactElement { return <AppStateSubscription showMemoryWarnings={true} />; }
|
||||
},
|
||||
];
|
||||
|
||||
@@ -80,6 +80,17 @@ var styles = StyleSheet.create({
|
||||
|
||||
borderTopLeftRadius: 100,
|
||||
},
|
||||
border7: {
|
||||
borderWidth: 10,
|
||||
borderColor: 'rgba(255,0,0,0.5)',
|
||||
borderRadius: 30,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
border7_inner: {
|
||||
backgroundColor: 'blue',
|
||||
width: 100,
|
||||
height: 100
|
||||
},
|
||||
});
|
||||
|
||||
exports.title = 'Border';
|
||||
@@ -134,4 +145,15 @@ exports.examples = [
|
||||
return <View style={[styles.box, styles.border6]} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Custom Borders',
|
||||
description: 'borderRadius & clipping',
|
||||
render() {
|
||||
return (
|
||||
<View style={[styles.box, styles.border7]}>
|
||||
<View style={styles.border7_inner} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
@@ -59,6 +59,16 @@ var propTypes = {
|
||||
* imagesPerRow: Number of images to be shown in each row.
|
||||
*/
|
||||
imagesPerRow: React.PropTypes.number,
|
||||
|
||||
/**
|
||||
* The asset type, one of 'Photos', 'Videos' or 'All'
|
||||
*/
|
||||
assetType: React.PropTypes.oneOf([
|
||||
'Photos',
|
||||
'Videos',
|
||||
'All',
|
||||
]),
|
||||
|
||||
};
|
||||
|
||||
var CameraRollView = React.createClass({
|
||||
@@ -69,6 +79,7 @@ var CameraRollView = React.createClass({
|
||||
groupTypes: 'SavedPhotos',
|
||||
batchSize: 5,
|
||||
imagesPerRow: 1,
|
||||
assetType: 'Photos',
|
||||
renderImage: function(asset) {
|
||||
var imageSize = 150;
|
||||
var imageStyle = [styles.image, {width: imageSize, height: imageSize}];
|
||||
@@ -89,6 +100,7 @@ var CameraRollView = React.createClass({
|
||||
assets: ([]: Array<Image>),
|
||||
groupTypes: this.props.groupTypes,
|
||||
lastCursor: (null : ?string),
|
||||
assetType: this.props.assetType,
|
||||
noMore: false,
|
||||
loadingMore: false,
|
||||
dataSource: ds,
|
||||
@@ -124,7 +136,8 @@ var CameraRollView = React.createClass({
|
||||
|
||||
var fetchParams: Object = {
|
||||
first: this.props.batchSize,
|
||||
groupTypes: this.props.groupTypes
|
||||
groupTypes: this.props.groupTypes,
|
||||
assetType: this.props.assetType,
|
||||
};
|
||||
if (this.state.lastCursor) {
|
||||
fetchParams.after = this.state.lastCursor;
|
||||
|
||||
@@ -29,13 +29,13 @@ var ReachabilitySubscription = React.createClass({
|
||||
};
|
||||
},
|
||||
componentDidMount: function() {
|
||||
NetInfo.reachabilityIOS.addEventListener(
|
||||
NetInfo.addEventListener(
|
||||
'change',
|
||||
this._handleReachabilityChange
|
||||
);
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
NetInfo.reachabilityIOS.removeEventListener(
|
||||
NetInfo.removeEventListener(
|
||||
'change',
|
||||
this._handleReachabilityChange
|
||||
);
|
||||
@@ -63,16 +63,16 @@ var ReachabilityCurrent = React.createClass({
|
||||
};
|
||||
},
|
||||
componentDidMount: function() {
|
||||
NetInfo.reachabilityIOS.addEventListener(
|
||||
NetInfo.addEventListener(
|
||||
'change',
|
||||
this._handleReachabilityChange
|
||||
);
|
||||
NetInfo.reachabilityIOS.fetch().done(
|
||||
NetInfo.fetch().done(
|
||||
(reachability) => { this.setState({reachability}); }
|
||||
);
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
NetInfo.reachabilityIOS.removeEventListener(
|
||||
NetInfo.removeEventListener(
|
||||
'change',
|
||||
this._handleReachabilityChange
|
||||
);
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
ProgressViewIOS,
|
||||
StyleSheet,
|
||||
View,
|
||||
} = React;
|
||||
var TimerMixin = require('react-timer-mixin');
|
||||
|
||||
var ProgressViewExample = React.createClass({
|
||||
mixins: [TimerMixin],
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
progress: 0,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
this.updateProgress();
|
||||
},
|
||||
|
||||
updateProgress() {
|
||||
var progress = this.state.progress + 0.01;
|
||||
this.setState({ progress });
|
||||
this.requestAnimationFrame(() => this.updateProgress());
|
||||
},
|
||||
|
||||
getProgress(offset) {
|
||||
var progress = this.state.progress + offset;
|
||||
return Math.sin(progress % Math.PI) % 1;
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ProgressViewIOS style={styles.progressView} progress={this.getProgress(0)}/>
|
||||
<ProgressViewIOS style={styles.progressView} progressTintColor="purple" progress={this.getProgress(0.2)}/>
|
||||
<ProgressViewIOS style={styles.progressView} progressTintColor="red" progress={this.getProgress(0.4)}/>
|
||||
<ProgressViewIOS style={styles.progressView} progressTintColor="orange" progress={this.getProgress(0.6)}/>
|
||||
<ProgressViewIOS style={styles.progressView} progressTintColor="yellow" progress={this.getProgress(0.8)}/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
exports.framework = 'React';
|
||||
exports.title = 'ProgressViewIOS';
|
||||
exports.description = 'ProgressViewIOS';
|
||||
exports.examples = [{
|
||||
title: 'ProgressViewIOS',
|
||||
render() {
|
||||
return (
|
||||
<ProgressViewExample/>
|
||||
);
|
||||
}
|
||||
}];
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
container: {
|
||||
marginTop: -20,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
progressView: {
|
||||
marginTop: 20,
|
||||
}
|
||||
});
|
||||
@@ -32,11 +32,11 @@ exports.examples = [{
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
{Object.keys(StatusBarIOS.Style).map((key) =>
|
||||
{['default', 'light-content'].map((style) =>
|
||||
<TouchableHighlight style={styles.wrapper}
|
||||
onPress={() => StatusBarIOS.setStyle(StatusBarIOS.Style[key])}>
|
||||
onPress={() => StatusBarIOS.setStyle(style)}>
|
||||
<View style={styles.button}>
|
||||
<Text>setStyle(StatusBarIOS.Style.{key})</Text>
|
||||
<Text>setStyle('{style}')</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
)}
|
||||
@@ -48,11 +48,11 @@ exports.examples = [{
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
{Object.keys(StatusBarIOS.Style).map((key) =>
|
||||
{['default', 'light-content'].map((style) =>
|
||||
<TouchableHighlight style={styles.wrapper}
|
||||
onPress={() => StatusBarIOS.setStyle(StatusBarIOS.Style[key], true)}>
|
||||
onPress={() => StatusBarIOS.setStyle(style, true)}>
|
||||
<View style={styles.button}>
|
||||
<Text>setStyle(StatusBarIOS.Style.{key}, true)</Text>
|
||||
<Text>setStyle('{style}', true)</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
)}
|
||||
@@ -64,18 +64,18 @@ exports.examples = [{
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
{Object.keys(StatusBarIOS.Animation).map((key) =>
|
||||
{['none', 'fade', 'slide'].map((animation) =>
|
||||
<View>
|
||||
<TouchableHighlight style={styles.wrapper}
|
||||
onPress={() => StatusBarIOS.setHidden(true, StatusBarIOS.Animation[key])}>
|
||||
onPress={() => StatusBarIOS.setHidden(true, animation)}>
|
||||
<View style={styles.button}>
|
||||
<Text>setHidden(true, StatusBarIOS.Animation.{key})</Text>
|
||||
<Text>setHidden(true, '{animation}')</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight style={styles.wrapper}
|
||||
onPress={() => StatusBarIOS.setHidden(false, StatusBarIOS.Animation[key])}>
|
||||
onPress={() => StatusBarIOS.setHidden(false, animation)}>
|
||||
<View style={styles.button}>
|
||||
<Text>setHidden(false, StatusBarIOS.Animation.{key})</Text>
|
||||
<Text>setHidden(false, '{animation}')</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
|
||||
@@ -48,7 +48,9 @@ var TabBarExample = React.createClass({
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<TabBarIOS>
|
||||
<TabBarIOS
|
||||
tintColor="black"
|
||||
barTintColor="#3abeff">
|
||||
<TabBarIOS.Item
|
||||
title="Blue Tab"
|
||||
selected={this.state.selectedTab === 'blueTab'}
|
||||
|
||||
@@ -300,17 +300,17 @@ exports.examples = [
|
||||
title: 'containerBackgroundColor attribute',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<View style={{flexDirection: 'row', height: 85}}>
|
||||
<View style={{backgroundColor: '#ffaaaa', width: 150}} />
|
||||
<View style={{backgroundColor: '#aaaaff', width: 150}} />
|
||||
<View style={{backgroundColor: 'yellow'}}>
|
||||
<View style={{flexDirection: 'row', position: 'absolute', height: 80}}>
|
||||
<View style={{backgroundColor: '#ffaaaa', width: 140}} />
|
||||
<View style={{backgroundColor: '#aaaaff', width: 140}} />
|
||||
</View>
|
||||
<Text style={[styles.backgroundColorText, {top: -80}]}>
|
||||
<Text style={styles.backgroundColorText}>
|
||||
Default containerBackgroundColor (inherited) + backgroundColor wash
|
||||
</Text>
|
||||
<Text style={[
|
||||
styles.backgroundColorText,
|
||||
{top: -70, containerBackgroundColor: 'transparent'}]}>
|
||||
{marginBottom: 5, containerBackgroundColor: 'transparent'}]}>
|
||||
{"containerBackgroundColor: 'transparent' + backgroundColor wash"}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -322,13 +322,13 @@ exports.examples = [
|
||||
return (
|
||||
<View>
|
||||
<Text numberOfLines={1}>
|
||||
Maximum of one line no matter now much I write here. If I keep writing it{"'"}ll just truncate after one line
|
||||
Maximum of one line, no matter how much I write here. If I keep writing, it{"'"}ll just truncate after one line.
|
||||
</Text>
|
||||
<Text numberOfLines={2} style={{marginTop: 20}}>
|
||||
Maximum of two lines no matter now much I write here. If I keep writing it{"'"}ll just truncate after two lines
|
||||
Maximum of two lines, no matter how much I write here. If I keep writing, it{"'"}ll just truncate after two lines.
|
||||
</Text>
|
||||
<Text style={{marginTop: 20}}>
|
||||
No maximum lines specified no matter now much I write here. If I keep writing it{"'"}ll just keep going and going
|
||||
No maximum lines specified, no matter how much I write here. If I keep writing, it{"'"}ll just keep going and going.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
@@ -337,7 +337,8 @@ exports.examples = [
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
backgroundColorText: {
|
||||
left: 5,
|
||||
margin: 5,
|
||||
marginBottom: 0,
|
||||
backgroundColor: 'rgba(100, 100, 100, 0.3)'
|
||||
},
|
||||
entity: {
|
||||
|
||||
@@ -75,6 +75,14 @@ exports.examples = [
|
||||
render: function(): ReactElement {
|
||||
return <TouchableFeedbackEvents />;
|
||||
},
|
||||
}, {
|
||||
title: 'Touchable delay for events',
|
||||
description: '<Touchable*> components also accept delayPressIn, ' +
|
||||
'delayPressOut, and delayLongPress as props. These props impact the ' +
|
||||
'timing of feedback events.',
|
||||
render: function(): ReactElement {
|
||||
return <TouchableDelayEvents />;
|
||||
},
|
||||
}];
|
||||
|
||||
var TextOnPressBox = React.createClass({
|
||||
@@ -148,6 +156,44 @@ var TouchableFeedbackEvents = React.createClass({
|
||||
},
|
||||
});
|
||||
|
||||
var TouchableDelayEvents = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
eventLog: [],
|
||||
};
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<View style={[styles.row, {justifyContent: 'center'}]}>
|
||||
<TouchableOpacity
|
||||
style={styles.wrapper}
|
||||
onPress={() => this._appendEvent('press')}
|
||||
delayPressIn={400}
|
||||
onPressIn={() => this._appendEvent('pressIn - 400ms delay')}
|
||||
delayPressOut={1000}
|
||||
onPressOut={() => this._appendEvent('pressOut - 1000ms delay')}
|
||||
delayLongPress={800}
|
||||
onLongPress={() => this._appendEvent('longPress - 800ms delay')}>
|
||||
<Text style={styles.button}>
|
||||
Press Me
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.eventLogBox}>
|
||||
{this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
_appendEvent: function(eventName) {
|
||||
var limit = 6;
|
||||
var eventLog = this.state.eventLog.slice(0, limit - 1);
|
||||
eventLog.unshift(eventName);
|
||||
this.setState({eventLog});
|
||||
},
|
||||
});
|
||||
|
||||
var heartImage = {uri: 'https://pbs.twimg.com/media/BlXBfT3CQAA6cVZ.png:small'};
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule TransformExample
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('React');
|
||||
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var TimerMixin = require('react-timer-mixin');
|
||||
var UIExplorerBlock = require('UIExplorerBlock');
|
||||
var UIExplorerPage = require('UIExplorerPage');
|
||||
var View = require('View');
|
||||
|
||||
var TransformExample = React.createClass({
|
||||
|
||||
mixins: [TimerMixin],
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
interval: this.setInterval(this._update, 800),
|
||||
pulse: false,
|
||||
};
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<UIExplorerPage title="Transforms">
|
||||
<UIExplorerBlock title="foo bar">
|
||||
<View style={{height: 500}}>
|
||||
<View style={styles.box1} />
|
||||
<View style={styles.box2} />
|
||||
<View style={styles.box3step1} />
|
||||
<View style={styles.box3step2} />
|
||||
<View style={styles.box3step3} />
|
||||
<View style={styles.box4} />
|
||||
<View style={[
|
||||
styles.box5,
|
||||
this.state.pulse ? styles.box5Transform : null
|
||||
]} />
|
||||
</View>
|
||||
</UIExplorerBlock>
|
||||
</UIExplorerPage>
|
||||
);
|
||||
},
|
||||
|
||||
_update() {
|
||||
this.setState({
|
||||
pulse: !this.state.pulse,
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
box1: {
|
||||
left: 0,
|
||||
backgroundColor: 'green',
|
||||
height: 50,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
transform: [
|
||||
{translateX: 100},
|
||||
{translateY: 50},
|
||||
{rotate: '30deg'},
|
||||
{scaleX: 2},
|
||||
{scaleY: 2},
|
||||
],
|
||||
width: 50,
|
||||
},
|
||||
box2: {
|
||||
left: 0,
|
||||
backgroundColor: 'purple',
|
||||
height: 50,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
transform: [
|
||||
{scaleX: 2},
|
||||
{scaleY: 2},
|
||||
{translateX: 100},
|
||||
{translateY: 50},
|
||||
{rotate: '30deg'},
|
||||
],
|
||||
width: 50,
|
||||
},
|
||||
box3step1: {
|
||||
left: 0,
|
||||
backgroundColor: '#ffb6c1', // lightpink
|
||||
height: 50,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
transform: [
|
||||
{rotate: '30deg'},
|
||||
],
|
||||
width: 50,
|
||||
},
|
||||
box3step2: {
|
||||
left: 0,
|
||||
backgroundColor: '#ff69b4', //hotpink
|
||||
height: 50,
|
||||
opacity: 0.5,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
transform: [
|
||||
{rotate: '30deg'},
|
||||
{scaleX: 2},
|
||||
{scaleY: 2},
|
||||
],
|
||||
width: 50,
|
||||
},
|
||||
box3step3: {
|
||||
left: 0,
|
||||
backgroundColor: '#ff1493', // deeppink
|
||||
height: 50,
|
||||
opacity: 0.5,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
transform: [
|
||||
{rotate: '30deg'},
|
||||
{scaleX: 2},
|
||||
{scaleY: 2},
|
||||
{translateX: 100},
|
||||
{translateY: 50},
|
||||
],
|
||||
width: 50,
|
||||
},
|
||||
box4: {
|
||||
left: 0,
|
||||
backgroundColor: '#ff8c00', // darkorange
|
||||
height: 50,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
transform: [
|
||||
{translate: [200, 350]},
|
||||
{scale: 2.5},
|
||||
{rotate: '-0.2rad'},
|
||||
],
|
||||
width: 100,
|
||||
},
|
||||
box5: {
|
||||
backgroundColor: '#800000', // maroon
|
||||
height: 50,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
width: 50,
|
||||
},
|
||||
box5Transform: {
|
||||
transform: [
|
||||
{translate: [-50, 35]},
|
||||
{rotate: '50deg'},
|
||||
{scale: 2},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
module.exports = TransformExample;
|
||||
@@ -13,6 +13,7 @@
|
||||
1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341802B1AA91779003F314A /* libRCTNetwork.a */; };
|
||||
134454601AAFCABD003F0779 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1344545A1AAFCAAE003F0779 /* libRCTAdSupport.a */; };
|
||||
134A8A2A1AACED7A00945AAE /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 134A8A251AACED6A00945AAE /* libRCTGeolocation.a */; };
|
||||
1353F5461B0E64F9009B4FAC /* ClippingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1353F5451B0E64F9009B4FAC /* ClippingTests.m */; };
|
||||
139FDEDB1B0651FB00C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */; };
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
|
||||
@@ -129,6 +130,7 @@
|
||||
134180261AA91779003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
|
||||
134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAdSupport.xcodeproj; path = ../../Libraries/AdSupport/RCTAdSupport.xcodeproj; sourceTree = "<group>"; };
|
||||
134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../../Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
|
||||
1353F5451B0E64F9009B4FAC /* ClippingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ClippingTests.m; sourceTree = "<group>"; };
|
||||
139FDECA1B0651EA00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = "<group>"; };
|
||||
13B07F961A680F5B00A75B9A /* UIExplorer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UIExplorer.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = UIExplorer/AppDelegate.h; sourceTree = "<group>"; };
|
||||
@@ -179,6 +181,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
004D28A21AAF61C70097A701 /* UIExplorerTests.m */,
|
||||
1353F5451B0E64F9009B4FAC /* ClippingTests.m */,
|
||||
004D28A01AAF61C70097A701 /* Supporting Files */,
|
||||
);
|
||||
path = UIExplorerTests;
|
||||
@@ -575,6 +578,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
004D28A31AAF61C70097A701 /* UIExplorerTests.m in Sources */,
|
||||
1353F5461B0E64F9009B4FAC /* ClippingTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -50,6 +50,10 @@
|
||||
|
||||
// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
|
||||
#if RUNNING_ON_CI
|
||||
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
#endif
|
||||
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
|
||||
moduleName:@"UIExplorerApp"
|
||||
launchOptions:launchOptions];
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.facebook.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<string>com.facebook.internal.uiexplorer.local</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
@@ -22,6 +22,8 @@
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>You need to add NSLocationWhenInUseUsageDescription key in Info.plist to enable geolocation, otherwise it is going to *fail silently*!</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
@@ -34,8 +36,6 @@
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>You need to add NSLocationWhenInUseUsageDescription key in Info.plist to enable geolocation, otherwise it is going to *fail silently*!</string>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
|
||||
@@ -77,13 +77,7 @@ var styles = StyleSheet.create({
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 5,
|
||||
},
|
||||
titleRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
titleText: {
|
||||
backgroundColor: 'transparent',
|
||||
fontSize: 14,
|
||||
fontWeight: '500',
|
||||
},
|
||||
@@ -101,8 +95,7 @@ var styles = StyleSheet.create({
|
||||
height: 8,
|
||||
},
|
||||
children: {
|
||||
backgroundColor: 'transparent',
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ var {
|
||||
var { TestModule } = React.addons;
|
||||
var Settings = require('Settings');
|
||||
|
||||
import type { Example, ExampleModule } from 'ExampleTypes';
|
||||
import type { ExampleModule } from 'ExampleTypes';
|
||||
|
||||
var createExamplePage = require('./createExamplePage');
|
||||
|
||||
@@ -45,6 +45,7 @@ var COMPONENTS = [
|
||||
require('./NavigatorIOSColorsExample'),
|
||||
require('./NavigatorIOSExample'),
|
||||
require('./PickerIOSExample'),
|
||||
require('./ProgressViewIOSExample'),
|
||||
require('./ScrollViewExample'),
|
||||
require('./SegmentedControlIOSExample'),
|
||||
require('./SliderIOSExample'),
|
||||
@@ -58,6 +59,7 @@ var COMPONENTS = [
|
||||
];
|
||||
|
||||
var APIS = [
|
||||
require('./AccessibilityIOSExample'),
|
||||
require('./ActionSheetIOSExample'),
|
||||
require('./AdSupportIOSExample'),
|
||||
require('./AlertIOSExample'),
|
||||
@@ -153,7 +155,9 @@ class UIExplorerList extends React.Component {
|
||||
dataSource={this.state.dataSource}
|
||||
renderRow={this._renderRow.bind(this)}
|
||||
renderSectionHeader={this._renderSectionHeader}
|
||||
keyboardShouldPersistTaps={true}
|
||||
automaticallyAdjustContentInsets={false}
|
||||
keyboardDismissMode="on-drag"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIView.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
extern CGRect RCTClipRect(CGSize contentSize, CGFloat contentScale,
|
||||
CGSize targetSize, CGFloat targetScale,
|
||||
UIViewContentMode resizeMode);
|
||||
|
||||
#define RCTAssertEqualPoints(a, b) { \
|
||||
XCTAssertEqual(a.x, b.x); \
|
||||
XCTAssertEqual(a.y, b.y); \
|
||||
}
|
||||
|
||||
#define RCTAssertEqualSizes(a, b) { \
|
||||
XCTAssertEqual(a.width, b.width); \
|
||||
XCTAssertEqual(a.height, b.height); \
|
||||
}
|
||||
|
||||
#define RCTAssertEqualRects(a, b) { \
|
||||
RCTAssertEqualPoints(a.origin, b.origin); \
|
||||
RCTAssertEqualSizes(a.size, b.size); \
|
||||
}
|
||||
|
||||
@interface ClippingTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation ClippingTests
|
||||
|
||||
- (void)testLandscapeSourceLandscapeTarget
|
||||
{
|
||||
CGSize content = {1000, 100};
|
||||
CGSize target = {100, 20};
|
||||
|
||||
{
|
||||
CGRect expected = {CGPointZero, {100, 20}};
|
||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleToFill);
|
||||
RCTAssertEqualRects(expected, result);
|
||||
}
|
||||
|
||||
{
|
||||
CGRect expected = {CGPointZero, {100, 10}};
|
||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFit);
|
||||
RCTAssertEqualRects(expected, result);
|
||||
}
|
||||
|
||||
{
|
||||
CGRect expected = {{-50, 0}, {200, 20}};
|
||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFill);
|
||||
RCTAssertEqualRects(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testPortraitSourceLandscapeTarget
|
||||
{
|
||||
CGSize content = {10, 100};
|
||||
CGSize target = {100, 20};
|
||||
|
||||
{
|
||||
CGRect expected = {CGPointZero, {10, 20}};
|
||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleToFill);
|
||||
RCTAssertEqualRects(expected, result);
|
||||
}
|
||||
|
||||
{
|
||||
CGRect expected = {CGPointZero, {2, 20}};
|
||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFit);
|
||||
RCTAssertEqualRects(expected, result);
|
||||
}
|
||||
|
||||
{
|
||||
CGRect expected = {{0, -49}, {10, 100}};
|
||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFill);
|
||||
RCTAssertEqualRects(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testPortraitSourcePortraitTarget
|
||||
{
|
||||
CGSize content = {10, 100};
|
||||
CGSize target = {20, 50};
|
||||
|
||||
{
|
||||
CGRect expected = {CGPointZero, {10, 50}};
|
||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleToFill);
|
||||
RCTAssertEqualRects(expected, result);
|
||||
}
|
||||
|
||||
{
|
||||
CGRect expected = {CGPointZero, {5, 50}};
|
||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFit);
|
||||
RCTAssertEqualRects(expected, result);
|
||||
}
|
||||
|
||||
{
|
||||
CGRect expected = {{0, -37.5}, {10, 100}};
|
||||
CGRect result = RCTClipRect(content, 1, target, 1, UIViewContentModeScaleAspectFill);
|
||||
RCTAssertEqualRects(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testScaling
|
||||
{
|
||||
CGSize content = {2, 2};
|
||||
CGSize target = {3, 3};
|
||||
|
||||
CGRect expected = {CGPointZero, {3, 3}};
|
||||
CGRect result = RCTClipRect(content, 2, target, 1, UIViewContentModeScaleToFill);
|
||||
RCTAssertEqualRects(expected, result);
|
||||
}
|
||||
|
||||
@end
|
||||
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 352 KiB After Width: | Height: | Size: 269 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 86 KiB |
@@ -38,7 +38,7 @@
|
||||
RCTAssert(!__LP64__, @"Snapshot tests should be run on 32-bit device simulators (e.g. iPhone 5)");
|
||||
#endif
|
||||
NSString *version = [[UIDevice currentDevice] systemVersion];
|
||||
RCTAssert([version isEqualToString:@"8.1"], @"Snapshot tests should be run on iOS 8.1, found %@", version);
|
||||
RCTAssert([version isEqualToString:@"8.3"], @"Snapshot tests should be run on iOS 8.3, found %@", version);
|
||||
_runner = RCTInitRunnerForApp(@"Examples/UIExplorer/UIExplorerApp");
|
||||
|
||||
// If tests have changes, set recordMode = YES below and run the affected
|
||||
@@ -62,6 +62,9 @@
|
||||
// Make sure this test runs first because the other tests will tear out the rootView
|
||||
- (void)testAAA_RootViewLoadsAndRenders
|
||||
{
|
||||
// TODO (t7296305) Fix and Re-Enable this UIExplorer Test
|
||||
return;
|
||||
|
||||
UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController;
|
||||
RCTAssert([vc.view isKindOfClass:[RCTRootView class]], @"This test must run first.");
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
|
||||
@@ -74,18 +77,15 @@
|
||||
|
||||
redboxError = [[RCTRedBox sharedInstance] currentErrorMessage];
|
||||
foundElement = [self findSubviewInView:vc.view matching:^(UIView *view) {
|
||||
if ([view respondsToSelector:@selector(attributedText)]) {
|
||||
NSString *text = [(id)view attributedText].string;
|
||||
if ([text isEqualToString:@"<View>"]) {
|
||||
return YES;
|
||||
}
|
||||
if ([view.accessibilityLabel isEqualToString:@"<View>"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}];
|
||||
}
|
||||
|
||||
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
|
||||
XCTAssertTrue(foundElement, @"Cound't find element with '<View>' text in %d seconds", TIMEOUT_SECONDS);
|
||||
XCTAssertTrue(foundElement, @"Couldn't find element with '<View>' text in %d seconds", TIMEOUT_SECONDS);
|
||||
}
|
||||
|
||||
#define RCT_SNAPSHOT_TEST(name, reRecord) \
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AppEventsTest
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
NativeAppEventEmitter,
|
||||
NativeModules,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
var TestModule = NativeModules.TestModule || NativeModules.SnapshotTestManager;
|
||||
|
||||
var deepDiffer = require('deepDiffer');
|
||||
|
||||
var TEST_PAYLOAD = {foo: 'bar'};
|
||||
|
||||
var AppEventsTest = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {sent: 'none', received: 'none'};
|
||||
},
|
||||
componentDidMount: function() {
|
||||
NativeAppEventEmitter.addListener('testEvent', this.receiveEvent);
|
||||
var event = {data: TEST_PAYLOAD, ts: Date.now()};
|
||||
TestModule.sendAppEvent('testEvent', event);
|
||||
this.setState({sent: event});
|
||||
},
|
||||
receiveEvent: function(event: any) {
|
||||
if (deepDiffer(event.data, TEST_PAYLOAD)) {
|
||||
throw new Error('Received wrong event: ' + JSON.stringify(event));
|
||||
}
|
||||
var elapsed = (Date.now() - event.ts) + 'ms';
|
||||
this.setState({received: event, elapsed}, TestModule.markTestCompleted);
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>
|
||||
{JSON.stringify(this.state, null, ' ')}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
container: {
|
||||
margin: 40,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = AppEventsTest;
|
||||
@@ -16,12 +16,19 @@ var {
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var deepDiffer = require('deepDiffer');
|
||||
|
||||
var DEBUG = false;
|
||||
|
||||
var KEY_1 = 'key_1';
|
||||
var VAL_1 = 'val_1';
|
||||
var KEY_2 = 'key_2';
|
||||
var VAL_2 = 'val_2';
|
||||
var KEY_MERGE = 'key_merge';
|
||||
var VAL_MERGE_1 = {'foo': 1, 'bar': {'hoo': 1, 'boo': 1}, 'moo': {'a': 3}};
|
||||
var VAL_MERGE_2 = {'bar': {'hoo': 2}, 'baz': 2, 'moo': {'a': 3}};
|
||||
var VAL_MERGE_EXPECT =
|
||||
{'foo': 1, 'bar': {'hoo': 2, 'boo': 1}, 'baz': 2, 'moo': {'a': 3}};
|
||||
|
||||
// setup in componentDidMount
|
||||
var done;
|
||||
@@ -40,8 +47,9 @@ function expectTrue(condition, message) {
|
||||
|
||||
function expectEqual(lhs, rhs, testname) {
|
||||
expectTrue(
|
||||
lhs === rhs,
|
||||
'Error in test ' + testname + ': expected ' + rhs + ', got ' + lhs
|
||||
!deepDiffer(lhs, rhs),
|
||||
'Error in test ' + testname + ': expected\n' + JSON.stringify(rhs) +
|
||||
'\ngot\n' + JSON.stringify(lhs)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,25 +101,25 @@ function testRemoveItem() {
|
||||
'Missing KEY_1 or KEY_2 in ' + '(' + result + ')'
|
||||
);
|
||||
updateMessage('testRemoveItem - add two items');
|
||||
AsyncStorage.removeItem(KEY_1, (err) => {
|
||||
expectAsyncNoError(err);
|
||||
AsyncStorage.removeItem(KEY_1, (err2) => {
|
||||
expectAsyncNoError(err2);
|
||||
updateMessage('delete successful ');
|
||||
AsyncStorage.getItem(KEY_1, (err, result) => {
|
||||
expectAsyncNoError(err);
|
||||
AsyncStorage.getItem(KEY_1, (err3, result2) => {
|
||||
expectAsyncNoError(err3);
|
||||
expectEqual(
|
||||
result,
|
||||
result2,
|
||||
null,
|
||||
'testRemoveItem: key_1 present after delete'
|
||||
);
|
||||
updateMessage('key properly removed ');
|
||||
AsyncStorage.getAllKeys((err, result2) => {
|
||||
expectAsyncNoError(err);
|
||||
AsyncStorage.getAllKeys((err4, result3) => {
|
||||
expectAsyncNoError(err4);
|
||||
expectTrue(
|
||||
result2.indexOf(KEY_1) === -1,
|
||||
'Unexpected: KEY_1 present in ' + result2
|
||||
result3.indexOf(KEY_1) === -1,
|
||||
'Unexpected: KEY_1 present in ' + result3
|
||||
);
|
||||
updateMessage('proper length returned.\nDone!');
|
||||
done();
|
||||
updateMessage('proper length returned.');
|
||||
runTestCase('should merge values', testMerge);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -120,6 +128,21 @@ function testRemoveItem() {
|
||||
});
|
||||
}
|
||||
|
||||
function testMerge() {
|
||||
AsyncStorage.setItem(KEY_MERGE, JSON.stringify(VAL_MERGE_1), (err1) => {
|
||||
expectAsyncNoError(err1);
|
||||
AsyncStorage.mergeItem(KEY_MERGE, JSON.stringify(VAL_MERGE_2), (err2) => {
|
||||
expectAsyncNoError(err2);
|
||||
AsyncStorage.getItem(KEY_MERGE, (err3, result) => {
|
||||
expectAsyncNoError(err3);
|
||||
expectEqual(JSON.parse(result), VAL_MERGE_EXPECT, 'testMerge');
|
||||
updateMessage('objects deeply merged\nDone!');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var AsyncStorageTest = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
|
||||
@@ -26,6 +26,7 @@ var TESTS = [
|
||||
require('./TimersTest'),
|
||||
require('./AsyncStorageTest'),
|
||||
require('./LayoutEventsTest'),
|
||||
require('./AppEventsTest'),
|
||||
require('./SimpleSnapshotTest'),
|
||||
];
|
||||
|
||||
|
||||
@@ -76,6 +76,11 @@
|
||||
[_runner runTest:_cmd module:@"LayoutEventsTest"];
|
||||
}
|
||||
|
||||
- (void)testAppEvents
|
||||
{
|
||||
[_runner runTest:_cmd module:@"AppEventsTest"];
|
||||
}
|
||||
|
||||
#pragma mark Snapshot Tests
|
||||
|
||||
- (void)testSimpleSnapshot
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
*
|
||||
* @providesModule ARTSerializablePath
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
// TODO: Move this into an ART mode called "serialized" or something
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
*
|
||||
* @providesModule ReactNativeART
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var Color = require('art/core/color');
|
||||
var Path = require('ARTSerializablePath');
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
jest.autoMockOff();
|
||||
|
||||
var AnimationUtils = require('AnimationUtils');
|
||||
|
||||
describe('AnimationUtils', function() {
|
||||
var DURATION = 300;
|
||||
|
||||
var Samples = {
|
||||
easeInQuad: [0,0.0030864197530864196,0.012345679012345678,0.027777777777777776,0.04938271604938271,0.0771604938271605,0.1111111111111111,0.15123456790123457,0.19753086419753085,0.25,0.308641975308642,0.37345679012345684,0.4444444444444444,0.5216049382716049,0.6049382716049383,0.6944444444444445,0.7901234567901234,0.8919753086419753,1],
|
||||
easeOutQuad: [0,0.10802469135802469,0.20987654320987653,0.3055555555555555,0.3950617283950617,0.47839506172839513,0.5555555555555556,0.6265432098765432,0.691358024691358,0.75,0.8024691358024691,0.8487654320987654,0.888888888888889,0.9228395061728394,0.9506172839506174,0.9722222222222221,0.9876543209876543,0.9969135802469136,1],
|
||||
easeInOutQuad: [0,0.006172839506172839,0.024691358024691357,0.05555555555555555,0.09876543209876543,0.154320987654321,0.2222222222222222,0.30246913580246915,0.3950617283950617,0.5,0.6049382716049383,0.697530864197531,0.7777777777777777,0.845679012345679,0.9012345679012346,0.9444444444444444,0.9753086419753086,0.9938271604938271,1],
|
||||
easeInCubic: [0,0.00017146776406035664,0.0013717421124828531,0.004629629629629629,0.010973936899862825,0.021433470507544586,0.037037037037037035,0.05881344307270234,0.0877914951989026,0.125,0.1714677640603567,0.22822359396433475,0.2962962962962963,0.37671467764060357,0.4705075445816187,0.5787037037037038,0.7023319615912208,0.8424211248285322,1],
|
||||
easeOutCubic: [0,0.15757887517146785,0.2976680384087792,0.42129629629629617,0.5294924554183813,0.6232853223593964,0.7037037037037036,0.7717764060356652,0.8285322359396433,0.875,0.9122085048010974,0.9411865569272977,0.9629629629629629,0.9785665294924554,0.9890260631001372,0.9953703703703703,0.9986282578875172,0.9998285322359396,1],
|
||||
easeInOutCubic: [0,0.0006858710562414266,0.0054869684499314125,0.018518518518518517,0.0438957475994513,0.08573388203017834,0.14814814814814814,0.23525377229080935,0.3511659807956104,0.5,0.6488340192043895,0.7647462277091908,0.8518518518518519,0.9142661179698217,0.9561042524005487,0.9814814814814815,0.9945130315500685,0.9993141289437586,1],
|
||||
easeInQuart: [0,0.000009525986892242035,0.00015241579027587256,0.0007716049382716049,0.002438652644413961,0.005953741807651274,0.012345679012345678,0.02287189452827313,0.039018442310623375,0.0625,0.09525986892242039,0.1394699740893157,0.19753086419753085,0.2720717116293248,0.3659503124523701,0.48225308641975323,0.624295076969974,0.7956199512269471,1],
|
||||
easeOutQuart: [0,0.20438004877305294,0.375704923030026,0.5177469135802468,0.6340496875476299,0.7279282883706752,0.802469135802469,0.8605300259106843,0.9047401310775796,0.9375,0.9609815576893767,0.9771281054717269,0.9876543209876543,0.9940462581923487,0.997561347355586,0.9992283950617284,0.9998475842097241,0.9999904740131078,1],
|
||||
easeInOutQuart: [0,0.00007620789513793628,0.0012193263222069805,0.006172839506172839,0.019509221155311687,0.047629934461210194,0.09876543209876543,0.18297515622618504,0.312147538484987,0.5,0.687852461515013,0.8170248437738151,0.9012345679012346,0.9523700655387898,0.9804907788446883,0.9938271604938271,0.998780673677793,0.999923792104862,1],
|
||||
easeInQuint: [0,5.292214940134463e-7,0.000016935087808430282,0.00012860082304526747,0.000541922809869769,0.0016538171687920206,0.004115226337448559,0.008894625649883995,0.01734152991583261,0.03125,0.05292214940134466,0.08523165083235959,0.1316872427983539,0.1964962361767346,0.28462802079628785,0.401877572016461,0.5549289573066435,0.75141884282545,1],
|
||||
easeOutQuint: [0,0.24858115717454998,0.4450710426933565,0.598122427983539,0.7153719792037121,0.8035037638232654,0.868312757201646,0.9147683491676404,0.9470778505986553,0.96875,0.9826584700841674,0.991105374350116,0.9958847736625515,0.998346182831208,0.9994580771901302,0.9998713991769548,0.9999830649121916,0.999999470778506,1],
|
||||
easeInOutQuint: [0,0.000008467543904215141,0.0002709614049348845,0.0020576131687242796,0.008670764957916305,0.02646107470067233,0.06584362139917695,0.14231401039814393,0.27746447865332174,0.5,0.7225355213466782,0.8576859896018563,0.934156378600823,0.9735389252993276,0.9913292350420837,0.9979423868312757,0.9997290385950651,0.9999915324560957,1],
|
||||
easeInSine: [0,0.003805301908254455,0.01519224698779198,0.03407417371093169,0.06030737921409157,0.09369221296335006,0.1339745962155613,0.1808479557110082,0.233955556881022,0.2928932188134524,0.35721239031346064,0.42642356364895384,0.4999999999999999,0.5773817382593005,0.6579798566743311,0.7411809548974793,0.8263518223330696,0.9128442572523416,0.9999999999999999],
|
||||
easeOutSine: [0,0.08715574274765817,0.17364817766693033,0.25881904510252074,0.3420201433256687,0.42261826174069944,0.49999999999999994,0.573576436351046,0.6427876096865393,0.7071067811865475,0.766044443118978,0.8191520442889918,0.8660254037844386,0.9063077870366499,0.9396926207859083,0.9659258262890683,0.984807753012208,0.9961946980917455,1],
|
||||
easeInOutSine: [0,0.00759612349389599,0.030153689607045786,0.06698729810778065,0.116977778440511,0.17860619515673032,0.24999999999999994,0.32898992833716556,0.4131759111665348,0.49999999999999994,0.5868240888334652,0.6710100716628343,0.7499999999999999,0.8213938048432696,0.883022221559489,0.9330127018922194,0.9698463103929542,0.9924038765061041,1],
|
||||
easeInExpo: [0,0.0014352875901128893,0.002109491677524035,0.0031003926796253885,0.004556754060844206,0.006697218616039631,0.009843133202303688,0.014466792379488908,0.021262343752724643,0.03125,0.045929202883612456,0.06750373368076916,0.09921256574801243,0.1458161299470146,0.2143109957132682,0.31498026247371835,0.46293735614364506,0.6803950000871883,1],
|
||||
easeOutExpo: [0,0.31960499991281155,0.5370626438563548,0.6850197375262816,0.7856890042867318,0.8541838700529854,0.9007874342519875,0.9324962663192309,0.9540707971163875,0.96875,0.9787376562472754,0.9855332076205111,0.9901568667976963,0.9933027813839603,0.9954432459391558,0.9968996073203746,0.9978905083224759,0.9985647124098871,1],
|
||||
easeInOutExpo: [0,0.0010547458387620175,0.002278377030422103,0.004921566601151844,0.010631171876362321,0.022964601441806228,0.049606282874006216,0.1071554978566341,0.23146867807182253,0.5,0.7685313219281775,0.892844502143366,0.9503937171259937,0.9770353985581938,0.9893688281236377,0.9950784333988482,0.9977216229695779,0.998945254161238,1],
|
||||
easeInCirc: [0,0.0015444024660317135,0.006192010000093506,0.013986702816730645,0.025003956956430873,0.03935464078941209,0.057190958417936644,0.07871533601238889,0.10419358352238339,0.1339745962155614,0.1685205807169019,0.20845517506805522,0.2546440075000701,0.3083389112228482,0.37146063894529113,0.4472292016074334,0.5418771527091488,0.6713289009389102,1],
|
||||
easeOutCirc: [0,0.3286710990610898,0.45812284729085123,0.5527707983925666,0.6285393610547089,0.6916610887771518,0.7453559924999298,0.7915448249319448,0.8314794192830981,0.8660254037844386,0.8958064164776166,0.9212846639876111,0.9428090415820634,0.9606453592105879,0.9749960430435691,0.9860132971832694,0.9938079899999065,0.9984555975339683,1],
|
||||
easeInOutCirc: [0,0.003096005000046753,0.012501978478215436,0.028595479208968322,0.052096791761191696,0.08426029035845095,0.12732200375003505,0.18573031947264557,0.2709385763545744,0.5,0.7290614236454256,0.8142696805273546,0.8726779962499649,0.915739709641549,0.9479032082388084,0.9714045207910317,0.9874980215217846,0.9969039949999532,1],
|
||||
easeInElastic: [0,0.0008570943160003016,0.0020526300563455885,0.0005383775388688477,-0.003807112477441741,-0.005595444524068916,0.0017092421431128787,0.014076838118604966,0.012696991251677569,-0.015625000000000045,-0.045618646044515744,-0.01936028903971309,0.07600123467884114,0.13030605320629246,-0.012461076179381799,-0.29598462833976175,-0.3176868895106366,0.2694906924487451,1],
|
||||
easeOutElastic: [0,0.7305093075512543,1.3176868895106364,1.2959846283397618,1.0124610761793817,0.8696939467937076,0.9239987653211588,1.019360289039713,1.0456186460445158,1.015625,0.9873030087483224,0.9859231618813951,0.9982907578568871,1.005595444524069,1.0038071124774417,0.9994616224611311,0.9979473699436544,0.9991429056839997,1],
|
||||
easeInOutElastic: [0,0.0010420781824747765,-0.0003083357248478688,-0.004888288728445655,0.0010292130059457788,0.022895545534212507,-0.0028843488305936938,-0.10707491183281304,0.004488485931276091,0.5,0.995511514068724,1.107074911832813,1.0028843488305939,0.9771044544657875,0.9989707869940542,1.0048882887284456,1.000308335724848,0.9989579218175252,1],
|
||||
easeInBack: [0,-0.004788556241426612,-0.017301289437585736,-0.0347587962962963,-0.05438167352537723,-0.07339051783264748,-0.08900592592592595,-0.09844849451303156,-0.0989388203017833,-0.08769750000000004,-0.06194513031550073,-0.018902307956104283,0.044210370370370254,0.13017230795610413,0.2417629080932785,0.3817615740740742,0.5529477091906719,0.7581007167352535,0.9999999999999998],
|
||||
easeOutBack: [2.220446049250313e-16,0.24189928326474652,0.44705229080932807,0.6182384259259258,0.7582370919067215,0.8698276920438959,0.9557896296296297,1.0189023079561044,1.0619451303155008,1.0876975,1.0989388203017834,1.0984484945130315,1.089005925925926,1.0733905178326475,1.0543816735253773,1.0347587962962963,1.0173012894375857,1.0047885562414267,1],
|
||||
easeInOutBack: [0,-0.01355231550068587,-0.04434668449931412,-0.07758924074074074,-0.09848611796982167,-0.0922434499314129,-0.0440673703703704,0.060835986968449905,0.237260488340192,0.5,0.762739511659808,0.9391640130315503,1.0440673703703702,1.0922434499314129,1.0984861179698218,1.0775892407407408,1.0443466844993141,1.0135523155006858,1],
|
||||
};
|
||||
|
||||
Object.keys(Samples).forEach(function(type) {
|
||||
it('should interpolate ' + type, function() {
|
||||
expect(AnimationUtils.evaluateEasingFunction(DURATION, type))
|
||||
.toEqual(Samples[type]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -74,7 +74,9 @@ var AppRegistry = {
|
||||
);
|
||||
invariant(
|
||||
runnables[appKey] && runnables[appKey].run,
|
||||
'Application ' + appKey + ' has not been registered.'
|
||||
'Application ' + appKey + ' has not been registered. This ' +
|
||||
'is either due to a require() error during initialization ' +
|
||||
'or failure to call AppRegistry.registerComponent.'
|
||||
);
|
||||
runnables[appKey].run(appParameters);
|
||||
},
|
||||
|
||||
@@ -11,15 +11,18 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var Map = require('Map');
|
||||
var NativeModules = require('NativeModules');
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
var RCTAppState = NativeModules.AppState;
|
||||
|
||||
var logError = require('logError');
|
||||
var invariant = require('invariant');
|
||||
|
||||
var DEVICE_APPSTATE_EVENT = 'appStateDidChange';
|
||||
|
||||
var _appStateHandlers = {};
|
||||
var _eventHandlers = {
|
||||
change: new Map(),
|
||||
memoryWarning: new Map(),
|
||||
};
|
||||
|
||||
/**
|
||||
* `AppStateIOS` can tell you if the app is in the foreground or background,
|
||||
@@ -82,12 +85,23 @@ var AppStateIOS = {
|
||||
type: string,
|
||||
handler: Function
|
||||
) {
|
||||
_appStateHandlers[handler] = RCTDeviceEventEmitter.addListener(
|
||||
DEVICE_APPSTATE_EVENT,
|
||||
(appStateData) => {
|
||||
handler(appStateData.app_state);
|
||||
}
|
||||
invariant(
|
||||
['change', 'memoryWarning'].indexOf(type) !== -1,
|
||||
'Trying to subscribe to unknown event: "%s"', type
|
||||
);
|
||||
if (type === 'change') {
|
||||
_eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
|
||||
'appStateDidChange',
|
||||
(appStateData) => {
|
||||
handler(appStateData.app_state);
|
||||
}
|
||||
));
|
||||
} else if (type === 'memoryWarning') {
|
||||
_eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
|
||||
'memoryWarning',
|
||||
handler
|
||||
));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -97,11 +111,15 @@ var AppStateIOS = {
|
||||
type: string,
|
||||
handler: Function
|
||||
) {
|
||||
if (!_appStateHandlers[handler]) {
|
||||
invariant(
|
||||
['change', 'memoryWarning'].indexOf(type) !== -1,
|
||||
'Trying to remove listener for unknown event: "%s"', type
|
||||
);
|
||||
if (!_eventHandlers[type].has(handler)) {
|
||||
return;
|
||||
}
|
||||
_appStateHandlers[handler].remove();
|
||||
_appStateHandlers[handler] = null;
|
||||
_eventHandlers[type].get(handler).remove();
|
||||
_eventHandlers[type].delete(handler);
|
||||
},
|
||||
|
||||
currentState: (null : ?String),
|
||||
@@ -109,7 +127,7 @@ var AppStateIOS = {
|
||||
};
|
||||
|
||||
RCTDeviceEventEmitter.addListener(
|
||||
DEVICE_APPSTATE_EVENT,
|
||||
'appStateDidChange',
|
||||
(appStateData) => {
|
||||
AppStateIOS.currentState = appStateData.app_state;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule POPAnimation
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
@@ -17,7 +16,7 @@ if (!RCTPOPAnimationManager) {
|
||||
// workaround to enable its availability to be determined at runtime.
|
||||
// For Flow let's pretend like we always export POPAnimation
|
||||
// so all our users don't need to do null checks
|
||||
module.exports = ((null: any): typeof POPAnimation);
|
||||
module.exports = null;
|
||||
} else {
|
||||
|
||||
var ReactPropTypes = require('ReactPropTypes');
|
||||
|
||||
@@ -29,8 +29,16 @@ var GROUP_TYPES_OPTIONS = [
|
||||
'SavedPhotos', // default
|
||||
];
|
||||
|
||||
var ASSET_TYPE_OPTIONS = [
|
||||
'All',
|
||||
'Videos',
|
||||
'Photos', // default
|
||||
];
|
||||
|
||||
|
||||
// Flow treats Object and Array as disjoint types, currently.
|
||||
deepFreezeAndThrowOnMutationInDev((GROUP_TYPES_OPTIONS: any));
|
||||
deepFreezeAndThrowOnMutationInDev((ASSET_TYPE_OPTIONS: any));
|
||||
|
||||
/**
|
||||
* Shape of the param arg for the `getPhotos` function.
|
||||
@@ -58,6 +66,11 @@ var getPhotosParamChecker = createStrictShapeTypeChecker({
|
||||
* titles.
|
||||
*/
|
||||
groupName: ReactPropTypes.string,
|
||||
|
||||
/**
|
||||
* Specifies filter on asset type
|
||||
*/
|
||||
assetType: ReactPropTypes.oneOf(ASSET_TYPE_OPTIONS),
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -94,6 +107,7 @@ var getPhotosReturnChecker = createStrictShapeTypeChecker({
|
||||
class CameraRoll {
|
||||
|
||||
static GroupTypesOptions: Array<string>;
|
||||
static AssetTypeOptions: Array<string>;
|
||||
/**
|
||||
* Saves the image with tag `tag` to the camera roll.
|
||||
*
|
||||
@@ -154,5 +168,6 @@ class CameraRoll {
|
||||
}
|
||||
|
||||
CameraRoll.GroupTypesOptions = GROUP_TYPES_OPTIONS;
|
||||
CameraRoll.AssetTypeOptions = ASSET_TYPE_OPTIONS;
|
||||
|
||||
module.exports = CameraRoll;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
'use strict';
|
||||
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var NativeModules = require('NativeModules');
|
||||
var PropTypes = require('ReactPropTypes');
|
||||
var React = require('React');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
@@ -53,6 +52,12 @@ var ActivityIndicatorIOS = React.createClass({
|
||||
'small',
|
||||
'large',
|
||||
]),
|
||||
/**
|
||||
* Invoked on mount and layout changes with
|
||||
*
|
||||
* {nativeEvent: { layout: {x, y, width, height}}}.
|
||||
*/
|
||||
onLayout: PropTypes.func,
|
||||
},
|
||||
|
||||
getDefaultProps: function(): DefaultProps {
|
||||
@@ -65,10 +70,12 @@ var ActivityIndicatorIOS = React.createClass({
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var {style, ...props} = this.props;
|
||||
var {onLayout, style, ...props} = this.props;
|
||||
var sizeStyle = (this.props.size === 'large') ? styles.sizeLarge : styles.sizeSmall;
|
||||
return (
|
||||
<View style={[styles.container, sizeStyle, style]}>
|
||||
<View
|
||||
onLayout={onLayout}
|
||||
style={[styles.container, sizeStyle, style]}>
|
||||
<RCTActivityIndicatorView {...props} />
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -120,7 +120,7 @@ var DatePickerIOS = React.createClass({
|
||||
<View style={props.style}>
|
||||
<RCTDatePickerIOS
|
||||
ref={DATEPICKER}
|
||||
style={styles.rkDatePickerIOS}
|
||||
style={styles.datePickerIOS}
|
||||
date={props.date.getTime()}
|
||||
maximumDate={
|
||||
props.maximumDate ? props.maximumDate.getTime() : undefined
|
||||
@@ -128,7 +128,7 @@ var DatePickerIOS = React.createClass({
|
||||
minimumDate={
|
||||
props.minimumDate ? props.minimumDate.getTime() : undefined
|
||||
}
|
||||
mode={RCTDatePickerIOSConsts.DatePickerModes[props.mode]}
|
||||
mode={props.mode}
|
||||
minuteInterval={props.minuteInterval}
|
||||
timeZoneOffsetInMinutes={props.timeZoneOffsetInMinutes}
|
||||
onChange={this._onChange}
|
||||
@@ -139,7 +139,7 @@ var DatePickerIOS = React.createClass({
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
rkDatePickerIOS: {
|
||||
datePickerIOS: {
|
||||
height: RCTDatePickerIOSConsts.ComponentHeight,
|
||||
width: RCTDatePickerIOSConsts.ComponentWidth,
|
||||
},
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ProgressViewIOS
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var React = require('React');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var Text = require('Text');
|
||||
var View = require('View');
|
||||
|
||||
var DummyProgressViewIOS = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<View style={[styles.dummy, this.props.style]}>
|
||||
<Text style={styles.text}>
|
||||
ProgressViewIOS is not supported on this platform!
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
dummy: {
|
||||
width: 120,
|
||||
height: 20,
|
||||
backgroundColor: '#ffbcbc',
|
||||
borderWidth: 1,
|
||||
borderColor: 'red',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
text: {
|
||||
color: '#333333',
|
||||
margin: 5,
|
||||
fontSize: 10,
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = DummyProgressViewIOS;
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ProgressViewIOS
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var Image = require('Image');
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var NativeModules = require('NativeModules');
|
||||
var PropTypes = require('ReactPropTypes');
|
||||
var React = require('React');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
|
||||
var requireNativeComponent = require('requireNativeComponent');
|
||||
var verifyPropTypes = require('verifyPropTypes');
|
||||
|
||||
/**
|
||||
* Use `ProgressViewIOS` to render a UIProgressView on iOS.
|
||||
*/
|
||||
var ProgressViewIOS = React.createClass({
|
||||
mixins: [NativeMethodsMixin],
|
||||
|
||||
propTypes: {
|
||||
/**
|
||||
* The progress bar style.
|
||||
*/
|
||||
progressViewStyle: PropTypes.oneOf(['default', 'bar']),
|
||||
|
||||
/**
|
||||
* The progress value (between 0 and 1).
|
||||
*/
|
||||
progress: PropTypes.number,
|
||||
|
||||
/**
|
||||
* The tint color of the progress bar itself.
|
||||
*/
|
||||
progressTintColor: PropTypes.string,
|
||||
|
||||
/**
|
||||
* The tint color of the progress bar track.
|
||||
*/
|
||||
trackTintColor: PropTypes.string,
|
||||
|
||||
/**
|
||||
* A stretchable image to display as the progress bar.
|
||||
*/
|
||||
progressImage: Image.propTypes.source,
|
||||
|
||||
/**
|
||||
* A stretchable image to display behind the progress bar.
|
||||
*/
|
||||
trackImage: Image.propTypes.source,
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<RCTProgressView
|
||||
{...this.props}
|
||||
style={[styles.progressView, this.props.style]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
progressView: {
|
||||
height: NativeModules.ProgressViewManager.ComponentHeight
|
||||
},
|
||||
});
|
||||
|
||||
var RCTProgressView = requireNativeComponent(
|
||||
'RCTProgressView',
|
||||
ProgressViewIOS
|
||||
);
|
||||
|
||||
module.exports = ProgressViewIOS;
|
||||
@@ -183,7 +183,7 @@ var ScrollResponderMixin = {
|
||||
var currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
|
||||
if (!this.props.keyboardShouldPersistTaps &&
|
||||
currentlyFocusedTextInput != null &&
|
||||
e.target != currentlyFocusedTextInput) {
|
||||
e.target !== currentlyFocusedTextInput) {
|
||||
return true;
|
||||
}
|
||||
return this.scrollResponderIsAnimating();
|
||||
@@ -244,7 +244,7 @@ var ScrollResponderMixin = {
|
||||
var currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
|
||||
if (!this.props.keyboardShouldPersistTaps &&
|
||||
currentlyFocusedTextInput != null &&
|
||||
e.target != currentlyFocusedTextInput &&
|
||||
e.target !== currentlyFocusedTextInput &&
|
||||
!this.state.observedScrollSinceBecomingResponder &&
|
||||
!this.state.becameResponderWhileAnimating) {
|
||||
this.props.onScrollResponderKeyboardDismissed &&
|
||||
|
||||
@@ -38,12 +38,6 @@ var PropTypes = React.PropTypes;
|
||||
var SCROLLVIEW = 'ScrollView';
|
||||
var INNERVIEW = 'InnerScrollView';
|
||||
|
||||
var keyboardDismissModeConstants = {
|
||||
'none': RCTScrollViewConsts.KeyboardDismissMode.None, // default
|
||||
'interactive': RCTScrollViewConsts.KeyboardDismissMode.Interactive,
|
||||
'onDrag': RCTScrollViewConsts.KeyboardDismissMode.OnDrag,
|
||||
};
|
||||
|
||||
/**
|
||||
* Component that wraps platform ScrollView while providing
|
||||
* integration with touch locking "responder" system.
|
||||
@@ -147,7 +141,7 @@ var ScrollView = React.createClass({
|
||||
keyboardDismissMode: PropTypes.oneOf([
|
||||
'none', // default
|
||||
'interactive',
|
||||
'onDrag',
|
||||
'on-drag',
|
||||
]),
|
||||
/**
|
||||
* When false, tapping outside of the focused text input when the keyboard
|
||||
@@ -287,9 +281,6 @@ var ScrollView = React.createClass({
|
||||
...this.props,
|
||||
alwaysBounceHorizontal,
|
||||
alwaysBounceVertical,
|
||||
keyboardDismissMode: this.props.keyboardDismissMode ?
|
||||
keyboardDismissModeConstants[this.props.keyboardDismissMode] :
|
||||
undefined,
|
||||
style: ([styles.base, this.props.style]: ?Array<any>),
|
||||
onTouchStart: this.scrollResponderHandleTouchStart,
|
||||
onTouchMove: this.scrollResponderHandleTouchMove,
|
||||
@@ -308,7 +299,7 @@ var ScrollView = React.createClass({
|
||||
onResponderRelease: this.scrollResponderHandleResponderRelease,
|
||||
onResponderReject: this.scrollResponderHandleResponderReject,
|
||||
};
|
||||
|
||||
|
||||
var ScrollViewClass;
|
||||
if (Platform.OS === 'ios') {
|
||||
ScrollViewClass = RCTScrollView;
|
||||
@@ -318,6 +309,13 @@ var ScrollView = React.createClass({
|
||||
} else {
|
||||
ScrollViewClass = AndroidScrollView;
|
||||
}
|
||||
var keyboardDismissModeConstants = {
|
||||
'none': RCTScrollViewConsts.KeyboardDismissMode.None, // default
|
||||
'interactive': RCTScrollViewConsts.KeyboardDismissMode.Interactive,
|
||||
'on-drag': RCTScrollViewConsts.KeyboardDismissMode.OnDrag,
|
||||
};
|
||||
props.keyboardDismissMode = props.keyboardDismissMode ?
|
||||
keyboardDismissModeConstants[props.keyboardDismissMode] : undefined;
|
||||
}
|
||||
invariant(
|
||||
ScrollViewClass !== undefined,
|
||||
|
||||
@@ -17,7 +17,7 @@ var StyleSheet = require('StyleSheet');
|
||||
var Text = require('Text');
|
||||
var View = require('View');
|
||||
|
||||
var Dummy = React.createClass({
|
||||
var DummySegmentedControlIOS = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<View style={[styles.dummy, this.props.style]}>
|
||||
@@ -46,4 +46,4 @@ var styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Dummy;
|
||||
module.exports = DummySegmentedControlIOS;
|
||||
|
||||
@@ -108,13 +108,7 @@ var styles = StyleSheet.create({
|
||||
|
||||
var RCTSegmentedControl = requireNativeComponent(
|
||||
'RCTSegmentedControl',
|
||||
null
|
||||
SegmentedControlIOS
|
||||
);
|
||||
if (__DEV__) {
|
||||
verifyPropTypes(
|
||||
RCTSegmentedControl,
|
||||
RCTSegmentedControl.viewConfig
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = SegmentedControlIOS;
|
||||
|
||||
@@ -13,26 +13,26 @@
|
||||
|
||||
var RCTStatusBarManager = require('NativeModules').StatusBarManager;
|
||||
|
||||
type StatusBarStyle = $Enum<{
|
||||
'default': string,
|
||||
'light-content': string,
|
||||
}>;
|
||||
|
||||
type StatusBarAnimation = $Enum<{
|
||||
'none': string,
|
||||
'fade': string,
|
||||
'slide': string,
|
||||
}>;
|
||||
|
||||
var StatusBarIOS = {
|
||||
|
||||
Style: {
|
||||
default: RCTStatusBarManager.Style.default,
|
||||
lightContent: RCTStatusBarManager.Style.lightContent
|
||||
},
|
||||
|
||||
Animation: {
|
||||
none: RCTStatusBarManager.Animation.none,
|
||||
fade: RCTStatusBarManager.Animation.fade,
|
||||
slide: RCTStatusBarManager.Animation.slide,
|
||||
},
|
||||
|
||||
setStyle(style: number, animated?: boolean) {
|
||||
setStyle(style: StatusBarStyle, animated?: boolean) {
|
||||
animated = animated || false;
|
||||
RCTStatusBarManager.setStyle(style, animated);
|
||||
},
|
||||
|
||||
setHidden(hidden: boolean, animation: number) {
|
||||
animation = animation || StatusBarIOS.Animation.none;
|
||||
setHidden(hidden: boolean, animation?: StatusBarAnimation) {
|
||||
animation = animation || 'none';
|
||||
RCTStatusBarManager.setHidden(hidden, animation);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('EventEmitter');
|
||||
import type EventEmitter from 'EventEmitter';
|
||||
|
||||
/**
|
||||
* Subscribable provides a mixin for safely subscribing a component to an
|
||||
|
||||
@@ -25,11 +25,22 @@ var TabBarIOS = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
style: View.propTypes.style,
|
||||
/**
|
||||
* Color of the currently selected tab icon
|
||||
*/
|
||||
tintColor: React.PropTypes.string,
|
||||
/**
|
||||
* Background color of the tab bar
|
||||
*/
|
||||
barTintColor: React.PropTypes.string
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<RCTTabBar style={[styles.tabGroup, this.props.style]}>
|
||||
<RCTTabBar
|
||||
style={[styles.tabGroup, this.props.style]}
|
||||
tintColor={this.props.tintColor}
|
||||
barTintColor={this.props.barTintColor}>
|
||||
{this.props.children}
|
||||
</RCTTabBar>
|
||||
);
|
||||
|
||||
@@ -31,10 +31,6 @@ var emptyFunction = require('emptyFunction');
|
||||
var invariant = require('invariant');
|
||||
var merge = require('merge');
|
||||
|
||||
var autoCapitalizeConsts = RCTUIManager.UIText.AutocapitalizationType;
|
||||
var keyboardTypeConsts = RCTUIManager.UIKeyboardType;
|
||||
var returnKeyTypeConsts = RCTUIManager.UIReturnKeyType;
|
||||
|
||||
var RCTTextViewAttributes = merge(ReactNativeViewAttributes.UIView, {
|
||||
autoCorrect: true,
|
||||
autoCapitalize: true,
|
||||
@@ -96,10 +92,6 @@ var viewConfigAndroid = {
|
||||
validAttributes: AndroidTextInputAttributes,
|
||||
};
|
||||
|
||||
var crossPlatformKeyboardTypeMap = {
|
||||
'numeric': 'decimal-pad',
|
||||
};
|
||||
|
||||
type DefaultProps = {
|
||||
bufferDelay: number;
|
||||
};
|
||||
@@ -171,20 +163,20 @@ var TextInput = React.createClass({
|
||||
* Determines which keyboard to open, e.g.`numeric`.
|
||||
*/
|
||||
keyboardType: PropTypes.oneOf([
|
||||
'default',
|
||||
// iOS
|
||||
// Cross-platform
|
||||
'default',
|
||||
'numeric',
|
||||
'email-address',
|
||||
// iOS-only
|
||||
'ascii-capable',
|
||||
'numbers-and-punctuation',
|
||||
'url',
|
||||
'number-pad',
|
||||
'phone-pad',
|
||||
'name-phone-pad',
|
||||
'email-address',
|
||||
'decimal-pad',
|
||||
'twitter',
|
||||
'web-search',
|
||||
// Cross-platform
|
||||
'numeric',
|
||||
]),
|
||||
/**
|
||||
* Determines how the return key should look.
|
||||
@@ -407,29 +399,31 @@ var TextInput = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
getChildContext: function(): Object {
|
||||
return {isInAParentText: true};
|
||||
},
|
||||
|
||||
childContextTypes: {
|
||||
isInAParentText: React.PropTypes.bool
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (Platform.OS === 'ios') {
|
||||
return this._renderIOs();
|
||||
return this._renderIOS();
|
||||
} else if (Platform.OS === 'android') {
|
||||
return this._renderAndroid();
|
||||
}
|
||||
},
|
||||
|
||||
_renderIOs: function() {
|
||||
_renderIOS: function() {
|
||||
var textContainer;
|
||||
|
||||
var autoCapitalize = autoCapitalizeConsts[this.props.autoCapitalize];
|
||||
var clearButtonMode = RCTUIManager.UITextField.clearButtonMode[this.props.clearButtonMode];
|
||||
var props = this.props;
|
||||
props.style = [styles.input, this.props.style];
|
||||
|
||||
var keyboardType = keyboardTypeConsts[
|
||||
crossPlatformKeyboardTypeMap[this.props.keyboardType] ||
|
||||
this.props.keyboardType
|
||||
];
|
||||
var returnKeyType = returnKeyTypeConsts[this.props.returnKeyType];
|
||||
|
||||
if (!this.props.multiline) {
|
||||
if (!props.multiline) {
|
||||
for (var propKey in onlyMultiline) {
|
||||
if (this.props[propKey]) {
|
||||
if (props[propKey]) {
|
||||
throw new Error(
|
||||
'TextInput prop `' + propKey + '` is only supported with multiline.'
|
||||
);
|
||||
@@ -438,91 +432,73 @@ var TextInput = React.createClass({
|
||||
textContainer =
|
||||
<RCTTextField
|
||||
ref="input"
|
||||
style={[styles.input, this.props.style]}
|
||||
enabled={this.props.editable}
|
||||
keyboardType={keyboardType}
|
||||
returnKeyType={returnKeyType}
|
||||
enablesReturnKeyAutomatically={this.props.enablesReturnKeyAutomatically}
|
||||
secureTextEntry={this.props.password || this.props.secureTextEntry}
|
||||
{...props}
|
||||
onFocus={this._onFocus}
|
||||
onBlur={this._onBlur}
|
||||
onChange={this._onChange}
|
||||
onEndEditing={this.props.onEndEditing}
|
||||
onSubmitEditing={this.props.onSubmitEditing}
|
||||
onSelectionChangeShouldSetResponder={() => true}
|
||||
onLayout={this.props.onLayout}
|
||||
placeholder={this.props.placeholder}
|
||||
placeholderTextColor={this.props.placeholderTextColor}
|
||||
text={this.state.bufferedValue}
|
||||
autoCapitalize={autoCapitalize}
|
||||
autoCorrect={this.props.autoCorrect}
|
||||
clearButtonMode={clearButtonMode}
|
||||
clearTextOnFocus={this.props.clearTextOnFocus}
|
||||
selectTextOnFocus={this.props.selectTextOnFocus}
|
||||
/>;
|
||||
} else {
|
||||
for (var propKey in notMultiline) {
|
||||
if (this.props[propKey]) {
|
||||
if (props[propKey]) {
|
||||
throw new Error(
|
||||
'TextInput prop `' + propKey + '` cannot be used with multiline.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var children = this.props.children;
|
||||
var children = props.children;
|
||||
var childCount = 0;
|
||||
ReactChildren.forEach(children, () => ++childCount);
|
||||
invariant(
|
||||
!(this.props.value && childCount),
|
||||
!(props.value && childCount),
|
||||
'Cannot specify both value and children.'
|
||||
);
|
||||
if (childCount > 1) {
|
||||
children = <Text>{children}</Text>;
|
||||
}
|
||||
if (this.props.inputView) {
|
||||
children = [children, this.props.inputView];
|
||||
if (props.inputView) {
|
||||
children = [children, props.inputView];
|
||||
}
|
||||
textContainer =
|
||||
<RCTTextView
|
||||
ref="input"
|
||||
style={[styles.input, this.props.style]}
|
||||
{...props}
|
||||
children={children}
|
||||
mostRecentEventCounter={this.state.mostRecentEventCounter}
|
||||
editable={this.props.editable}
|
||||
keyboardType={keyboardType}
|
||||
returnKeyType={returnKeyType}
|
||||
enablesReturnKeyAutomatically={this.props.enablesReturnKeyAutomatically}
|
||||
secureTextEntry={this.props.password || this.props.secureTextEntry}
|
||||
onFocus={this._onFocus}
|
||||
onBlur={this._onBlur}
|
||||
onChange={this._onChange}
|
||||
onEndEditing={this.props.onEndEditing}
|
||||
onSelectionChange={this._onSelectionChange}
|
||||
onTextInput={this._onTextInput}
|
||||
onSelectionChangeShouldSetResponder={emptyFunction.thatReturnsTrue}
|
||||
onLayout={this.props.onLayout}
|
||||
placeholder={this.props.placeholder}
|
||||
placeholderTextColor={this.props.placeholderTextColor}
|
||||
text={this.state.bufferedValue}
|
||||
autoCapitalize={autoCapitalize}
|
||||
autoCorrect={this.props.autoCorrect}
|
||||
clearButtonMode={clearButtonMode}
|
||||
selectTextOnFocus={this.props.selectTextOnFocus}
|
||||
clearTextOnFocus={this.props.clearTextOnFocus}
|
||||
/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableWithoutFeedback
|
||||
onPress={this._onPress}
|
||||
rejectResponderTermination={true}>
|
||||
rejectResponderTermination={true}
|
||||
testID={props.testID}>
|
||||
{textContainer}
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
},
|
||||
|
||||
_renderAndroid: function() {
|
||||
var autoCapitalize = autoCapitalizeConsts[this.props.autoCapitalize];
|
||||
var autoCapitalize = RCTUIManager.UIText.AutocapitalizationType[this.props.autoCapitalize];
|
||||
var children = this.props.children;
|
||||
var childCount = 0;
|
||||
ReactChildren.forEach(children, () => ++childCount);
|
||||
invariant(
|
||||
!(this.props.value && childCount),
|
||||
'Cannot specify both value and children.'
|
||||
);
|
||||
if (childCount > 1) {
|
||||
children = <Text>{children}</Text>;
|
||||
}
|
||||
var textContainer =
|
||||
<AndroidTextInput
|
||||
ref="input"
|
||||
@@ -540,6 +516,7 @@ var TextInput = React.createClass({
|
||||
password={this.props.password || this.props.secureTextEntry}
|
||||
placeholder={this.props.placeholder}
|
||||
text={this.state.bufferedValue}
|
||||
children={children}
|
||||
/>;
|
||||
|
||||
return (
|
||||
|
||||
@@ -23,6 +23,7 @@ var View = require('View');
|
||||
|
||||
var cloneWithProps = require('cloneWithProps');
|
||||
var ensureComponentIsNative = require('ensureComponentIsNative');
|
||||
var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
|
||||
var keyOf = require('keyOf');
|
||||
var merge = require('merge');
|
||||
var onlyChild = require('onlyChild');
|
||||
@@ -70,6 +71,14 @@ var TouchableHighlight = React.createClass({
|
||||
*/
|
||||
underlayColor: React.PropTypes.string,
|
||||
style: View.propTypes.style,
|
||||
/**
|
||||
* Called immediately after the underlay is shown
|
||||
*/
|
||||
onShowUnderlay: React.PropTypes.func,
|
||||
/**
|
||||
* Called immediately after the underlay is hidden
|
||||
*/
|
||||
onHideUnderlay: React.PropTypes.func,
|
||||
},
|
||||
|
||||
mixins: [NativeMethodsMixin, TimerMixin, Touchable.Mixin],
|
||||
@@ -103,6 +112,7 @@ var TouchableHighlight = React.createClass({
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
ensurePositiveDelayProps(this.props);
|
||||
ensureComponentIsNative(this.refs[CHILD_REF]);
|
||||
},
|
||||
|
||||
@@ -111,6 +121,7 @@ var TouchableHighlight = React.createClass({
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
ensurePositiveDelayProps(nextProps);
|
||||
if (nextProps.activeOpacity !== this.props.activeOpacity ||
|
||||
nextProps.underlayColor !== this.props.underlayColor ||
|
||||
nextProps.style !== this.props.style) {
|
||||
@@ -144,7 +155,8 @@ var TouchableHighlight = React.createClass({
|
||||
touchableHandlePress: function() {
|
||||
this.clearTimeout(this._hideTimeout);
|
||||
this._showUnderlay();
|
||||
this._hideTimeout = this.setTimeout(this._hideUnderlay, 100);
|
||||
this._hideTimeout = this.setTimeout(this._hideUnderlay,
|
||||
this.props.delayPressOut || 100);
|
||||
this.props.onPress && this.props.onPress();
|
||||
},
|
||||
|
||||
@@ -156,9 +168,22 @@ var TouchableHighlight = React.createClass({
|
||||
return PRESS_RECT_OFFSET; // Always make sure to predeclare a constant!
|
||||
},
|
||||
|
||||
touchableGetHighlightDelayMS: function() {
|
||||
return this.props.delayPressIn;
|
||||
},
|
||||
|
||||
touchableGetLongPressDelayMS: function() {
|
||||
return this.props.delayLongPress;
|
||||
},
|
||||
|
||||
touchableGetPressOutDelayMS: function() {
|
||||
return this.props.delayPressOut;
|
||||
},
|
||||
|
||||
_showUnderlay: function() {
|
||||
this.refs[UNDERLAY_REF].setNativeProps(this.state.activeUnderlayProps);
|
||||
this.refs[CHILD_REF].setNativeProps(this.state.activeProps);
|
||||
this.props.onShowUnderlay && this.props.onShowUnderlay();
|
||||
},
|
||||
|
||||
_hideUnderlay: function() {
|
||||
@@ -170,6 +195,7 @@ var TouchableHighlight = React.createClass({
|
||||
...INACTIVE_UNDERLAY_PROPS,
|
||||
style: this.state.underlayStyle,
|
||||
});
|
||||
this.props.onHideUnderlay && this.props.onHideUnderlay();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var POPAnimationMixin = require('POPAnimationMixin');
|
||||
var React = require('React');
|
||||
var TimerMixin = require('react-timer-mixin');
|
||||
var Touchable = require('Touchable');
|
||||
var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
|
||||
|
||||
var cloneWithProps = require('cloneWithProps');
|
||||
var ensureComponentIsNative = require('ensureComponentIsNative');
|
||||
var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
|
||||
var flattenStyle = require('flattenStyle');
|
||||
var keyOf = require('keyOf');
|
||||
var onlyChild = require('onlyChild');
|
||||
@@ -44,10 +46,13 @@ var onlyChild = require('onlyChild');
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
* > **NOTE**: TouchableOpacity supports only one child
|
||||
* >
|
||||
* > If you wish to have to have several child components, wrap them in a View.
|
||||
*/
|
||||
|
||||
var TouchableOpacity = React.createClass({
|
||||
mixins: [Touchable.Mixin, NativeMethodsMixin, POPAnimationMixin],
|
||||
mixins: [TimerMixin, Touchable.Mixin, NativeMethodsMixin, POPAnimationMixin],
|
||||
|
||||
propTypes: {
|
||||
...TouchableWithoutFeedback.propTypes,
|
||||
@@ -69,6 +74,7 @@ var TouchableOpacity = React.createClass({
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
ensurePositiveDelayProps(this.props);
|
||||
ensureComponentIsNative(this.refs[CHILD_REF]);
|
||||
},
|
||||
|
||||
@@ -76,6 +82,10 @@ var TouchableOpacity = React.createClass({
|
||||
ensureComponentIsNative(this.refs[CHILD_REF]);
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
ensurePositiveDelayProps(nextProps);
|
||||
},
|
||||
|
||||
setOpacityTo: function(value) {
|
||||
if (POPAnimationMixin) {
|
||||
// Reset with animation if POP is available
|
||||
@@ -83,6 +93,7 @@ var TouchableOpacity = React.createClass({
|
||||
var anim = {
|
||||
type: this.AnimationTypes.linear,
|
||||
property: this.AnimationProperties.opacity,
|
||||
duration: 0.15,
|
||||
toValue: value,
|
||||
};
|
||||
this.startAnimation(CHILD_REF, anim);
|
||||
@@ -99,20 +110,26 @@ var TouchableOpacity = React.createClass({
|
||||
* defined on your component.
|
||||
*/
|
||||
touchableHandleActivePressIn: function() {
|
||||
this.refs[CHILD_REF].setNativeProps({
|
||||
opacity: this.props.activeOpacity
|
||||
});
|
||||
this.clearTimeout(this._hideTimeout);
|
||||
this._hideTimeout = null;
|
||||
this._opacityActive();
|
||||
this.props.onPressIn && this.props.onPressIn();
|
||||
},
|
||||
|
||||
touchableHandleActivePressOut: function() {
|
||||
var child = onlyChild(this.props.children);
|
||||
var childStyle = flattenStyle(child.props.style) || {};
|
||||
this.setOpacityTo(childStyle.opacity === undefined ? 1 : childStyle.opacity);
|
||||
if (!this._hideTimeout) {
|
||||
this._opacityInactive();
|
||||
}
|
||||
this.props.onPressOut && this.props.onPressOut();
|
||||
},
|
||||
|
||||
touchableHandlePress: function() {
|
||||
this.clearTimeout(this._hideTimeout);
|
||||
this._opacityActive();
|
||||
this._hideTimeout = this.setTimeout(
|
||||
this._opacityInactive,
|
||||
this.props.delayPressOut || 100
|
||||
);
|
||||
this.props.onPress && this.props.onPress();
|
||||
},
|
||||
|
||||
@@ -125,7 +142,30 @@ var TouchableOpacity = React.createClass({
|
||||
},
|
||||
|
||||
touchableGetHighlightDelayMS: function() {
|
||||
return 0;
|
||||
return this.props.delayPressIn || 0;
|
||||
},
|
||||
|
||||
touchableGetLongPressDelayMS: function() {
|
||||
return this.props.delayLongPress === 0 ? 0 :
|
||||
this.props.delayLongPress || 500;
|
||||
},
|
||||
|
||||
touchableGetPressOutDelayMS: function() {
|
||||
return this.props.delayPressOut;
|
||||
},
|
||||
|
||||
_opacityActive: function() {
|
||||
this.setOpacityTo(this.props.activeOpacity);
|
||||
},
|
||||
|
||||
_opacityInactive: function() {
|
||||
this.clearTimeout(this._hideTimeout);
|
||||
this._hideTimeout = null;
|
||||
var child = onlyChild(this.props.children);
|
||||
var childStyle = flattenStyle(child.props.style) || {};
|
||||
this.setOpacityTo(
|
||||
childStyle.opacity === undefined ? 1 : childStyle.opacity
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('React');
|
||||
var TimerMixin = require('react-timer-mixin');
|
||||
var Touchable = require('Touchable');
|
||||
var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
|
||||
var onlyChild = require('onlyChild');
|
||||
|
||||
/**
|
||||
@@ -31,23 +33,44 @@ type Event = Object;
|
||||
* one of the primary reason a "web" app doesn't feel "native".
|
||||
*/
|
||||
var TouchableWithoutFeedback = React.createClass({
|
||||
mixins: [Touchable.Mixin],
|
||||
mixins: [TimerMixin, Touchable.Mixin],
|
||||
|
||||
propTypes: {
|
||||
/**
|
||||
* Called when the touch is released, but not if cancelled (e.g. by a scroll
|
||||
* that steals the responder lock).
|
||||
*/
|
||||
accessible: React.PropTypes.bool,
|
||||
onPress: React.PropTypes.func,
|
||||
onPressIn: React.PropTypes.func,
|
||||
onPressOut: React.PropTypes.func,
|
||||
onLongPress: React.PropTypes.func,
|
||||
/**
|
||||
* Delay in ms, from the start of the touch, before onPressIn is called.
|
||||
*/
|
||||
delayPressIn: React.PropTypes.number,
|
||||
/**
|
||||
* Delay in ms, from the release of the touch, before onPressOut is called.
|
||||
*/
|
||||
delayPressOut: React.PropTypes.number,
|
||||
/**
|
||||
* Delay in ms, from onPressIn, before onLongPress is called.
|
||||
*/
|
||||
delayLongPress: React.PropTypes.number,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.touchableGetInitialState();
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
ensurePositiveDelayProps(this.props);
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps: Object) {
|
||||
ensurePositiveDelayProps(nextProps);
|
||||
},
|
||||
|
||||
/**
|
||||
* `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
|
||||
* defined on your component.
|
||||
@@ -73,13 +96,22 @@ var TouchableWithoutFeedback = React.createClass({
|
||||
},
|
||||
|
||||
touchableGetHighlightDelayMS: function(): number {
|
||||
return 0;
|
||||
return this.props.delayPressIn || 0;
|
||||
},
|
||||
|
||||
touchableGetLongPressDelayMS: function(): number {
|
||||
return this.props.delayLongPress === 0 ? 0 :
|
||||
this.props.delayLongPress || 500;
|
||||
},
|
||||
|
||||
touchableGetPressOutDelayMS: function(): number {
|
||||
return this.props.delayPressOut || 0;
|
||||
},
|
||||
|
||||
render: function(): ReactElement {
|
||||
// Note(avik): remove dynamic typecast once Flow has been upgraded
|
||||
return (React: any).cloneElement(onlyChild(this.props.children), {
|
||||
accessible: true,
|
||||
accessible: this.props.accessible !== false,
|
||||
testID: this.props.testID,
|
||||
onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
|
||||
onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest,
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ensurePositiveDelayProps
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var invariant = require('invariant');
|
||||
|
||||
var ensurePositiveDelayProps = function(props: any) {
|
||||
invariant(
|
||||
!(props.delayPressIn < 0 || props.delayPressOut < 0 ||
|
||||
props.delayLongPress < 0),
|
||||
'Touchable components cannot have negative delay properties'
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = ensurePositiveDelayProps;
|
||||
@@ -24,6 +24,26 @@ var createReactNativeComponentClass = require('createReactNativeComponentClass')
|
||||
|
||||
var stylePropType = StyleSheetPropType(ViewStylePropTypes);
|
||||
|
||||
var AccessibilityTraits = [
|
||||
'none',
|
||||
'button',
|
||||
'link',
|
||||
'header',
|
||||
'search',
|
||||
'image',
|
||||
'selected',
|
||||
'plays',
|
||||
'key',
|
||||
'text',
|
||||
'summary',
|
||||
'disabled',
|
||||
'frequentUpdates',
|
||||
'startsMedia',
|
||||
'adjustable',
|
||||
'allowsDirectInteraction',
|
||||
'pageTurn',
|
||||
];
|
||||
|
||||
/**
|
||||
* The most fundamental component for building UI, `View` is a
|
||||
* container that supports layout with flexbox, style, some touch handling, and
|
||||
@@ -70,6 +90,27 @@ var View = React.createClass({
|
||||
*/
|
||||
accessibilityLabel: PropTypes.string,
|
||||
|
||||
/**
|
||||
* Provides additional traits to screen reader. By default no traits are
|
||||
* provided unless specified otherwise in element
|
||||
*/
|
||||
accessibilityTraits: PropTypes.oneOfType([
|
||||
PropTypes.oneOf(AccessibilityTraits),
|
||||
PropTypes.arrayOf(PropTypes.oneOf(AccessibilityTraits)),
|
||||
]),
|
||||
|
||||
/**
|
||||
* When `accessible` is true, the system will try to invoke this function
|
||||
* when the user performs accessibility tap gesture.
|
||||
*/
|
||||
onAcccessibilityTap: PropTypes.func,
|
||||
|
||||
/**
|
||||
* When `accessible` is true, the system will invoke this function when the
|
||||
* user performs the magic tap gesture.
|
||||
*/
|
||||
onMagicTap: PropTypes.func,
|
||||
|
||||
/**
|
||||
* Used to locate this view in end-to-end tests.
|
||||
*/
|
||||
@@ -91,7 +132,9 @@ var View = React.createClass({
|
||||
onStartShouldSetResponderCapture: PropTypes.func,
|
||||
|
||||
/**
|
||||
* Invoked on mount and layout changes with {x, y, width, height}.
|
||||
* Invoked on mount and layout changes with
|
||||
*
|
||||
* {nativeEvent: { layout: {x, y, width, height}}}.
|
||||
*/
|
||||
onLayout: PropTypes.func,
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ var WebView = React.createClass({
|
||||
errorEvent.code,
|
||||
errorEvent.description);
|
||||
} else if (this.state.viewState !== WebViewState.IDLE) {
|
||||
console.error("RCTWebView invalid state encountered: " + this.state.loading);
|
||||
console.error('RCTWebView invalid state encountered: ' + this.state.loading);
|
||||
}
|
||||
|
||||
var webViewStyles = [styles.container, this.props.style];
|
||||
@@ -152,7 +152,7 @@ var WebView = React.createClass({
|
||||
|
||||
onLoadingError: function(event) {
|
||||
event.persist(); // persist this event because we need to store it
|
||||
console.error("encountered an error loading page", event.nativeEvent);
|
||||
console.error('Encountered an error loading page', event.nativeEvent);
|
||||
|
||||
this.setState({
|
||||
lastErrorEvent: event.nativeEvent,
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
var ActivityIndicatorIOS = require('ActivityIndicatorIOS');
|
||||
var EdgeInsetsPropType = require('EdgeInsetsPropType');
|
||||
var React = require('React');
|
||||
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var Text = require('Text');
|
||||
var View = require('View');
|
||||
@@ -198,7 +197,7 @@ var WebView = React.createClass({
|
||||
|
||||
onLoadingError: function(event: Event) {
|
||||
event.persist(); // persist this event because we need to store it
|
||||
console.error("encountered an error loading page", event.nativeEvent);
|
||||
console.error('Encountered an error loading page', event.nativeEvent);
|
||||
|
||||
this.setState({
|
||||
lastErrorEvent: event.nativeEvent,
|
||||
|
||||
@@ -45,7 +45,6 @@ var DEFAULT_INITIAL_ROWS = 10;
|
||||
var DEFAULT_SCROLL_RENDER_AHEAD = 1000;
|
||||
var DEFAULT_END_REACHED_THRESHOLD = 1000;
|
||||
var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
|
||||
var RENDER_INTERVAL = 20;
|
||||
var SCROLLVIEW_REF = 'listviewscroll';
|
||||
|
||||
|
||||
@@ -108,7 +107,7 @@ var ListView = React.createClass({
|
||||
* You must provide a renderRow function. If you omit any of the other render
|
||||
* functions, ListView will simply skip rendering them.
|
||||
*
|
||||
* - renderRow(rowData, sectionID, rowID);
|
||||
* - renderRow(rowData, sectionID, rowID, highlightRow);
|
||||
* - renderSectionHeader(sectionData, sectionID);
|
||||
*/
|
||||
propTypes: {
|
||||
@@ -116,11 +115,22 @@ var ListView = React.createClass({
|
||||
|
||||
dataSource: PropTypes.instanceOf(ListViewDataSource).isRequired,
|
||||
/**
|
||||
* (rowData, sectionID, rowID) => renderable
|
||||
* (sectionID, rowID, adjacentRowHighlighted) => renderable
|
||||
* If provided, a renderable component to be rendered as the separator
|
||||
* below each row but not the last row if there is a section header below.
|
||||
* Take a sectionID and rowID of the row above and whether its adjacent row
|
||||
* is highlighted.
|
||||
*/
|
||||
renderSeparator: PropTypes.func,
|
||||
/**
|
||||
* (rowData, sectionID, rowID, highlightRow) => renderable
|
||||
* Takes a data entry from the data source and its ids and should return
|
||||
* a renderable component to be rendered as the row. By default the data
|
||||
* is exactly what was put into the data source, but it's also possible to
|
||||
* provide custom extractors.
|
||||
* provide custom extractors. ListView can be notified when a row is
|
||||
* being highlighted by calling highlightRow function. The separators above and
|
||||
* below will be hidden when a row is highlighted. The highlighted state of
|
||||
* a row can be reset by calling highlightRow(null).
|
||||
*/
|
||||
renderRow: PropTypes.func.isRequired,
|
||||
/**
|
||||
@@ -227,6 +237,7 @@ var ListView = React.createClass({
|
||||
return {
|
||||
curRenderedRowsCount: this.props.initialListSize,
|
||||
prevRenderedRowsCount: 0,
|
||||
highlightedRow: {},
|
||||
};
|
||||
},
|
||||
|
||||
@@ -246,7 +257,6 @@ var ListView = React.createClass({
|
||||
// the component is laid out
|
||||
this.requestAnimationFrame(() => {
|
||||
this._measureAndUpdateScrollProps();
|
||||
this.setInterval(this._renderMoreRowsIfNeeded, RENDER_INTERVAL);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -256,6 +266,10 @@ var ListView = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
onRowHighlighted: function(sectionID, rowID) {
|
||||
this.setState({highlightedRow: {sectionID, rowID}});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var bodyComponents = [];
|
||||
|
||||
@@ -305,11 +319,28 @@ var ListView = React.createClass({
|
||||
null,
|
||||
dataSource.getRowData(sectionIdx, rowIdx),
|
||||
sectionID,
|
||||
rowID
|
||||
rowID,
|
||||
this.onRowHighlighted
|
||||
)}
|
||||
/>;
|
||||
bodyComponents.push(row);
|
||||
totalIndex++;
|
||||
|
||||
if (this.props.renderSeparator &&
|
||||
(rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length - 1)) {
|
||||
var adjacentRowHighlighted =
|
||||
this.state.highlightedRow.sectionID === sectionID && (
|
||||
this.state.highlightedRow.rowID === rowID ||
|
||||
this.state.highlightedRow.rowID === rowIDs[rowIdx + 1]
|
||||
);
|
||||
var separator = this.props.renderSeparator(
|
||||
sectionID,
|
||||
rowID,
|
||||
adjacentRowHighlighted
|
||||
);
|
||||
bodyComponents.push(separator);
|
||||
totalIndex++;
|
||||
}
|
||||
if (++rowCount === this.state.curRenderedRowsCount) {
|
||||
break;
|
||||
}
|
||||
@@ -364,6 +395,7 @@ var ListView = React.createClass({
|
||||
_setScrollVisibleHeight: function(left, top, width, height) {
|
||||
this.scrollProperties.visibleHeight = height;
|
||||
this._updateVisibleRows();
|
||||
this._renderMoreRowsIfNeeded();
|
||||
},
|
||||
|
||||
_renderMoreRowsIfNeeded: function() {
|
||||
@@ -410,8 +442,8 @@ var ListView = React.createClass({
|
||||
}
|
||||
var updatedFrames = e && e.nativeEvent.updatedChildFrames;
|
||||
if (updatedFrames) {
|
||||
updatedFrames.forEach((frame) => {
|
||||
this._childFrames[frame.index] = merge(frame);
|
||||
updatedFrames.forEach((newFrame) => {
|
||||
this._childFrames[newFrame.index] = merge(newFrame);
|
||||
});
|
||||
}
|
||||
var dataSource = this.props.dataSource;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*
|
||||
* @providesModule Navigator
|
||||
*/
|
||||
/* eslint-disable no-extra-boolean-cast*/
|
||||
'use strict';
|
||||
|
||||
var AnimationsDebugModule = require('NativeModules').AnimationsDebugModule;
|
||||
@@ -48,8 +49,6 @@ var clamp = require('clamp');
|
||||
var flattenStyle = require('flattenStyle');
|
||||
var getNavigatorContext = require('getNavigatorContext');
|
||||
var invariant = require('invariant');
|
||||
var keyMirror = require('keyMirror');
|
||||
var merge = require('merge');
|
||||
var rebound = require('rebound');
|
||||
|
||||
var PropTypes = React.PropTypes;
|
||||
@@ -333,7 +332,7 @@ var Navigator = React.createClass({
|
||||
this._subRouteFocus = [];
|
||||
this.navigatorContext = {
|
||||
// Actions for child navigators or interceptors:
|
||||
setHandlerForRoute: this.setHandlerForRoute,
|
||||
setHandlerForIndex: this.setHandlerForIndex,
|
||||
request: this.request,
|
||||
|
||||
// Contextual utilities
|
||||
@@ -341,14 +340,13 @@ var Navigator = React.createClass({
|
||||
getCurrentRoutes: this.getCurrentRoutes,
|
||||
// `route` is injected by NavigatorStaticContextContainer
|
||||
|
||||
// Contextual nav actions
|
||||
// Contextual nav action
|
||||
pop: this.requestPop,
|
||||
popToRoute: this.requestPopTo,
|
||||
|
||||
// Legacy, imperitive nav actions. Will transition these to contextual actions
|
||||
jumpBack: this.jumpBack,
|
||||
jumpForward: this.jumpForward,
|
||||
jumpTo: this.jumpTo,
|
||||
popToRoute: this.popToRoute,
|
||||
push: this.push,
|
||||
replace: this.replace,
|
||||
replaceAtIndex: this.replaceAtIndex,
|
||||
@@ -411,8 +409,6 @@ var Navigator = React.createClass({
|
||||
switch (action) {
|
||||
case 'pop':
|
||||
return this._handlePop(arg1);
|
||||
case 'popTo':
|
||||
return this._handlePopTo(arg1);
|
||||
case 'push':
|
||||
return this._handlePush(arg1);
|
||||
default:
|
||||
@@ -441,30 +437,13 @@ var Navigator = React.createClass({
|
||||
return true;
|
||||
},
|
||||
|
||||
_handlePopTo: function(destRoute) {
|
||||
if (destRoute) {
|
||||
var hasRoute = this.state.routeStack.indexOf(destRoute) !== -1;
|
||||
if (hasRoute) {
|
||||
this.popToRoute(destRoute);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this.state.presentedIndex === 0) {
|
||||
return false;
|
||||
}
|
||||
this.pop();
|
||||
return true;
|
||||
},
|
||||
|
||||
_handlePush: function(route) {
|
||||
this.push(route);
|
||||
return true;
|
||||
},
|
||||
|
||||
setHandlerForRoute: function(route, handler) {
|
||||
this._handlers[this.state.routeStack.indexOf(route)] = handler;
|
||||
setHandlerForIndex: function(index, handler) {
|
||||
this._handlers[index] = handler;
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
@@ -570,11 +549,14 @@ var Navigator = React.createClass({
|
||||
this.spring.getCurrentValue()
|
||||
);
|
||||
} else if (this.state.activeGesture != null) {
|
||||
this._transitionBetween(
|
||||
this.state.presentedIndex,
|
||||
this.state.presentedIndex + this._deltaForGestureAction(this.state.activeGesture),
|
||||
this.spring.getCurrentValue()
|
||||
);
|
||||
var presentedToIndex = this.state.presentedIndex + this._deltaForGestureAction(this.state.activeGesture);
|
||||
if (presentedToIndex > -1) {
|
||||
this._transitionBetween(
|
||||
this.state.presentedIndex,
|
||||
presentedToIndex,
|
||||
this.spring.getCurrentValue()
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -689,7 +671,7 @@ var Navigator = React.createClass({
|
||||
*/
|
||||
_enableScene: function(sceneIndex) {
|
||||
// First, determine what the defined styles are for scenes in this navigator
|
||||
var sceneStyle = flattenStyle(this.props.sceneStyle);
|
||||
var sceneStyle = flattenStyle([styles.baseScene, this.props.sceneStyle]);
|
||||
// Then restore the left value for this scene
|
||||
var enabledSceneNativeProps = {
|
||||
left: sceneStyle.left,
|
||||
@@ -745,7 +727,6 @@ var Navigator = React.createClass({
|
||||
},
|
||||
|
||||
_handleMoveShouldSetPanResponder: function(e, gestureState) {
|
||||
var currentRoute = this.state.routeStack[this.state.presentedIndex];
|
||||
var sceneConfig = this.state.sceneConfigStack[this.state.presentedIndex];
|
||||
this._expectingGestureGrant = this._matchGestureAction(this._eligibleGestures, sceneConfig.gestures, gestureState);
|
||||
return !! this._expectingGestureGrant;
|
||||
@@ -829,7 +810,16 @@ var Navigator = React.createClass({
|
||||
}
|
||||
} else {
|
||||
// The gesture has enough velocity to complete, so we transition to the gesture's destination
|
||||
this._transitionTo(destIndex, transitionVelocity);
|
||||
this._transitionTo(
|
||||
destIndex,
|
||||
transitionVelocity,
|
||||
null,
|
||||
() => {
|
||||
if (releaseGestureAction === 'pop') {
|
||||
this._cleanScenesPastIndex(destIndex);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
this._detachGesture();
|
||||
},
|
||||
@@ -1148,17 +1138,13 @@ var Navigator = React.createClass({
|
||||
this.popToRoute(this.state.routeStack[0]);
|
||||
},
|
||||
|
||||
_getNumToPopForRoute: function(route) {
|
||||
popToRoute: function(route) {
|
||||
var indexOfRoute = this.state.routeStack.indexOf(route);
|
||||
invariant(
|
||||
indexOfRoute !== -1,
|
||||
'Calling pop to route for a route that doesn\'t exist!'
|
||||
'Calling popToRoute for a route that doesn\'t exist!'
|
||||
);
|
||||
return this.state.presentedIndex - indexOfRoute;
|
||||
},
|
||||
|
||||
popToRoute: function(route) {
|
||||
var numToPop = this._getNumToPopForRoute(route);
|
||||
var numToPop = this.state.presentedIndex - indexOfRoute;
|
||||
this._popN(numToPop);
|
||||
},
|
||||
|
||||
@@ -1255,7 +1241,7 @@ var Navigator = React.createClass({
|
||||
...this.navigatorContext,
|
||||
route,
|
||||
setHandler: (handler) => {
|
||||
this.navigatorContext.setHandlerForRoute(route, handler);
|
||||
this.navigatorContext.setHandlerForIndex(i, handler);
|
||||
},
|
||||
onWillFocus: (childRoute) => {
|
||||
this._subRouteFocus[i] = childRoute;
|
||||
@@ -1291,16 +1277,29 @@ var Navigator = React.createClass({
|
||||
if (i !== this.state.presentedIndex) {
|
||||
disabledSceneStyle = styles.disabledScene;
|
||||
}
|
||||
var originalRef = child.ref;
|
||||
if (originalRef != null && typeof originalRef !== 'function') {
|
||||
console.warn(
|
||||
'String refs are not supported for navigator scenes. Use a callback ' +
|
||||
'ref instead. Ignoring ref: ' + originalRef
|
||||
);
|
||||
originalRef = null;
|
||||
}
|
||||
return (
|
||||
<View
|
||||
key={this.state.idStack[i]}
|
||||
ref={'scene_' + i}
|
||||
onStartShouldSetResponderCapture={() => {
|
||||
return i !== this.state.presentedIndex;
|
||||
return !!this.state.transitionFromIndex || !!this.state.activeGesture;
|
||||
}}
|
||||
style={[styles.baseScene, this.props.sceneStyle, disabledSceneStyle]}>
|
||||
{React.cloneElement(child, {
|
||||
ref: this._handleItemRef.bind(null, this.state.idStack[i], route),
|
||||
ref: component => {
|
||||
this._handleItemRef(this.state.idStack[i], route, component);
|
||||
if (originalRef) {
|
||||
originalRef(component);
|
||||
}
|
||||
}
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -213,7 +213,7 @@ var FromTheLeft = {
|
||||
translateX: {
|
||||
from: -SCREEN_WIDTH,
|
||||
to: 0,
|
||||
min: 0,
|
||||
min: 0,
|
||||
max: 1,
|
||||
type: 'linear',
|
||||
extrapolate: true,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
* @providesModule fetch
|
||||
* @nolint
|
||||
*/
|
||||
/* eslint-disable */
|
||||
'use strict';
|
||||
|
||||
var self = {};
|
||||
|
||||
@@ -120,6 +120,6 @@ var Geolocation = {
|
||||
subscriptions = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Geolocation;
|
||||
|
||||
@@ -85,7 +85,9 @@ static NSDictionary *RCTPositionError(RCTPositionErrorCode code, NSString *msg /
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_timeoutTimer invalidate];
|
||||
if (_timeoutTimer.valid) {
|
||||
[_timeoutTimer invalidate];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -273,6 +275,7 @@ RCT_EXPORT_METHOD(getCurrentPosition:(RCTLocationOptions)options
|
||||
// Fire all queued callbacks
|
||||
for (RCTLocationRequest *request in _pendingRequests) {
|
||||
request.successBlock(@[_lastLocationEvent]);
|
||||
[request.timeoutTimer invalidate];
|
||||
}
|
||||
[_pendingRequests removeAllObjects];
|
||||
|
||||
@@ -311,6 +314,7 @@ RCT_EXPORT_METHOD(getCurrentPosition:(RCTLocationOptions)options
|
||||
// Fire all queued error callbacks
|
||||
for (RCTLocationRequest *request in _pendingRequests) {
|
||||
request.errorBlock(@[jsError]);
|
||||
[request.timeoutTimer invalidate];
|
||||
}
|
||||
[_pendingRequests removeAllObjects];
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ var Image = React.createClass({
|
||||
/**
|
||||
* `uri` is a string representing the resource identifier for the image, which
|
||||
* could be an http address, a local file path, or the name of a static image
|
||||
* resource (which should be wrapped in the `required('image!name')` function).
|
||||
* resource (which should be wrapped in the `require('image!name')` function).
|
||||
*/
|
||||
source: PropTypes.shape({
|
||||
uri: PropTypes.string,
|
||||
@@ -99,6 +99,12 @@ var Image = React.createClass({
|
||||
* testing scripts.
|
||||
*/
|
||||
testID: PropTypes.string,
|
||||
/**
|
||||
* Invoked on mount and layout changes with
|
||||
*
|
||||
* {nativeEvent: { layout: {x, y, width, height}}}.
|
||||
*/
|
||||
onLayout: PropTypes.func,
|
||||
},
|
||||
|
||||
statics: {
|
||||
@@ -140,20 +146,11 @@ var Image = React.createClass({
|
||||
if (this.props.style && this.props.style.tintColor) {
|
||||
warning(RawImage === RCTStaticImage, 'tintColor style only supported on static images.');
|
||||
}
|
||||
var resizeMode = this.props.resizeMode || style.resizeMode;
|
||||
var contentModes = NativeModules.UIManager.UIView.ContentMode;
|
||||
var contentMode;
|
||||
if (resizeMode === ImageResizeMode.stretch) {
|
||||
contentMode = contentModes.ScaleToFill;
|
||||
} else if (resizeMode === ImageResizeMode.contain) {
|
||||
contentMode = contentModes.ScaleAspectFit;
|
||||
} else { // ImageResizeMode.cover or undefined
|
||||
contentMode = contentModes.ScaleAspectFill;
|
||||
}
|
||||
var resizeMode = this.props.resizeMode || style.resizeMode || 'cover';
|
||||
|
||||
var nativeProps = merge(this.props, {
|
||||
style,
|
||||
contentMode,
|
||||
resizeMode,
|
||||
tintColor: style.tintColor,
|
||||
});
|
||||
if (isStored) {
|
||||
@@ -181,7 +178,7 @@ var nativeOnlyProps = {
|
||||
src: true,
|
||||
defaultImageSrc: true,
|
||||
imageTag: true,
|
||||
contentMode: true,
|
||||
resizeMode: true,
|
||||
};
|
||||
if (__DEV__) {
|
||||
verifyPropTypes(Image, RCTStaticImage.viewConfig, nativeOnlyProps);
|
||||
|
||||
@@ -69,7 +69,9 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
||||
NSString *afterCursor = params[@"after"];
|
||||
NSString *groupTypesStr = params[@"groupTypes"];
|
||||
NSString *groupName = params[@"groupName"];
|
||||
NSString *assetType = params[@"assetType"];
|
||||
ALAssetsGroupType groupTypes;
|
||||
|
||||
if ([groupTypesStr isEqualToString:@"Album"]) {
|
||||
groupTypes = ALAssetsGroupAlbum;
|
||||
} else if ([groupTypesStr isEqualToString:@"All"]) {
|
||||
@@ -93,7 +95,15 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
||||
|
||||
[[RCTImageLoader assetsLibrary] enumerateGroupsWithTypes:groupTypes usingBlock:^(ALAssetsGroup *group, BOOL *stopGroups) {
|
||||
if (group && (groupName == nil || [groupName isEqualToString:[group valueForProperty:ALAssetsGroupPropertyName]])) {
|
||||
[group setAssetsFilter:ALAssetsFilter.allPhotos];
|
||||
|
||||
if (assetType == nil || [assetType isEqualToString:@"Photos"]) {
|
||||
[group setAssetsFilter:ALAssetsFilter.allPhotos];
|
||||
} else if ([assetType isEqualToString:@"Videos"]) {
|
||||
[group setAssetsFilter:ALAssetsFilter.allVideos];
|
||||
} else if ([assetType isEqualToString:@"All"]) {
|
||||
[group setAssetsFilter:ALAssetsFilter.allAssets];
|
||||
}
|
||||
|
||||
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stopAssets) {
|
||||
if (result) {
|
||||
NSString *uri = [(NSURL *)[result valueForProperty:ALAssetPropertyAssetURL] absoluteString];
|
||||
|
||||
@@ -33,6 +33,8 @@ typedef void (^RCTImageDownloadBlock)(UIImage *image, NSError *error);
|
||||
- (id)downloadImageForURL:(NSURL *)url
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(UIViewContentMode)resizeMode
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
block:(RCTImageDownloadBlock)block;
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#import "RCTImageDownloader.h"
|
||||
|
||||
#import "RCTCache.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
typedef void (^RCTCachedDataDownloadBlock)(BOOL cached, NSData *data, NSError *error);
|
||||
@@ -81,8 +82,8 @@ static NSString *RCTCacheKeyForURL(NSURL *url)
|
||||
RCTImageDownloader *strongSelf = weakSelf;
|
||||
NSArray *blocks = strongSelf->_pendingBlocks[cacheKey];
|
||||
[strongSelf->_pendingBlocks removeObjectForKey:cacheKey];
|
||||
for (RCTCachedDataDownloadBlock block in blocks) {
|
||||
block(cached, data, error);
|
||||
for (RCTCachedDataDownloadBlock cacheDownloadBlock in blocks) {
|
||||
cacheDownloadBlock(cached, data, error);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -121,34 +122,134 @@ static NSString *RCTCacheKeyForURL(NSURL *url)
|
||||
}];
|
||||
}
|
||||
|
||||
- (id)downloadImageForURL:(NSURL *)url size:(CGSize)size
|
||||
scale:(CGFloat)scale block:(RCTImageDownloadBlock)block
|
||||
/**
|
||||
* Returns the optimal context size for an image drawn using the clip rect
|
||||
* returned by RCTClipRect.
|
||||
*/
|
||||
CGSize RCTTargetSizeForClipRect(CGRect);
|
||||
CGSize RCTTargetSizeForClipRect(CGRect clipRect)
|
||||
{
|
||||
return (CGSize){
|
||||
clipRect.size.width + clipRect.origin.x * 2,
|
||||
clipRect.size.height + clipRect.origin.y * 2
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes an input content size & scale (typically from an image),
|
||||
* a target size & scale that it will be drawn into (typically a CGContext) and
|
||||
* then calculates the optimal rectangle to draw the image into so that it will
|
||||
* be sized and positioned correctly if drawn using the specified content mode.
|
||||
*/
|
||||
CGRect RCTClipRect(CGSize, CGFloat, CGSize, CGFloat, UIViewContentMode);
|
||||
CGRect RCTClipRect(CGSize sourceSize, CGFloat sourceScale,
|
||||
CGSize destSize, CGFloat destScale,
|
||||
UIViewContentMode resizeMode)
|
||||
{
|
||||
// Precompensate for scale
|
||||
CGFloat scale = sourceScale / destScale;
|
||||
sourceSize.width *= scale;
|
||||
sourceSize.height *= scale;
|
||||
|
||||
// Calculate aspect ratios if needed (don't bother is resizeMode == stretch)
|
||||
CGFloat aspect = 0.0, targetAspect = 0.0;
|
||||
if (resizeMode != UIViewContentModeScaleToFill) {
|
||||
aspect = sourceSize.width / sourceSize.height;
|
||||
targetAspect = destSize.width / destSize.height;
|
||||
if (aspect == targetAspect) {
|
||||
resizeMode = UIViewContentModeScaleToFill;
|
||||
}
|
||||
}
|
||||
|
||||
switch (resizeMode) {
|
||||
case UIViewContentModeScaleToFill: // stretch
|
||||
|
||||
sourceSize.width = MIN(destSize.width, sourceSize.width);
|
||||
sourceSize.height = MIN(destSize.height, sourceSize.height);
|
||||
return (CGRect){CGPointZero, sourceSize};
|
||||
|
||||
case UIViewContentModeScaleAspectFit: // contain
|
||||
|
||||
if (targetAspect <= aspect) { // target is taller than content
|
||||
sourceSize.width = destSize.width = MIN(sourceSize.width, destSize.width);
|
||||
sourceSize.height = sourceSize.width / aspect;
|
||||
} else { // target is wider than content
|
||||
sourceSize.height = destSize.height = MIN(sourceSize.height, destSize.height);
|
||||
sourceSize.width = sourceSize.height * aspect;
|
||||
}
|
||||
return (CGRect){CGPointZero, sourceSize};
|
||||
|
||||
case UIViewContentModeScaleAspectFill: // cover
|
||||
|
||||
if (targetAspect <= aspect) { // target is taller than content
|
||||
|
||||
sourceSize.height = destSize.height = MIN(sourceSize.height, destSize.height);
|
||||
sourceSize.width = sourceSize.height * aspect;
|
||||
destSize.width = destSize.height * targetAspect;
|
||||
return (CGRect){{(destSize.width - sourceSize.width) / 2, 0}, sourceSize};
|
||||
|
||||
} else { // target is wider than content
|
||||
|
||||
sourceSize.width = destSize.width = MIN(sourceSize.width, destSize.width);
|
||||
sourceSize.height = sourceSize.width / aspect;
|
||||
destSize.height = destSize.width / targetAspect;
|
||||
return (CGRect){{0, (destSize.height - sourceSize.height) / 2}, sourceSize};
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
RCTLogError(@"A resizeMode value of %zd is not supported", resizeMode);
|
||||
return (CGRect){CGPointZero, destSize};
|
||||
}
|
||||
}
|
||||
|
||||
- (id)downloadImageForURL:(NSURL *)url
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(UIViewContentMode)resizeMode
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
block:(RCTImageDownloadBlock)block
|
||||
{
|
||||
return [self downloadDataForURL:url block:^(NSData *data, NSError *error) {
|
||||
|
||||
if (!data || error) {
|
||||
block(nil, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CGSizeEqualToSize(size, CGSizeZero)) {
|
||||
// Target size wasn't available yet, so abort image drawing
|
||||
block(nil, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
UIImage *image = [UIImage imageWithData:data scale:scale];
|
||||
if (image) {
|
||||
|
||||
// Resize (TODO: should we take aspect ratio into account?)
|
||||
CGSize imageSize = size;
|
||||
if (CGSizeEqualToSize(imageSize, CGSizeZero)) {
|
||||
imageSize = image.size;
|
||||
} else {
|
||||
imageSize = (CGSize){
|
||||
MIN(size.width, image.size.width),
|
||||
MIN(size.height, image.size.height)
|
||||
};
|
||||
}
|
||||
// Get scale and size
|
||||
CGFloat destScale = scale ?: RCTScreenScale();
|
||||
CGRect imageRect = RCTClipRect(image.size, image.scale, size, destScale, resizeMode);
|
||||
CGSize destSize = RCTTargetSizeForClipRect(imageRect);
|
||||
|
||||
// Rescale image if required size is smaller
|
||||
CGFloat imageScale = scale;
|
||||
if (imageScale == 0 || imageScale < image.scale) {
|
||||
imageScale = image.scale;
|
||||
// Opacity optimizations
|
||||
UIColor *blendColor = nil;
|
||||
BOOL opaque = !RCTImageHasAlpha(image.CGImage);
|
||||
if (!opaque && backgroundColor) {
|
||||
CGFloat alpha;
|
||||
[backgroundColor getRed:NULL green:NULL blue:NULL alpha:&alpha];
|
||||
if (alpha > 0.999) { // no benefit to blending if background is translucent
|
||||
opaque = YES;
|
||||
blendColor = backgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
// Decompress image at required size
|
||||
UIGraphicsBeginImageContextWithOptions(imageSize, NO, imageScale);
|
||||
[image drawInRect:(CGRect){{0, 0}, imageSize}];
|
||||
UIGraphicsBeginImageContextWithOptions(destSize, opaque, destScale);
|
||||
if (blendColor) {
|
||||
[blendColor setFill];
|
||||
UIRectFill((CGRect){CGPointZero, destSize});
|
||||
}
|
||||
[image drawInRect:imageRect];
|
||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ static dispatch_queue_t RCTImageLoaderQueue(void)
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
queue = dispatch_queue_create("com.facebook.rctImageLoader", DISPATCH_QUEUE_SERIAL);
|
||||
dispatch_set_target_queue(queue,
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
|
||||
});
|
||||
|
||||
return queue;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#import "RCTGIFImage.h"
|
||||
#import "RCTImageDownloader.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
@implementation RCTNetworkImageView
|
||||
{
|
||||
@@ -26,8 +27,7 @@
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame imageDownloader:(RCTImageDownloader *)imageDownloader
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
_deferSentinel = 0;
|
||||
_imageDownloader = imageDownloader;
|
||||
self.userInteractionEnabled = NO;
|
||||
@@ -37,20 +37,44 @@
|
||||
|
||||
- (NSURL *)imageURL
|
||||
{
|
||||
// We clear our backing layer's imageURL when we are not in a window for a while,
|
||||
// We clear our imageURL when we are not in a window for a while,
|
||||
// to make sure we don't consume network resources while offscreen.
|
||||
// However we don't want to expose this hackery externally.
|
||||
return _deferred ? _deferredImageURL : _imageURL;
|
||||
}
|
||||
|
||||
- (void)setBackgroundColor:(UIColor *)backgroundColor
|
||||
{
|
||||
super.backgroundColor = backgroundColor;
|
||||
[self _updateImage];
|
||||
}
|
||||
|
||||
- (void)reactSetFrame:(CGRect)frame
|
||||
{
|
||||
[super reactSetFrame:frame];
|
||||
[self _updateImage];
|
||||
}
|
||||
|
||||
- (void)_updateImage
|
||||
{
|
||||
[self setImageURL:_imageURL resetToDefaultImageWhileLoading:NO];
|
||||
}
|
||||
|
||||
- (void)setImageURL:(NSURL *)imageURL resetToDefaultImageWhileLoading:(BOOL)reset
|
||||
{
|
||||
if (![_imageURL isEqual:imageURL] && _downloadToken) {
|
||||
[_imageDownloader cancelDownload:_downloadToken];
|
||||
_downloadToken = nil;
|
||||
}
|
||||
|
||||
_imageURL = imageURL;
|
||||
|
||||
if (_deferred) {
|
||||
_deferredImageURL = imageURL;
|
||||
} else {
|
||||
if (_downloadToken) {
|
||||
[_imageDownloader cancelDownload:_downloadToken];
|
||||
_downloadToken = nil;
|
||||
if (!imageURL) {
|
||||
self.layer.contents = nil;
|
||||
return;
|
||||
}
|
||||
if (reset) {
|
||||
self.layer.contentsScale = _defaultImage.scale;
|
||||
@@ -62,25 +86,35 @@
|
||||
_downloadToken = [_imageDownloader downloadDataForURL:imageURL block:^(NSData *data, NSError *error) {
|
||||
if (data) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (imageURL != self.imageURL) {
|
||||
// Image has changed
|
||||
return;
|
||||
}
|
||||
CAKeyframeAnimation *animation = RCTGIFImageWithData(data);
|
||||
self.layer.contentsScale = 1.0;
|
||||
self.layer.minificationFilter = kCAFilterLinear;
|
||||
self.layer.magnificationFilter = kCAFilterLinear;
|
||||
[self.layer addAnimation:animation forKey:@"contents"];
|
||||
});
|
||||
} else if (error) {
|
||||
RCTLogWarn(@"Unable to download image data. Error: %@", error);
|
||||
}
|
||||
// TODO: handle errors
|
||||
}];
|
||||
} else {
|
||||
_downloadToken = [_imageDownloader downloadImageForURL:imageURL size:self.bounds.size scale:RCTScreenScale() block:^(UIImage *image, NSError *error) {
|
||||
_downloadToken = [_imageDownloader downloadImageForURL:imageURL size:self.bounds.size scale:RCTScreenScale() resizeMode:self.contentMode backgroundColor:self.backgroundColor block:^(UIImage *image, NSError *error) {
|
||||
if (image) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (imageURL != self.imageURL) {
|
||||
// Image has changed
|
||||
return;
|
||||
}
|
||||
[self.layer removeAnimationForKey:@"contents"];
|
||||
self.layer.contentsScale = image.scale;
|
||||
self.layer.contents = (__bridge id)image.CGImage;
|
||||
});
|
||||
} else if (error) {
|
||||
RCTLogWarn(@"Unable to download image. Error: %@", error);
|
||||
}
|
||||
// TODO: handle errors
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,6 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
RCT_REMAP_VIEW_PROPERTY(defaultImageSrc, defaultImage, UIImage)
|
||||
RCT_REMAP_VIEW_PROPERTY(src, imageURL, NSURL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(contentMode, UIViewContentMode)
|
||||
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
|
||||
|
||||
@end
|
||||
|
||||
@@ -26,7 +26,7 @@ RCT_EXPORT_MODULE()
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(capInsets, UIEdgeInsets)
|
||||
RCT_EXPORT_VIEW_PROPERTY(contentMode, UIViewContentMode)
|
||||
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
|
||||
RCT_CUSTOM_VIEW_PROPERTY(src, NSURL, RCTStaticImage)
|
||||
{
|
||||
if (json) {
|
||||
|
||||
@@ -175,7 +175,7 @@ describe('resolveAssetSource', () => {
|
||||
isStatic: true,
|
||||
width: 100,
|
||||
height: 200,
|
||||
uri: 'assets_awesomemodule_subdir_logo1_',
|
||||
uri: 'awesomemodule_subdir_logo1_',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -50,7 +50,8 @@ function getPathInArchive(asset) {
|
||||
return (assetDir + '/' + asset.name)
|
||||
.toLowerCase()
|
||||
.replace(/\//g, '_') // Encode folder structure in file name
|
||||
.replace(/([^a-z0-9_])/g, ''); // Remove illegal chars
|
||||
.replace(/([^a-z0-9_])/g, '') // Remove illegal chars
|
||||
.replace(/^assets_/, ''); // Remove "assets_" prefix
|
||||
} else {
|
||||
// E.g. 'assets/AwesomeModule/icon@2x.png'
|
||||
return getScaledAssetPath(asset);
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule Inspector
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ReactInstanceHandles = require('ReactInstanceHandles');
|
||||
var ReactInstanceMap = require('ReactInstanceMap');
|
||||
var ReactNativeMount = require('ReactNativeMount');
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
|
||||
function traverseOwnerTreeUp(hierarchy, instance) {
|
||||
if (instance) {
|
||||
hierarchy.unshift(instance);
|
||||
traverseOwnerTreeUp(hierarchy, instance._currentElement._owner);
|
||||
}
|
||||
}
|
||||
|
||||
function findInstance(component, targetID) {
|
||||
if (targetID === findRootNodeID(component)) {
|
||||
return component;
|
||||
}
|
||||
if (component._renderedComponent) {
|
||||
return findInstance(component._renderedComponent, targetID);
|
||||
} else {
|
||||
for (var key in component._renderedChildren) {
|
||||
var child = component._renderedChildren[key];
|
||||
if (ReactInstanceHandles.isAncestorIDOf(findRootNodeID(child), targetID)) {
|
||||
var instance = findInstance(child, targetID);
|
||||
if (instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findRootNodeID(component) {
|
||||
var internalInstance = ReactInstanceMap.get(component);
|
||||
return internalInstance ? internalInstance._rootNodeID : component._rootNodeID;
|
||||
}
|
||||
|
||||
function findInstanceByNativeTag(rootTag, nativeTag) {
|
||||
var containerID = ReactNativeTagHandles.tagToRootNodeID[rootTag];
|
||||
var rootInstance = ReactNativeMount._instancesByContainerID[containerID];
|
||||
var targetID = ReactNativeTagHandles.tagToRootNodeID[nativeTag];
|
||||
if (!targetID) {
|
||||
return undefined;
|
||||
}
|
||||
return findInstance(rootInstance, targetID);
|
||||
}
|
||||
|
||||
function getOwnerHierarchy(instance) {
|
||||
var hierarchy = [];
|
||||
traverseOwnerTreeUp(hierarchy, instance);
|
||||
return hierarchy;
|
||||
}
|
||||
|
||||
module.exports = {findInstanceByNativeTag, getOwnerHierarchy};
|
||||
@@ -19,6 +19,13 @@ var invariant = require('invariant');
|
||||
var keyMirror = require('keyMirror');
|
||||
var setImmediate = require('setImmediate');
|
||||
|
||||
type Handle = number;
|
||||
|
||||
/**
|
||||
* Maximum time a handle can be open before warning in DEV.
|
||||
*/
|
||||
var DEV_TIMEOUT = 2000;
|
||||
|
||||
var _emitter = new EventEmitter();
|
||||
var _interactionSet = new Set();
|
||||
var _addInteractionSet = new Set();
|
||||
@@ -83,17 +90,25 @@ var InteractionManager = {
|
||||
/**
|
||||
* Notify manager that an interaction has started.
|
||||
*/
|
||||
createInteractionHandle(): number {
|
||||
createInteractionHandle(): Handle {
|
||||
scheduleUpdate();
|
||||
var handle = ++_inc;
|
||||
_addInteractionSet.add(handle);
|
||||
if (__DEV__) {
|
||||
// Capture the stack trace of what created the handle.
|
||||
var error = new Error(
|
||||
'InteractionManager: interaction handle not cleared within ' +
|
||||
DEV_TIMEOUT + ' ms.'
|
||||
);
|
||||
setDevTimeoutHandle(handle, error, DEV_TIMEOUT);
|
||||
}
|
||||
return handle;
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify manager that an interaction has completed.
|
||||
*/
|
||||
clearInteractionHandle(handle: number) {
|
||||
clearInteractionHandle(handle: Handle) {
|
||||
invariant(
|
||||
!!handle,
|
||||
'Must provide a handle to clear.'
|
||||
@@ -151,4 +166,19 @@ function processUpdate() {
|
||||
_deleteInteractionSet.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until `timeout` has passed and warn if the handle has not been cleared.
|
||||
*/
|
||||
function setDevTimeoutHandle(
|
||||
handle: Handle,
|
||||
error: Error,
|
||||
timeout: number
|
||||
): void {
|
||||
setTimeout(() => {
|
||||
if (_interactionSet.has(handle)) {
|
||||
console.warn(error.message + '\n' + error.stack);
|
||||
}
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
module.exports = InteractionManager;
|
||||
|
||||
@@ -30,17 +30,10 @@ function reportException(e: Exception, isFatal: bool, stack?: any) {
|
||||
if (!stack) {
|
||||
stack = parseErrorStack(e);
|
||||
}
|
||||
if (!RCTExceptionsManager.reportFatalException ||
|
||||
!RCTExceptionsManager.reportSoftException) {
|
||||
// Backwards compatibility - no differentiation
|
||||
// TODO(#7049989): deprecate reportUnhandledException on Android
|
||||
RCTExceptionsManager.reportUnhandledException(e.message, stack);
|
||||
if (isFatal) {
|
||||
RCTExceptionsManager.reportFatalException(e.message, stack);
|
||||
} else {
|
||||
if (isFatal) {
|
||||
RCTExceptionsManager.reportFatalException(e.message, stack);
|
||||
} else {
|
||||
RCTExceptionsManager.reportSoftException(e.message, stack);
|
||||
}
|
||||
RCTExceptionsManager.reportSoftException(e.message, stack);
|
||||
}
|
||||
if (__DEV__) {
|
||||
(sourceMapPromise = sourceMapPromise || loadSourceMap())
|
||||
|
||||
@@ -33,7 +33,7 @@ if (typeof window === 'undefined') {
|
||||
window = GLOBAL;
|
||||
}
|
||||
|
||||
function handleErrorWithRedBox(e, isFatal) {
|
||||
function handleError(e, isFatal) {
|
||||
try {
|
||||
require('ExceptionsManager').handleException(e, isFatal);
|
||||
} catch(ee) {
|
||||
@@ -43,7 +43,7 @@ function handleErrorWithRedBox(e, isFatal) {
|
||||
|
||||
function setUpRedBoxErrorHandler() {
|
||||
var ErrorUtils = require('ErrorUtils');
|
||||
ErrorUtils.setGlobalHandler(handleErrorWithRedBox);
|
||||
ErrorUtils.setGlobalHandler(handleError);
|
||||
}
|
||||
|
||||
function setUpRedBoxConsoleErrorHandler() {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* and wrapping resulting file into `wrapper` function.
|
||||
*
|
||||
*/
|
||||
/*eslint-disable */
|
||||
|
||||
var scope = {};
|
||||
wrapper.call(scope);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*
|
||||
* @nolint
|
||||
*/
|
||||
/* eslint-disable */
|
||||
|
||||
(function() {
|
||||
var define = null; // Hack to make it work with our packager
|
||||
|
||||
@@ -43,7 +43,6 @@ var JSTimers = {
|
||||
var newID = JSTimersExecution.GUID++;
|
||||
var freeIndex = JSTimers._getFreeIndex();
|
||||
JSTimersExecution.timerIDs[freeIndex] = newID;
|
||||
JSTimersExecution.callbacks[freeIndex] = func;
|
||||
JSTimersExecution.callbacks[freeIndex] = function() {
|
||||
return func.apply(undefined, args);
|
||||
};
|
||||
@@ -60,7 +59,6 @@ var JSTimers = {
|
||||
var newID = JSTimersExecution.GUID++;
|
||||
var freeIndex = JSTimers._getFreeIndex();
|
||||
JSTimersExecution.timerIDs[freeIndex] = newID;
|
||||
JSTimersExecution.callbacks[freeIndex] = func;
|
||||
JSTimersExecution.callbacks[freeIndex] = function() {
|
||||
return func.apply(undefined, args);
|
||||
};
|
||||
@@ -77,7 +75,6 @@ var JSTimers = {
|
||||
var newID = JSTimersExecution.GUID++;
|
||||
var freeIndex = JSTimers._getFreeIndex();
|
||||
JSTimersExecution.timerIDs[freeIndex] = newID;
|
||||
JSTimersExecution.callbacks[freeIndex] = func;
|
||||
JSTimersExecution.callbacks[freeIndex] = function() {
|
||||
return func.apply(undefined, args);
|
||||
};
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule RCTNativeAppEventEmitter
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var transformSource = require('./jestSupport/scriptPreprocess.js').transformSource;
|
||||
var linterTransform = require('./lint/linterTransform');
|
||||
var EventEmitter = require('EventEmitter');
|
||||
|
||||
linterTransform.setLinterTransform(transformSource);
|
||||
var RCTNativeAppEventEmitter = new EventEmitter();
|
||||
|
||||
// Run the original CLI
|
||||
require('eslint/bin/eslint');
|
||||
module.exports = RCTNativeAppEventEmitter;
|
||||
@@ -12,8 +12,14 @@
|
||||
'use strict';
|
||||
|
||||
var NativeModules = require('NativeModules');
|
||||
var Platform = require('Platform');
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
var RCTReachability = NativeModules.Reachability;
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
var RCTNetInfo = NativeModules.Reachability;
|
||||
} else if (Platform.OS === 'android') {
|
||||
var RCTNetInfo = NativeModules.NetInfo;
|
||||
}
|
||||
|
||||
var DEVICE_REACHABILITY_EVENT = 'reachabilityDidChange';
|
||||
|
||||
@@ -28,11 +34,50 @@ type ReachabilityStateIOS = $Enum<{
|
||||
wifi: string;
|
||||
}>;
|
||||
|
||||
type ConnectivityStateAndroid = $Enum<{
|
||||
NONE: string;
|
||||
MOBILE: string;
|
||||
WIFI: string;
|
||||
MOBILE_MMS: string;
|
||||
MOBILE_SUPL: string;
|
||||
MOBILE_DUN: string;
|
||||
MOBILE_HIPRI: string;
|
||||
WIMAX: string;
|
||||
BLUETOOTH: string;
|
||||
DUMMY: string;
|
||||
ETHERNET: string;
|
||||
MOBILE_FOTA: string;
|
||||
MOBILE_IMS: string;
|
||||
MOBILE_CBS: string;
|
||||
WIFI_P2P: string;
|
||||
MOBILE_IA: string;
|
||||
MOBILE_EMERGENCY: string;
|
||||
PROXY: string;
|
||||
VPN: string;
|
||||
UNKNOWN: string;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* NetInfo exposes info about online/offline status
|
||||
*
|
||||
* ### reachabilityIOS
|
||||
* ```
|
||||
* NetInfo.fetch().done((reach) => {
|
||||
* console.log('Initial: ' + reach);
|
||||
* });
|
||||
* function handleFirstConnectivityChange(reach) {
|
||||
* console.log('First change: ' + reach);
|
||||
* NetInfo.removeEventListener(
|
||||
* 'change',
|
||||
* handleFirstConnectivityChange
|
||||
* );
|
||||
* }
|
||||
* NetInfo.addEventListener(
|
||||
* 'change',
|
||||
* handleFirstConnectivityChange
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* ### IOS
|
||||
*
|
||||
* Asynchronously determine if the device is online and on a cellular network.
|
||||
*
|
||||
@@ -41,21 +86,35 @@ type ReachabilityStateIOS = $Enum<{
|
||||
* - `cell` - device is connected via Edge, 3G, WiMax, or LTE
|
||||
* - `unknown` - error case and the network status is unknown
|
||||
*
|
||||
* ```
|
||||
* NetInfo.reachabilityIOS.fetch().done((reach) => {
|
||||
* console.log('Initial: ' + reach);
|
||||
* ### Android
|
||||
*
|
||||
* Asynchronously determine if the device is connected and details about that connection.
|
||||
*
|
||||
* Android Connectivity Types
|
||||
* - `NONE` - device is offline
|
||||
* - `BLUETOOTH` - The Bluetooth data connection.
|
||||
* - `DUMMY` - Dummy data connection.
|
||||
* - `ETHERNET` - The Ethernet data connection.
|
||||
* - `MOBILE` - The Mobile data connection.
|
||||
* - `MOBILE_DUN` - A DUN-specific Mobile data connection.
|
||||
* - `MOBILE_HIPRI` - A High Priority Mobile data connection.
|
||||
* - `MOBILE_MMS` - An MMS-specific Mobile data connection.
|
||||
* - `MOBILE_SUPL` - A SUPL-specific Mobile data connection.
|
||||
* - `VPN` - A virtual network using one or more native bearers. Requires API Level 21
|
||||
* - `WIFI` - The WIFI data connection.
|
||||
* - `WIMAX` - The WiMAX data connection.
|
||||
* - `UNKNOWN` - Unknown data connection.
|
||||
* The rest ConnectivityStates are hidden by the Android API, but can be used if necessary.
|
||||
*
|
||||
* ### isConnectionMetered
|
||||
*
|
||||
* Available on Android. Detect if the current active connection is metered or not. A network is
|
||||
* classified as metered when the user is sensitive to heavy data usage on that connection due to
|
||||
* monetary costs, data limitations or battery/performance issues.
|
||||
*
|
||||
* NetInfo.isConnectionMetered((isConnectionMetered) => {
|
||||
* console.log('Connection is ' + (isConnectionMetered ? 'Metered' : 'Not Metered'));
|
||||
* });
|
||||
* function handleFirstReachabilityChange(reach) {
|
||||
* console.log('First change: ' + reach);
|
||||
* NetInfo.reachabilityIOS.removeEventListener(
|
||||
* 'change',
|
||||
* handleFirstReachabilityChange
|
||||
* );
|
||||
* }
|
||||
* NetInfo.reachabilityIOS.addEventListener(
|
||||
* 'change',
|
||||
* handleFirstReachabilityChange
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* ### isConnected
|
||||
@@ -81,89 +140,101 @@ type ReachabilityStateIOS = $Enum<{
|
||||
* ```
|
||||
*/
|
||||
|
||||
var NetInfo = {};
|
||||
var _subscriptions = {};
|
||||
|
||||
if (RCTReachability) {
|
||||
|
||||
// RCTReachability is exposed, so this is an iOS-like environment and we will
|
||||
// expose reachabilityIOS
|
||||
|
||||
var _reachabilitySubscriptions = {};
|
||||
|
||||
NetInfo.reachabilityIOS = {
|
||||
addEventListener: function (
|
||||
eventName: ChangeEventName,
|
||||
handler: Function
|
||||
): void {
|
||||
_reachabilitySubscriptions[handler] = RCTDeviceEventEmitter.addListener(
|
||||
DEVICE_REACHABILITY_EVENT,
|
||||
(appStateData) => {
|
||||
handler(appStateData.network_reachability);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
removeEventListener: function(
|
||||
eventName: ChangeEventName,
|
||||
handler: Function
|
||||
): void {
|
||||
if (!_reachabilitySubscriptions[handler]) {
|
||||
return;
|
||||
var NetInfo = {
|
||||
addEventListener: function (
|
||||
eventName: ChangeEventName,
|
||||
handler: Function
|
||||
): void {
|
||||
_subscriptions[handler] = RCTDeviceEventEmitter.addListener(
|
||||
DEVICE_REACHABILITY_EVENT,
|
||||
(appStateData) => {
|
||||
handler(appStateData.network_reachability);
|
||||
}
|
||||
_reachabilitySubscriptions[handler].remove();
|
||||
_reachabilitySubscriptions[handler] = null;
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
fetch: function(): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTReachability.getCurrentReachability(
|
||||
function(resp) {
|
||||
resolve(resp.network_reachability);
|
||||
},
|
||||
reject
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
removeEventListener: function(
|
||||
eventName: ChangeEventName,
|
||||
handler: Function
|
||||
): void {
|
||||
if (!_subscriptions[handler]) {
|
||||
return;
|
||||
}
|
||||
_subscriptions[handler].remove();
|
||||
_subscriptions[handler] = null;
|
||||
},
|
||||
|
||||
var _isConnectedSubscriptions = {};
|
||||
fetch: function(): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTNetInfo.getCurrentReachability(
|
||||
function(resp) {
|
||||
resolve(resp.network_reachability);
|
||||
},
|
||||
reject
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
var _iosReachabilityIsConnected = function(
|
||||
isConnected: {},
|
||||
|
||||
isConnectionMetered: {},
|
||||
};
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
var _isConnected = function(
|
||||
reachability: ReachabilityStateIOS
|
||||
): bool {
|
||||
return reachability !== 'none' &&
|
||||
reachability !== 'unknown';
|
||||
};
|
||||
} else if (Platform.OS === 'android') {
|
||||
var _isConnected = function(
|
||||
connectionType: ConnectivityStateAndroid
|
||||
): bool {
|
||||
return connectionType !== 'NONE' && connectionType !== 'UNKNOWN';
|
||||
};
|
||||
}
|
||||
|
||||
NetInfo.isConnected = {
|
||||
addEventListener: function (
|
||||
eventName: ChangeEventName,
|
||||
handler: Function
|
||||
): void {
|
||||
_isConnectedSubscriptions[handler] = (reachability) => {
|
||||
handler(_iosReachabilityIsConnected(reachability));
|
||||
};
|
||||
NetInfo.reachabilityIOS.addEventListener(
|
||||
eventName,
|
||||
_isConnectedSubscriptions[handler]
|
||||
);
|
||||
},
|
||||
var _isConnectedSubscriptions = {};
|
||||
|
||||
removeEventListener: function(
|
||||
eventName: ChangeEventName,
|
||||
handler: Function
|
||||
): void {
|
||||
NetInfo.reachabilityIOS.removeEventListener(
|
||||
eventName,
|
||||
_isConnectedSubscriptions[handler]
|
||||
);
|
||||
},
|
||||
NetInfo.isConnected = {
|
||||
addEventListener: function (
|
||||
eventName: ChangeEventName,
|
||||
handler: Function
|
||||
): void {
|
||||
_isConnectedSubscriptions[handler] = (connection) => {
|
||||
handler(_isConnected(connection));
|
||||
};
|
||||
NetInfo.addEventListener(
|
||||
eventName,
|
||||
_isConnectedSubscriptions[handler]
|
||||
);
|
||||
},
|
||||
|
||||
fetch: function(): Promise {
|
||||
return NetInfo.reachabilityIOS.fetch().then(
|
||||
(reachability) => _iosReachabilityIsConnected(reachability)
|
||||
);
|
||||
},
|
||||
removeEventListener: function(
|
||||
eventName: ChangeEventName,
|
||||
handler: Function
|
||||
): void {
|
||||
NetInfo.removeEventListener(
|
||||
eventName,
|
||||
_isConnectedSubscriptions[handler]
|
||||
);
|
||||
},
|
||||
|
||||
fetch: function(): Promise {
|
||||
return NetInfo.fetch().then(
|
||||
(connection) => _isConnected(connection)
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
NetInfo.isConnectionMetered = function(callback): void {
|
||||
RCTNetInfo.isConnectionMetered((_isMetered) => {
|
||||
callback(_isMetered);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ RCT_EXPORT_MODULE()
|
||||
*/
|
||||
RCT_EXPORT_METHOD(queryData:(NSString *)queryType
|
||||
withQuery:(NSDictionary *)query
|
||||
queryHash:(__unused NSString *)queryHash
|
||||
responseSender:(RCTResponseSenderBlock)responseSender)
|
||||
{
|
||||
if ([queryType isEqualToString:@"http"]) {
|
||||
@@ -39,34 +38,35 @@ RCT_EXPORT_METHOD(queryData:(NSString *)queryType
|
||||
// Build data task
|
||||
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *connectionError) {
|
||||
|
||||
NSHTTPURLResponse *httpResponse = nil;
|
||||
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
// Might be a local file request
|
||||
httpResponse = (NSHTTPURLResponse *)response;
|
||||
}
|
||||
|
||||
// Build response
|
||||
NSDictionary *responseJSON;
|
||||
NSArray *responseJSON;
|
||||
if (connectionError == nil) {
|
||||
NSStringEncoding encoding = NSUTF8StringEncoding;
|
||||
if (response.textEncodingName) {
|
||||
CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
|
||||
encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
|
||||
}
|
||||
NSHTTPURLResponse *httpResponse = nil;
|
||||
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
// Might be a local file request
|
||||
httpResponse = (NSHTTPURLResponse *)response;
|
||||
}
|
||||
responseJSON = @{
|
||||
@"status": @([httpResponse statusCode] ?: 200),
|
||||
@"responseHeaders": [httpResponse allHeaderFields] ?: @{},
|
||||
@"responseText": [[NSString alloc] initWithData:data encoding:encoding] ?: @""
|
||||
};
|
||||
responseJSON = @[
|
||||
@(httpResponse.statusCode ?: 200),
|
||||
httpResponse.allHeaderFields ?: @{},
|
||||
[[NSString alloc] initWithData:data encoding:encoding] ?: @"",
|
||||
];
|
||||
} else {
|
||||
responseJSON = @{
|
||||
@"status": @0,
|
||||
@"responseHeaders": @{},
|
||||
@"responseText": [connectionError localizedDescription] ?: [NSNull null]
|
||||
};
|
||||
responseJSON = @[
|
||||
@(httpResponse.statusCode),
|
||||
httpResponse.allHeaderFields ?: @{},
|
||||
connectionError.localizedDescription ?: [NSNull null],
|
||||
];
|
||||
}
|
||||
|
||||
// Send response (won't be sent on same thread as caller)
|
||||
responseSender(@[RCTJSONStringify(responseJSON, NULL)]);
|
||||
responseSender(responseJSON);
|
||||
|
||||
}];
|
||||
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
|
||||
var RCTDataManager = require('NativeModules').DataManager;
|
||||
|
||||
var crc32 = require('crc32');
|
||||
|
||||
var XMLHttpRequestBase = require('XMLHttpRequestBase');
|
||||
|
||||
class XMLHttpRequest extends XMLHttpRequestBase {
|
||||
@@ -28,12 +26,7 @@ class XMLHttpRequest extends XMLHttpRequestBase {
|
||||
data: data,
|
||||
headers: headers,
|
||||
},
|
||||
// TODO: Do we need this? is it used anywhere?
|
||||
'h' + crc32(method + '|' + url + '|' + data),
|
||||
(result) => {
|
||||
result = JSON.parse(result);
|
||||
this.callback(result.status, result.responseHeaders, result.responseText);
|
||||
}
|
||||
this.callback.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class XMLHttpRequestBase {
|
||||
readyState: number;
|
||||
responseHeaders: ?Object;
|
||||
responseText: ?string;
|
||||
status: ?string;
|
||||
status: number;
|
||||
|
||||
_method: ?string;
|
||||
_url: ?string;
|
||||
@@ -43,7 +43,7 @@ class XMLHttpRequestBase {
|
||||
this.readyState = this.UNSENT;
|
||||
this.responseHeaders = undefined;
|
||||
this.responseText = undefined;
|
||||
this.status = undefined;
|
||||
this.status = 0;
|
||||
|
||||
this._method = null;
|
||||
this._url = null;
|
||||
@@ -73,7 +73,7 @@ class XMLHttpRequestBase {
|
||||
}
|
||||
|
||||
setRequestHeader(header: string, value: any): void {
|
||||
this._headers[header] = value;
|
||||
this._headers[header.toLowerCase()] = value;
|
||||
}
|
||||
|
||||
open(method: string, url: string, async: ?boolean): void {
|
||||
@@ -127,7 +127,7 @@ class XMLHttpRequestBase {
|
||||
this._aborted = true;
|
||||
}
|
||||
|
||||
callback(status: string, responseHeaders: ?Object, responseText: string): void {
|
||||
callback(status: number, responseHeaders: ?Object, responseText: string): void {
|
||||
if (this._aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,7 @@ var RCTPickerIOSConsts = require('NativeModules').UIManager.RCTPicker.Constants;
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var View = require('View');
|
||||
|
||||
var createReactNativeComponentClass =
|
||||
require('createReactNativeComponentClass');
|
||||
var requireNativeComponent = require('requireNativeComponent');
|
||||
var merge = require('merge');
|
||||
|
||||
var PICKER = 'picker';
|
||||
@@ -60,7 +59,7 @@ var PickerIOS = React.createClass({
|
||||
<View style={this.props.style}>
|
||||
<RCTPickerIOS
|
||||
ref={PICKER}
|
||||
style={styles.rkPickerIOS}
|
||||
style={styles.pickerIOS}
|
||||
items={this.state.items}
|
||||
selectedIndex={this.state.selectedIndex}
|
||||
onChange={this._onChange}
|
||||
@@ -104,7 +103,7 @@ PickerIOS.Item = React.createClass({
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
rkPickerIOS: {
|
||||
pickerIOS: {
|
||||
// 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.
|
||||
@@ -112,14 +111,6 @@ var styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
var rkPickerIOSAttributes = merge(ReactNativeViewAttributes.UIView, {
|
||||
items: true,
|
||||
selectedIndex: true,
|
||||
});
|
||||
|
||||
var RCTPickerIOS = createReactNativeComponentClass({
|
||||
validAttributes: rkPickerIOSAttributes,
|
||||
uiViewClassName: 'RCTPicker',
|
||||
});
|
||||
var RCTPickerIOS = requireNativeComponent('RCTPicker', null);
|
||||
|
||||
module.exports = PickerIOS;
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var NativeModules = require('NativeModules');
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
var RCTPushNotificationManager = require('NativeModules').PushNotificationManager;
|
||||
var invariant = require('invariant');
|
||||
@@ -21,6 +20,7 @@ var _initialNotification = RCTPushNotificationManager &&
|
||||
RCTPushNotificationManager.initialNotification;
|
||||
|
||||
var DEVICE_NOTIF_EVENT = 'remoteNotificationReceived';
|
||||
var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
|
||||
|
||||
/**
|
||||
* Handle push notifications for your app, including permission handling and
|
||||
@@ -50,30 +50,72 @@ class PushNotificationIOS {
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a listener to remote notifications while the app is running in the
|
||||
* foreground or the background.
|
||||
* Attaches a listener to remote notification events while the app is running
|
||||
* in the foreground or the background.
|
||||
*
|
||||
* The handler will get be invoked with an instance of `PushNotificationIOS`
|
||||
* Valid events are:
|
||||
*
|
||||
* - `notification` : Fired when a remote notification is received. The
|
||||
* handler will be invoked with an instance of `PushNotificationIOS`.
|
||||
* - `register`: Fired when the user registers for remote notifications. The
|
||||
* handler will be invoked with a hex string representing the deviceToken.
|
||||
*/
|
||||
static addEventListener(type: string, handler: Function) {
|
||||
invariant(
|
||||
type === 'notification',
|
||||
'PushNotificationIOS only supports `notification` events'
|
||||
);
|
||||
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
|
||||
DEVICE_NOTIF_EVENT,
|
||||
(notifData) => {
|
||||
handler(new PushNotificationIOS(notifData));
|
||||
}
|
||||
type === 'notification' || type === 'register',
|
||||
'PushNotificationIOS only supports `notification` and `register` events'
|
||||
);
|
||||
if (type === 'notification') {
|
||||
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
|
||||
DEVICE_NOTIF_EVENT,
|
||||
(notifData) => {
|
||||
handler(new PushNotificationIOS(notifData));
|
||||
}
|
||||
);
|
||||
} else if (type === 'register') {
|
||||
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
|
||||
NOTIF_REGISTER_EVENT,
|
||||
(registrationInfo) => {
|
||||
handler(registrationInfo.deviceToken);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests all notification permissions from iOS, prompting the user's
|
||||
* dialog box.
|
||||
* Requests notification permissions from iOS, prompting the user's
|
||||
* dialog box. By default, it will request all notification permissions, but
|
||||
* a subset of these can be requested by passing a map of requested
|
||||
* permissions.
|
||||
* The following permissions are supported:
|
||||
*
|
||||
* - `alert`
|
||||
* - `badge`
|
||||
* - `sound`
|
||||
*
|
||||
* If a map is provided to the method, only the permissions with truthy values
|
||||
* will be requested.
|
||||
*/
|
||||
static requestPermissions() {
|
||||
RCTPushNotificationManager.requestPermissions();
|
||||
static requestPermissions(permissions?: {
|
||||
alert?: boolean,
|
||||
badge?: boolean,
|
||||
sound?: boolean
|
||||
}) {
|
||||
var requestedPermissions = {};
|
||||
if (permissions) {
|
||||
requestedPermissions = {
|
||||
alert: !!permissions.alert,
|
||||
badge: !!permissions.badge,
|
||||
sound: !!permissions.sound
|
||||
};
|
||||
} else {
|
||||
requestedPermissions = {
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true
|
||||
};
|
||||
}
|
||||
RCTPushNotificationManager.requestPermissions(requestedPermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,8 +140,8 @@ class PushNotificationIOS {
|
||||
*/
|
||||
static removeEventListener(type: string, handler: Function) {
|
||||
invariant(
|
||||
type === 'notification',
|
||||
'PushNotificationIOS only supports `notification` events'
|
||||
type === 'notification' || type === 'register',
|
||||
'PushNotificationIOS only supports `notification` and `register` events'
|
||||
);
|
||||
if (!_notifHandlers[handler]) {
|
||||
return;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
@interface RCTPushNotificationManager : NSObject <RCTBridgeModule>
|
||||
|
||||
+ (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
|
||||
+ (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
|
||||
+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification;
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,7 +12,18 @@
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
|
||||
|
||||
#define UIUserNotificationTypeAlert UIRemoteNotificationTypeAlert
|
||||
#define UIUserNotificationTypeBadge UIRemoteNotificationTypeBadge
|
||||
#define UIUserNotificationTypeSound UIRemoteNotificationTypeSound
|
||||
#define UIUserNotificationTypeNone UIRemoteNotificationTypeNone
|
||||
#define UIUserNotificationType UIRemoteNotificationType
|
||||
|
||||
#endif
|
||||
|
||||
NSString *const RCTRemoteNotificationReceived = @"RemoteNotificationReceived";
|
||||
NSString *const RCTRemoteNotificationsRegistered = @"RemoteNotificationsRegistered";
|
||||
|
||||
@implementation RCTPushNotificationManager
|
||||
{
|
||||
@@ -30,6 +41,10 @@ RCT_EXPORT_MODULE()
|
||||
selector:@selector(handleRemoteNotificationReceived:)
|
||||
name:RCTRemoteNotificationReceived
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleRemoteNotificationsRegistered:)
|
||||
name:RCTRemoteNotificationsRegistered
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -52,6 +67,21 @@ RCT_EXPORT_MODULE()
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
|
||||
{
|
||||
NSMutableString *hexString = [NSMutableString string];
|
||||
const unsigned char *bytes = [deviceToken bytes];
|
||||
for (int i = 0; i < [deviceToken length]; i++) {
|
||||
[hexString appendFormat:@"%02x", bytes[i]];
|
||||
}
|
||||
NSDictionary *userInfo = @{
|
||||
@"deviceToken" : [hexString copy]
|
||||
};
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationsRegistered
|
||||
object:self
|
||||
userInfo:userInfo];
|
||||
}
|
||||
|
||||
+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationReceived
|
||||
@@ -65,6 +95,12 @@ RCT_EXPORT_MODULE()
|
||||
body:[notification userInfo]];
|
||||
}
|
||||
|
||||
- (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
|
||||
{
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"remoteNotificationsRegistered"
|
||||
body:[notification userInfo]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the application icon badge number on the home screen
|
||||
*/
|
||||
@@ -83,36 +119,35 @@ RCT_EXPORT_METHOD(getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback
|
||||
]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(requestPermissions)
|
||||
RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions)
|
||||
{
|
||||
Class _UIUserNotificationSettings;
|
||||
if ((_UIUserNotificationSettings = NSClassFromString(@"UIUserNotificationSettings"))) {
|
||||
UIUserNotificationType types = UIUserNotificationTypeSound | UIUserNotificationTypeBadge | UIUserNotificationTypeAlert;
|
||||
UIUserNotificationSettings *notificationSettings = [_UIUserNotificationSettings settingsForTypes:types categories:nil];
|
||||
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
|
||||
UIUserNotificationType types = UIRemoteNotificationTypeNone;
|
||||
if (permissions) {
|
||||
if ([permissions[@"alert"] boolValue]) {
|
||||
types |= UIUserNotificationTypeAlert;
|
||||
}
|
||||
if ([permissions[@"badge"] boolValue]) {
|
||||
types |= UIUserNotificationTypeBadge;
|
||||
}
|
||||
if ([permissions[@"sound"] boolValue]) {
|
||||
types |= UIUserNotificationTypeSound;
|
||||
}
|
||||
} else {
|
||||
types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
|
||||
}
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
|
||||
|
||||
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
|
||||
UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert];
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
|
||||
id notificationSettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
|
||||
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
|
||||
[[UIApplication sharedApplication] registerForRemoteNotifications];
|
||||
#else
|
||||
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
|
||||
{
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
|
||||
|
||||
#define UIUserNotificationTypeAlert UIRemoteNotificationTypeAlert
|
||||
#define UIUserNotificationTypeBadge UIRemoteNotificationTypeBadge
|
||||
#define UIUserNotificationTypeSound UIRemoteNotificationTypeSound
|
||||
|
||||
#endif
|
||||
|
||||
NSUInteger types = 0;
|
||||
if ([UIApplication instancesRespondToSelector:@selector(currentUserNotificationSettings)]) {
|
||||
types = [[[UIApplication sharedApplication] currentUserNotificationSettings] types];
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#import "FBSnapshotTestController.h"
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTUIManager.h"
|
||||
|
||||
@@ -63,4 +64,9 @@ RCT_EXPORT_METHOD(markTestCompleted)
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(sendAppEvent:(NSString *)name body:(id)body)
|
||||
{
|
||||
[_bridge.eventDispatcher sendAppEventWithName:name body:body];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -35,7 +35,11 @@
|
||||
sanitizedAppName = [sanitizedAppName stringByReplacingOccurrencesOfString:@"\\" withString:@"-"];
|
||||
_testController = [[FBSnapshotTestController alloc] initWithTestName:sanitizedAppName];
|
||||
_testController.referenceImagesDirectory = referenceDir;
|
||||
#if RUNNING_ON_CI
|
||||
_scriptURL = [[NSBundle bundleForClass:[RCTBridge class]] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
#else
|
||||
_scriptURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.includeRequire.runModule.bundle?dev=true", app]];
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||