diff --git a/.flowconfig b/.flowconfig
index ca1e816a28f..2adb896a567 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -13,6 +13,7 @@
; Ignore unexpected extra "@providesModule"
.*/node_modules/.*/node_modules/fbjs/.*
++.*/node_modules/react-dom/.*
; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
diff --git a/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml b/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
index 308604da538..ddad36d2191 100644
--- a/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
+++ b/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
@@ -10,6 +10,7 @@
+
diff --git a/Examples/UIExplorer/js/CameraRollView.js b/Examples/UIExplorer/js/CameraRollView.js
index 8bb9fbd2b07..5ffca8e0da9 100644
--- a/Examples/UIExplorer/js/CameraRollView.js
+++ b/Examples/UIExplorer/js/CameraRollView.js
@@ -27,9 +27,11 @@ var React = require('react');
var ReactNative = require('react-native');
var {
ActivityIndicator,
+ Alert,
CameraRoll,
Image,
ListView,
+ PermissionsAndroid,
Platform,
StyleSheet,
View,
@@ -137,13 +139,27 @@ var CameraRollView = React.createClass({
}
},
- _fetch: function(clear?: boolean) {
+ _fetch: async function(clear?: boolean) {
if (clear) {
this.setState(this.getInitialState(), this.fetch);
return;
}
- var fetchParams: Object = {
+ if (Platform.OS === 'android') {
+ const result = await PermissionsAndroid.request(
+ PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
+ {
+ title: 'Permission Explanation',
+ message: 'UIExplorer would like to access your pictures.',
+ },
+ );
+ if (result !== 'granted') {
+ Alert.alert('Access to pictures was denied.');
+ return;
+ }
+ }
+
+ const fetchParams: Object = {
first: this.props.batchSize,
groupTypes: this.props.groupTypes,
assetType: this.props.assetType,
@@ -156,8 +172,12 @@ var CameraRollView = React.createClass({
fetchParams.after = this.state.lastCursor;
}
- CameraRoll.getPhotos(fetchParams)
- .then((data) => this._appendAssets(data), (e) => logError(e));
+ try {
+ const data = await CameraRoll.getPhotos(fetchParams);
+ this._appendAssets(data);
+ } catch (e) {
+ logError(e);
+ }
},
/**
@@ -178,6 +198,7 @@ var CameraRollView = React.createClass({
onEndReached={this._onEndReached}
style={styles.container}
dataSource={this.state.dataSource}
+ enableEmptySections
/>
);
},
diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js
index 581989684c0..54d9ae70802 100644
--- a/Libraries/CameraRoll/CameraRoll.js
+++ b/Libraries/CameraRoll/CameraRoll.js
@@ -11,7 +11,8 @@
*/
'use strict';
-var ReactPropTypes = require('React').PropTypes
+// $FlowFixMe `checkPropTypes` is not in Flow's built in React typedefs yet.
+var {PropTypes, checkPropTypes} = require('React');
var RCTCameraRollManager = require('NativeModules').CameraRollManager;
var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
@@ -47,64 +48,65 @@ var getPhotosParamChecker = createStrictShapeTypeChecker({
* The number of photos wanted in reverse order of the photo application
* (i.e. most recent first for SavedPhotos).
*/
- first: ReactPropTypes.number.isRequired,
+ first: PropTypes.number.isRequired,
/**
* A cursor that matches `page_info { end_cursor }` returned from a previous
* call to `getPhotos`
*/
- after: ReactPropTypes.string,
+ after: PropTypes.string,
/**
* Specifies which group types to filter the results to.
*/
- groupTypes: ReactPropTypes.oneOf(GROUP_TYPES_OPTIONS),
+ groupTypes: PropTypes.oneOf(GROUP_TYPES_OPTIONS),
/**
* Specifies filter on group names, like 'Recent Photos' or custom album
* titles.
*/
- groupName: ReactPropTypes.string,
+ groupName: PropTypes.string,
/**
* Specifies filter on asset type
*/
- assetType: ReactPropTypes.oneOf(ASSET_TYPE_OPTIONS),
+ assetType: PropTypes.oneOf(ASSET_TYPE_OPTIONS),
/**
* Filter by mimetype (e.g. image/jpeg).
*/
- mimeTypes: ReactPropTypes.arrayOf(ReactPropTypes.string),
+ mimeTypes: PropTypes.arrayOf(PropTypes.string),
});
/**
* Shape of the return value of the `getPhotos` function.
*/
var getPhotosReturnChecker = createStrictShapeTypeChecker({
- edges: ReactPropTypes.arrayOf(createStrictShapeTypeChecker({
+ // $FlowFixMe(>=0.41.0)
+ edges: PropTypes.arrayOf(createStrictShapeTypeChecker({
node: createStrictShapeTypeChecker({
- type: ReactPropTypes.string.isRequired,
- group_name: ReactPropTypes.string.isRequired,
+ type: PropTypes.string.isRequired,
+ group_name: PropTypes.string.isRequired,
image: createStrictShapeTypeChecker({
- uri: ReactPropTypes.string.isRequired,
- height: ReactPropTypes.number.isRequired,
- width: ReactPropTypes.number.isRequired,
- isStored: ReactPropTypes.bool,
+ uri: PropTypes.string.isRequired,
+ height: PropTypes.number.isRequired,
+ width: PropTypes.number.isRequired,
+ isStored: PropTypes.bool,
}).isRequired,
- timestamp: ReactPropTypes.number.isRequired,
+ timestamp: PropTypes.number.isRequired,
location: createStrictShapeTypeChecker({
- latitude: ReactPropTypes.number,
- longitude: ReactPropTypes.number,
- altitude: ReactPropTypes.number,
- heading: ReactPropTypes.number,
- speed: ReactPropTypes.number,
+ latitude: PropTypes.number,
+ longitude: PropTypes.number,
+ altitude: PropTypes.number,
+ heading: PropTypes.number,
+ speed: PropTypes.number,
}),
}).isRequired,
})).isRequired,
page_info: createStrictShapeTypeChecker({
- has_next_page: ReactPropTypes.bool.isRequired,
- start_cursor: ReactPropTypes.string,
- end_cursor: ReactPropTypes.string,
+ has_next_page: PropTypes.bool.isRequired,
+ start_cursor: PropTypes.string,
+ end_cursor: PropTypes.string,
}).isRequired,
});
@@ -213,7 +215,7 @@ class CameraRoll {
*/
static getPhotos(params) {
if (__DEV__) {
- getPhotosParamChecker({params}, 'params', 'CameraRoll.getPhotos');
+ checkPropTypes({params: getPhotosParamChecker}, {params}, 'params', 'CameraRoll.getPhotos');
}
if (arguments.length > 1) {
console.warn('CameraRoll.getPhotos(tag, success, error) is deprecated. Use the returned Promise instead');
@@ -221,7 +223,8 @@ class CameraRoll {
if (__DEV__) {
const callback = arguments[1];
successCallback = (response) => {
- getPhotosReturnChecker(
+ checkPropTypes(
+ {response: getPhotosReturnChecker},
{response},
'response',
'CameraRoll.getPhotos callback'
diff --git a/Libraries/LayoutAnimation/LayoutAnimation.js b/Libraries/LayoutAnimation/LayoutAnimation.js
index 61d62601d71..a6670cab2f2 100644
--- a/Libraries/LayoutAnimation/LayoutAnimation.js
+++ b/Libraries/LayoutAnimation/LayoutAnimation.js
@@ -11,12 +11,13 @@
*/
'use strict';
-var {PropTypes} = require('React');
var UIManager = require('UIManager');
-var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
var keyMirror = require('fbjs/lib/keyMirror');
+// $FlowFixMe checkPropTypes not yet landed to Flow
+var {checkPropTypes, PropTypes} = require('react');
+
var TypesEnum = {
spring: true,
linear: true,
@@ -33,7 +34,7 @@ var PropertiesEnum = {
};
var Properties = keyMirror(PropertiesEnum);
-var animChecker = createStrictShapeTypeChecker({
+var animType = PropTypes.shape({
duration: PropTypes.number,
delay: PropTypes.number,
springDamping: PropTypes.number,
@@ -55,11 +56,11 @@ type Anim = {
property?: $Enum,
}
-var configChecker = createStrictShapeTypeChecker({
+var configType = PropTypes.shape({
duration: PropTypes.number.isRequired,
- create: animChecker,
- update: animChecker,
- delete: animChecker,
+ create: animType,
+ update: animType,
+ delete: animType,
});
type Config = {
@@ -69,9 +70,13 @@ type Config = {
delete?: Anim,
}
+function checkConfig(config: Config, location: string, name: string) {
+ checkPropTypes({config: configType}, {config}, location, name);
+}
+
function configureNext(config: Config, onAnimationDidEnd?: Function) {
if (__DEV__) {
- configChecker({config}, 'config', 'LayoutAnimation.configureNext');
+ checkConfig(config, 'config', 'LayoutAnimation.configureNext');
}
UIManager.configureNextLayoutAnimation(
config, onAnimationDidEnd || function() {}, function() { /* unused */ }
@@ -151,7 +156,7 @@ var LayoutAnimation = {
create,
Types,
Properties,
- configChecker: configChecker,
+ checkConfig,
Presets,
easeInEaseOut: configureNext.bind(
null, Presets.easeInEaseOut