Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
kfiroo authored Sep 13, 2017
2 parents 6c70ef8 + e335aba commit ed09225
Show file tree
Hide file tree
Showing 36 changed files with 7,948 additions and 1,309 deletions.
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["react-native"]
}
222 changes: 105 additions & 117 deletions CachedImage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
const _ = require('lodash');
const React = require('react');
const ReactNative = require('react-native');

const PropTypes = require('prop-types');

const ImageCacheManagerOptionsPropTypes = require('./ImageCacheManagerOptionsPropTypes');

const flattenStyle = ReactNative.StyleSheet.flatten;
const ImageCacheProvider = require('./ImageCacheProvider');

const ImageCacheManager = require('./ImageCacheManager');

const {
View,
Image,
ImageBackground,
ActivityIndicator,
NetInfo,
Platform
} = ReactNative;


const {
StyleSheet
Platform,
StyleSheet,
} = ReactNative;

const styles = StyleSheet.create({
Expand All @@ -39,51 +41,41 @@ function getImageProps(props) {

const CACHED_IMAGE_REF = 'cachedImage';

const CachedImage = React.createClass({
propTypes: {
renderImage: React.PropTypes.func.isRequired,
activityIndicatorProps: React.PropTypes.object.isRequired,
useQueryParamsInCacheKey: React.PropTypes.oneOfType([
React.PropTypes.bool,
React.PropTypes.array
]).isRequired,
resolveHeaders: React.PropTypes.func,
cacheLocation: React.PropTypes.string
},
class CachedImage extends React.Component {

static propTypes = {
renderImage: PropTypes.func.isRequired,
activityIndicatorProps: PropTypes.object.isRequired,

getDefaultProps() {
return {
renderImage: props => (<Image ref={CACHED_IMAGE_REF} {...props}/>),
// ImageCacheManager options
...ImageCacheManagerOptionsPropTypes,
};

static defaultProps = {
renderImage: props => (<ImageBackground imageStyle={props.style} ref={CACHED_IMAGE_REF} {...props} />),
activityIndicatorProps: {},
useQueryParamsInCacheKey: false,
resolveHeaders: () => Promise.resolve({}),
cacheLocation: ImageCacheProvider.LOCATION.CACHE
};
},
};

setNativeProps(nativeProps) {
try {
this.refs[CACHED_IMAGE_REF].setNativeProps(nativeProps);
} catch (e) {
console.error(e);
}
},
static contextTypes = {
getImageCacheManager: PropTypes.func,
};

getInitialState() {
constructor(props) {
super(props);
this._isMounted = false;
return {
isCacheable: false,
this.state = {
isCacheable: true,
cachedImagePath: null,
networkAvailable: true
};
},

safeSetState(newState) {
if (!this._isMounted) {
return;
}
return this.setState(newState);
},
this.getImageCacheManagerOptions = this.getImageCacheManagerOptions.bind(this);
this.getImageCacheManager = this.getImageCacheManager.bind(this);
this.safeSetState = this.safeSetState.bind(this);
this.handleConnectivityChange = this.handleConnectivityChange.bind(this);
this.processSource = this.processSource.bind(this);
this.renderLoader = this.renderLoader.bind(this);
}

componentWillMount() {
this._isMounted = true;
Expand All @@ -97,54 +89,73 @@ const CachedImage = React.createClass({
});

this.processSource(this.props.source);
},
}

componentWillUnmount() {
this._isMounted = false;
NetInfo.isConnected.removeEventListener('connectionChange', this.handleConnectivityChange);
},
}

componentWillReceiveProps(nextProps) {
if (!_.isEqual(this.props.source, nextProps.source)) {
this.processSource(nextProps.source);
}
},
}

setNativeProps(nativeProps) {
try {
this.refs[CACHED_IMAGE_REF].setNativeProps(nativeProps);
} catch (e) {
console.error(e);
}
}

getImageCacheManagerOptions() {
return _.pick(this.props, _.keys(ImageCacheManagerOptionsPropTypes));
}

getImageCacheManager() {
// try to get ImageCacheManager from context
if (this.context && this.context.getImageCacheManager) {
return this.context.getImageCacheManager();
}
// create a new one if context is not available
const options = this.getImageCacheManagerOptions();
return ImageCacheManager(options);
}

safeSetState(newState) {
if (!this._isMounted) {
return;
}
return this.setState(newState);
}

handleConnectivityChange(isConnected) {
this.safeSetState({
networkAvailable: isConnected
});
},
}

processSource(source) {
const url = _.get(source, ['uri'], null);
if (ImageCacheProvider.isCacheable(url)) {
const options = _.pick(this.props, ['useQueryParamsInCacheKey', 'cacheGroup', 'cacheLocation']);

// try to get the image path from cache
ImageCacheProvider.getCachedImagePath(url, options)
// try to put the image in cache if
.catch(() => ImageCacheProvider.cacheImage(url, options, this.props.resolveHeaders))
.then(cachedImagePath => {
this.safeSetState({
cachedImagePath
});
})
.catch(err => {
this.safeSetState({
cachedImagePath: null,
isCacheable: false
});
const options = this.getImageCacheManagerOptions();
const imageCacheManager = this.getImageCacheManager();

imageCacheManager.downloadAndCacheUrl(url, options)
.then(cachedImagePath => {
this.safeSetState({
cachedImagePath
});
})
.catch(err => {
// console.warn(err);
this.safeSetState({
cachedImagePath: null,
isCacheable: false
});
this.safeSetState({
isCacheable: true
});
} else {
this.safeSetState({
isCacheable: false
});
}
},
}

render() {
if (this.state.isCacheable && !this.state.cachedImagePath) {
Expand All @@ -153,23 +164,23 @@ const CachedImage = React.createClass({
const props = getImageProps(this.props);
const style = this.props.style || styles.image;
const source = (this.state.isCacheable && this.state.cachedImagePath) ? {
uri: 'file://' + this.state.cachedImagePath
} : this.props.source;
uri: 'file://' + this.state.cachedImagePath
} : this.props.source;
if (this.props.fallbackSource && !this.state.cachedImagePath) {
return this.props.renderImage({
...props,
key: `${props.key || source.uri}error`,
style,
source: this.props.fallbackSource
});
return this.props.renderImage({
...props,
key: `${props.key || source.uri}error`,
style,
source: this.props.fallbackSource
});
}
return this.props.renderImage({
...props,
key: props.key || source.uri,
style,
source
});
},
}

renderLoader() {
const imageProps = getImageProps(this.props);
Expand All @@ -186,11 +197,11 @@ const CachedImage = React.createClass({
// so we only show the ActivityIndicator
if (!source || (Platform.OS === 'android' && flattenStyle(imageStyle).borderRadius)) {
if (LoadingIndicator) {
return (
<View style={[imageStyle, activityIndicatorStyle]}>
<LoadingIndicator {...activityIndicatorProps} />
</View>
);
return (
<View style={[imageStyle, activityIndicatorStyle]}>
<LoadingIndicator {...activityIndicatorProps} />
</View>
);
}
return (
<ActivityIndicator
Expand All @@ -206,39 +217,16 @@ const CachedImage = React.createClass({
source,
children: (
LoadingIndicator
? <View style={[imageStyle, activityIndicatorStyle]}>
<LoadingIndicator {...activityIndicatorProps} />
</View>
: <ActivityIndicator
{...activityIndicatorProps}
style={activityIndicatorStyle}/>
? <View style={[imageStyle, activityIndicatorStyle]}>
<LoadingIndicator {...activityIndicatorProps} />
</View>
: <ActivityIndicator
{...activityIndicatorProps}
style={activityIndicatorStyle}/>
)
});
}
});

/**
* Same as ReactNaive.Image.getSize only it will not download the image if it has a cached version
* @param uri
* @param success
* @param failure
* @param options
*/
CachedImage.getSize = function getSize(uri, success, failure, options) {
if (ImageCacheProvider.isCacheable(uri)) {
ImageCacheProvider.getCachedImagePath(uri, options)
.then(imagePath => {
if (Platform.OS === 'android') {
imagePath = 'file://' + imagePath;
}
Image.getSize(imagePath, success, failure);
})
.catch(err => {
Image.getSize(uri, success, failure);
});
} else {
Image.getSize(uri, success, failure);
}
};
}

module.exports = CachedImage;
4 changes: 2 additions & 2 deletions CachedImageExample/.babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"presets": ["react-native"]
}
"presets": ["react-native"]
}
10 changes: 7 additions & 3 deletions CachedImageExample/.flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ node_modules/react-native/flow
flow/

[options]
emoji=true

module.system=haste

experimental.strict_type_args=true
Expand All @@ -35,11 +37,13 @@ suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FixMe

suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-5]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-5]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-7]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-7]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+

suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError

unsafe.enable_getters_and_setters=true

[version]
^0.35.0
^0.47.0
1 change: 1 addition & 0 deletions CachedImageExample/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ local.properties
#
node_modules/
npm-debug.log
yarn-error.log

# BUCK
buck-out/
Expand Down
Loading

0 comments on commit ed09225

Please sign in to comment.