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