2019-03-02 17:01:34 +08:00
|
|
|
/**
|
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
*
|
|
|
|
* @format
|
|
|
|
*/
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const React = require('react');
|
|
|
|
const ReactNative = require('react-native');
|
|
|
|
const {
|
|
|
|
ActivityIndicator,
|
|
|
|
Alert,
|
|
|
|
Image,
|
|
|
|
FlatList,
|
|
|
|
PermissionsAndroid,
|
|
|
|
Platform,
|
|
|
|
StyleSheet,
|
|
|
|
View,
|
|
|
|
} = ReactNative;
|
|
|
|
|
2019-03-03 18:54:13 +08:00
|
|
|
import CameraRoll from '../../js/CameraRoll';
|
|
|
|
|
2019-09-22 13:38:56 +02:00
|
|
|
const groupByEveryN = function groupByEveryN(num) {
|
|
|
|
const n = num;
|
|
|
|
return arrayArg => {
|
|
|
|
const array = [...arrayArg];
|
|
|
|
const result = [];
|
|
|
|
while (array.length > 0) {
|
|
|
|
const groupByNumber = array.length >= n ? n : array.length;
|
|
|
|
result.push(array.splice(0, groupByNumber));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
const logError = console.error;
|
2019-03-02 17:01:34 +08:00
|
|
|
|
2019-09-22 14:34:14 +02:00
|
|
|
class CameraRollView extends React.Component {
|
2019-03-02 17:01:34 +08:00
|
|
|
static defaultProps = {
|
2019-04-01 13:56:44 -07:00
|
|
|
groupTypes: 'All',
|
2019-03-02 17:01:34 +08:00
|
|
|
batchSize: 5,
|
|
|
|
imagesPerRow: 1,
|
|
|
|
assetType: 'Photos',
|
2019-09-22 14:34:14 +02:00
|
|
|
renderImage: function(asset) {
|
2019-03-02 17:01:34 +08:00
|
|
|
const imageSize = 150;
|
|
|
|
const imageStyle = [styles.image, {width: imageSize, height: imageSize}];
|
|
|
|
return <Image source={asset.node.image} style={imageStyle} />;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
state = this.getInitialState();
|
|
|
|
|
|
|
|
getInitialState() {
|
|
|
|
return {
|
|
|
|
assets: [],
|
|
|
|
data: [],
|
|
|
|
seen: new Set(),
|
|
|
|
lastCursor: null,
|
|
|
|
noMore: false,
|
|
|
|
loadingMore: false,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
this.fetch();
|
|
|
|
}
|
|
|
|
|
2019-09-22 14:34:14 +02:00
|
|
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
2019-03-02 17:01:34 +08:00
|
|
|
if (this.props.groupTypes !== nextProps.groupTypes) {
|
|
|
|
this.fetch(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-22 14:34:14 +02:00
|
|
|
async _fetch(clear) {
|
2019-03-02 17:01:34 +08:00
|
|
|
if (clear) {
|
|
|
|
this.setState(this.getInitialState(), this.fetch);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Platform.OS === 'android') {
|
|
|
|
const result = await PermissionsAndroid.request(
|
|
|
|
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
|
|
|
|
{
|
|
|
|
title: 'Permission Explanation',
|
|
|
|
message: 'RNTester would like to access your pictures.',
|
|
|
|
},
|
|
|
|
);
|
|
|
|
if (result !== 'granted') {
|
|
|
|
Alert.alert('Access to pictures was denied.');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-22 13:38:56 +02:00
|
|
|
const fetchParams = {
|
2019-03-02 17:01:34 +08:00
|
|
|
first: this.props.batchSize,
|
|
|
|
groupTypes: this.props.groupTypes,
|
|
|
|
assetType: this.props.assetType,
|
|
|
|
};
|
|
|
|
if (Platform.OS === 'android') {
|
|
|
|
// not supported in android
|
|
|
|
delete fetchParams.groupTypes;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.state.lastCursor) {
|
|
|
|
fetchParams.after = this.state.lastCursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const data = await CameraRoll.getPhotos(fetchParams);
|
|
|
|
this._appendAssets(data);
|
|
|
|
} catch (e) {
|
|
|
|
logError(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2019-09-22 14:34:14 +02:00
|
|
|
fetch = clear => {
|
2019-03-02 17:01:34 +08:00
|
|
|
if (!this.state.loadingMore) {
|
|
|
|
this.setState({loadingMore: true}, () => {
|
|
|
|
this._fetch(clear);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
2019-09-22 14:34:14 +02:00
|
|
|
console.log({data: this.state.data});
|
2019-03-02 17:01:34 +08:00
|
|
|
return (
|
|
|
|
<FlatList
|
|
|
|
keyExtractor={(_, idx) => String(idx)}
|
|
|
|
renderItem={this._renderItem}
|
|
|
|
ListFooterComponent={this._renderFooterSpinner}
|
|
|
|
onEndReached={this._onEndReached}
|
|
|
|
onEndReachedThreshold={0.2}
|
|
|
|
style={styles.container}
|
|
|
|
data={this.state.data || []}
|
|
|
|
extraData={this.props.bigImages + this.state.noMore}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderFooterSpinner = () => {
|
|
|
|
if (!this.state.noMore) {
|
|
|
|
return <ActivityIndicator />;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
2019-09-22 14:34:14 +02:00
|
|
|
_renderItem = ({item}) => {
|
|
|
|
console.log({item});
|
2019-03-02 17:01:34 +08:00
|
|
|
return (
|
|
|
|
<View style={styles.row}>
|
2019-09-22 14:34:14 +02:00
|
|
|
{item.map(image => (image ? this.props.renderImage(image) : null))}
|
2019-03-02 17:01:34 +08:00
|
|
|
</View>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2019-09-22 14:34:14 +02:00
|
|
|
_appendAssets(data) {
|
2019-03-02 17:01:34 +08:00
|
|
|
const assets = data.edges;
|
2019-09-22 14:34:14 +02:00
|
|
|
const newState = {loadingMore: false};
|
2019-03-02 17:01:34 +08:00
|
|
|
|
|
|
|
if (!data.page_info.has_next_page) {
|
|
|
|
newState.noMore = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (assets.length > 0) {
|
|
|
|
newState.lastCursor = data.page_info.end_cursor;
|
|
|
|
newState.seen = new Set(this.state.seen);
|
|
|
|
|
|
|
|
// Unique assets efficiently
|
|
|
|
// Checks new pages against seen objects
|
|
|
|
const uniqAssets = [];
|
|
|
|
for (let index = 0; index < assets.length; index++) {
|
|
|
|
const asset = assets[index];
|
|
|
|
let value = asset.node.image.uri;
|
|
|
|
if (newState.seen.has(value)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
newState.seen.add(value);
|
|
|
|
uniqAssets.push(asset);
|
|
|
|
}
|
|
|
|
|
|
|
|
newState.assets = this.state.assets.concat(uniqAssets);
|
2019-09-22 14:34:14 +02:00
|
|
|
newState.data = groupByEveryN(this.props.imagesPerRow)(newState.assets);
|
2019-03-02 17:01:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
this.setState(newState);
|
|
|
|
}
|
|
|
|
|
|
|
|
_onEndReached = () => {
|
|
|
|
if (!this.state.noMore) {
|
|
|
|
this.fetch();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const styles = StyleSheet.create({
|
|
|
|
row: {
|
|
|
|
flexDirection: 'row',
|
|
|
|
flex: 1,
|
|
|
|
},
|
|
|
|
image: {
|
|
|
|
margin: 4,
|
|
|
|
},
|
|
|
|
container: {
|
|
|
|
flex: 1,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
module.exports = CameraRollView;
|