Skip to content

Commit 50fbb5b

Browse files
authored
Merge branch 'master' into master
2 parents cfc8e60 + c984ff6 commit 50fbb5b

File tree

4 files changed

+46
-11
lines changed

4 files changed

+46
-11
lines changed

CachedImage.js

+29-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const flattenStyle = ReactNative.StyleSheet.flatten;
77
const ImageCacheProvider = require('./ImageCacheProvider');
88

99
const {
10+
View,
1011
Image,
1112
ActivityIndicator,
1213
NetInfo,
@@ -33,7 +34,7 @@ const styles = StyleSheet.create({
3334
});
3435

3536
function getImageProps(props) {
36-
return _.omit(props, ['source', 'defaultSource', 'activityIndicatorProps', 'style', 'useQueryParamsInCacheKey', 'renderImage', 'resolveHeaders']);
37+
return _.omit(props, ['source', 'defaultSource', 'fallbackSource', 'LoadingIndicator', 'activityIndicatorProps', 'style', 'useQueryParamsInCacheKey', 'renderImage', 'resolveHeaders']);
3738
}
3839

3940
const CACHED_IMAGE_REF = 'cachedImage';
@@ -154,8 +155,17 @@ const CachedImage = React.createClass({
154155
const source = (this.state.isCacheable && this.state.cachedImagePath) ? {
155156
uri: 'file://' + this.state.cachedImagePath
156157
} : this.props.source;
158+
if (this.props.fallbackSource && !this.state.cachedImagePath) {
159+
return this.props.renderImage({
160+
...props,
161+
key: `${props.key || source.uri}error`,
162+
style,
163+
source: this.props.fallbackSource
164+
});
165+
}
157166
return this.props.renderImage({
158167
...props,
168+
key: props.key || source.uri,
159169
style,
160170
source
161171
});
@@ -168,11 +178,20 @@ const CachedImage = React.createClass({
168178
const activityIndicatorProps = _.omit(this.props.activityIndicatorProps, ['style']);
169179
const activityIndicatorStyle = this.props.activityIndicatorProps.style || styles.loader;
170180

181+
const LoadingIndicator = this.props.loadingIndicator;
182+
171183
const source = this.props.defaultSource;
172184

173185
// if the imageStyle has borderRadius it will break the loading image view on android
174186
// so we only show the ActivityIndicator
175-
if (Platform.OS === 'android' && flattenStyle(imageStyle).borderRadius) {
187+
if (!source || (Platform.OS === 'android' && flattenStyle(imageStyle).borderRadius)) {
188+
if (LoadingIndicator) {
189+
return (
190+
<View style={[imageStyle, activityIndicatorStyle]}>
191+
<LoadingIndicator {...activityIndicatorProps} />
192+
</View>
193+
);
194+
}
176195
return (
177196
<ActivityIndicator
178197
{...activityIndicatorProps}
@@ -183,11 +202,16 @@ const CachedImage = React.createClass({
183202
return this.props.renderImage({
184203
...imageProps,
185204
style: imageStyle,
205+
key: source.uri,
186206
source,
187207
children: (
188-
<ActivityIndicator
189-
{...activityIndicatorProps}
190-
style={activityIndicatorStyle}/>
208+
LoadingIndicator
209+
? <View style={[imageStyle, activityIndicatorStyle]}>
210+
<LoadingIndicator {...activityIndicatorProps} />
211+
</View>
212+
: <ActivityIndicator
213+
{...activityIndicatorProps}
214+
style={activityIndicatorStyle}/>
191215
)
192216
});
193217
}

ImageCacheProvider.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -130,19 +130,23 @@ function ensurePath(dirPath) {
130130
function downloadImage(fromUrl, toFile, headers = {}) {
131131
// use toFile as the key as is was created using the cacheKey
132132
if (!_.has(activeDownloads, toFile)) {
133+
//Using a temporary file, if the download is accidentally interrupted, it will not produce a disabled file
134+
const tmpFile = toFile + '.tmp';
133135
// create an active download for this file
134136
activeDownloads[toFile] = new Promise((resolve, reject) => {
135137
RNFetchBlob
136-
.config({path: toFile})
138+
.config({path: tmpFile})
137139
.fetch('GET', fromUrl, headers)
138140
.then(res => {
139141
if (Math.floor(res.respInfo.status / 100) !== 2) {
140142
throw new Error('Failed to successfully download image');
141143
}
142-
resolve(toFile);
144+
//The download is complete and rename the temporary file
145+
return fs.mv(tmpFile, toFile);
143146
})
147+
.then(() => resolve(toFile))
144148
.catch(err => {
145-
return deleteFile(toFile)
149+
return deleteFile(tmpFile)
146150
.then(() => reject(err));
147151
})
148152
.finally(() => {
@@ -346,6 +350,7 @@ function getCacheInfo(cacheLocation) {
346350

347351
module.exports = {
348352
isCacheable,
353+
getCachedImageFilePath,
349354
getCachedImagePath,
350355
cacheImage,
351356
deleteCachedImage,

README.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ We use [`react-native-fetch-blob`](https://github.com/wkh237/react-native-fetch-
1717
_You should only have to do this once._
1818

1919
react-native link react-native-fetch-blob
20-
20+
2121
Or, if you want to add Android permissions to AndroidManifest.xml automatically, use this one:
2222

2323
RNFB_ANDROID_PERMISSIONS=true react-native link react-native-fetch-blob
@@ -51,6 +51,9 @@ When providing `source={{uri: 'https://example.com/path/to/remote/image.jpg'}}`
5151
* `defaultSource` - prop to display a background image while the source image is downloaded. This will work even in android, but will not display background image if there you set borderRadius on this component style prop
5252
* `resolveHeaders` - _function_ when provided, the returned object will be used as the headers object when sending the request to download the image. **(default: () => Promise.resolve({}))**
5353
* `cacheLocation` - _string_ allows changing the root directory to use for caching. The default directory is sufficient for most use-cases. Images in this directory may be purged by Android automatically to free up space. Use `ImageCacheProvider.LOCATION.BUNDLE` if the cached images are critical (you will have to manage cleanup manually). **(default: ImageCacheProvider.LOCATION.CACHE)**
54+
* `loadingIndicator` - _component_ prop to set custom `ActivityIndicator`.
55+
* `fallbackSource` - prop to set placeholder image. when `source.uri` is null or cached failed, the `fallbackSource` will be display.
56+
5457

5558
### ImageCacheProvider
5659
`ImageCacheProvider` exposes interaction with the cache layer that is used by `CachedImage` so you can use it to prefetch some urls in the background while you app is starting,
@@ -109,7 +112,10 @@ Deletes the underlying cached image for a given url.
109112
Cache a list of urls, if any of the urls is already cached will not try to download again.
110113

111114
#### `ImageCacheProvider.deleteMultipleCachedImages(urls: string[], options: CacheOptions): Promise`
112-
Deletes all images from cache that were cached using the given urls, if file doesn't exist do nothing
115+
Deletes all images from cache that were cached using the given urls, if file doesn't exist do nothing.
116+
117+
### `ImageCacheProvider.clearCache(): Promise`
118+
Deletes all cached images.
113119

114120
#### Dependencies
115121
- [lodash](https://github.com/lodash/lodash) for props handling

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-cached-image",
3-
"version": "1.3.3",
3+
"version": "1.3.4",
44
"description": "CachedImage component for react-native",
55
"main": "index.js",
66
"scripts": {

0 commit comments

Comments
 (0)