/** * Copyright 2004-present Facebook. All Rights Reserved. * * @providesModule CameraRollView */ 'use strict'; var React = require('react-native'); var { ActivityIndicatorIOS, CameraRoll, Image, ListView, ListViewDataSource, StyleSheet, View, } = React; var groupByEveryN = require('groupByEveryN'); var logError = require('logError'); var propTypes = { /** * The group where the photos will be fetched from. Possible * values are 'Album', 'All', 'Event', 'Faces', 'Library', 'PhotoStream' * and SavedPhotos. */ groupTypes: React.PropTypes.oneOf([ 'Album', 'All', 'Event', 'Faces', 'Library', 'PhotoStream', 'SavedPhotos', ]), /** * Number of images that will be fetched in one page. */ batchSize: React.PropTypes.number, /** * A function that takes a single image as a parameter and renders it. */ renderImage: React.PropTypes.func, /** * imagesPerRow: Number of images to be shown in each row. */ imagesPerRow: React.PropTypes.number, }; var CameraRollView = React.createClass({ propTypes: propTypes, getDefaultProps: function() { return { groupTypes: 'SavedPhotos', batchSize: 5, imagesPerRow: 1, renderImage: function(asset) { var imageSize = 150; var imageStyle = [styles.image, {width: imageSize, height: imageSize}]; return ( ); }, }; }, getInitialState: function() { var ds = new ListViewDataSource({rowHasChanged: this._rowHasChanged}); return { assets: [], groupTypes: this.props.groupTypes, lastCursor: null, noMore: false, loadingMore: false, dataSource: ds, }; }, /** * This should be called when the image renderer is changed to tell the * component to re-render its assets. */ rendererChanged: function() { var ds = new ListViewDataSource({rowHasChanged: this._rowHasChanged}); this.state.dataSource = ds.cloneWithRows( groupByEveryN(this.state.assets, this.props.imagesPerRow) ); }, componentDidMount: function() { this.fetch(); }, componentWillReceiveProps: function(nextProps) { if (this.props.groupTypes !== nextProps.groupTypes) { this.fetch(true); } }, _fetch: function(clear) { if (clear) { this.setState(this.getInitialState(), this.fetch); return; } var fetchParams = { first: this.props.batchSize, groupTypes: this.props.groupTypes, }; if (this.state.lastCursor) { fetchParams.after = this.state.lastCursor; } CameraRoll.getPhotos(fetchParams, this._appendAssets, logError); }, /** * Fetches more images from the camera roll. If clear is set to true, it will * set the component to its initial state and re-fetch the images. */ fetch: function(clear) { if (!this.state.loadingMore) { this.setState({loadingMore: true}, () => { this._fetch(clear); }); } }, render: function() { return ( ); }, _rowHasChanged: function(r1, r2) { if (r1.length !== r2.length) { return true; } for (var i = 0; i < r1.length; i++) { if (r1[i] !== r2[i]) { return true; } } return false; }, _renderFooterSpinner: function() { if (!this.state.noMore) { return ; } return null; }, // rowData is an array of images _renderRow: function(rowData, sectionID, rowID) { var images = rowData.map((image) => { if (image === null) { return null; } return this.props.renderImage(image); }); return ( {images} ); }, _appendAssets: function(data) { var assets = data.edges; var newState = { loadingMore: false }; if (!data.page_info.has_next_page) { newState.noMore = true; } if (assets.length > 0) { newState.lastCursor = data.page_info.end_cursor; newState.assets = this.state.assets.concat(assets); newState.dataSource = this.state.dataSource.cloneWithRows( groupByEveryN(newState.assets, this.props.imagesPerRow) ); } this.setState(newState); }, _onEndReached: function() { if (!this.state.noMore) { this.fetch(); } }, }); var styles = StyleSheet.create({ row: { flexDirection: 'row', flex: 1, }, url: { fontSize: 9, marginBottom: 14, }, image: { margin: 4, }, info: { flex: 1, }, container: { flex: 1, }, }); module.exports = CameraRollView;