1
+ import PropTypes from 'prop-types' ;
1
2
import React from 'react' ;
2
3
import { Image , ActivityIndicator , NetInfo , Platform } from 'react-native' ;
3
4
import RNFS , { DocumentDirectoryPath } from 'react-native-fs' ;
@@ -9,39 +10,50 @@ const URL = require('url-parse');
9
10
export default
10
11
class CacheableImage extends React . Component {
11
12
12
- constructor ( props ) {
13
- super ( props )
14
- this . imageDownloadBegin = this . imageDownloadBegin . bind ( this ) ;
15
- this . imageDownloadProgress = this . imageDownloadProgress . bind ( this ) ;
16
- this . _handleConnectivityChange = this . _handleConnectivityChange . bind ( this ) ;
17
- this . _stopDownload = this . _stopDownload . bind ( this ) ;
18
-
19
- this . state = {
20
- isRemote : false ,
21
- cachedImagePath : null ,
22
- cacheable : true
23
- } ;
13
+ static propTypes = {
14
+ activityIndicatorProps : PropTypes . object ,
15
+ defaultSource : Image . propTypes . source ,
16
+ useQueryParamsInCacheKey : PropTypes . oneOfType ( [
17
+ PropTypes . bool ,
18
+ PropTypes . array
19
+ ] ) ,
20
+ checkNetwork : PropTypes . bool ,
21
+ networkAvailable : PropTypes . bool ,
22
+ downloadInBackground : PropTypes . bool ,
23
+ storagePermissionGranted : PropTypes . bool
24
+ }
24
25
25
- this . networkAvailable = props . networkAvailable ;
26
- this . downloading = false ;
27
- this . jobId = null ;
28
- } ;
26
+ static defaultProps = {
27
+ style : { backgroundColor : 'transparent' } ,
28
+ activityIndicatorProps : {
29
+ style : { backgroundColor : 'transparent' , flex : 1 }
30
+ } ,
31
+ useQueryParamsInCacheKey : false , // bc
32
+ checkNetwork : true ,
33
+ networkAvailable : false ,
34
+ downloadInBackground : ( Platform . OS === 'ios' ) ? false : true ,
35
+ storagePermissionGranted : true
36
+ }
29
37
30
- componentWillReceiveProps ( nextProps ) {
31
- if ( nextProps . source != this . props . source || nextProps . networkAvailable != this . networkAvailable ) {
32
- this . networkAvailable = nextProps . networkAvailable ;
33
- this . _processSource ( nextProps . source ) ;
34
- }
38
+ state = {
39
+ isRemote : false ,
40
+ cachedImagePath : null ,
41
+ cacheable : true
35
42
}
36
43
37
- shouldComponentUpdate ( nextProps , nextState ) {
38
- if ( nextState === this . state && nextProps === this . props ) {
39
- return false ;
44
+ networkAvailable = this . props . networkAvailable
45
+
46
+ downloading = false
47
+
48
+ jobId = null
49
+
50
+ setNativeProps ( nativeProps ) {
51
+ if ( this . _imageComponent ) {
52
+ this . _imageComponent . setNativeProps ( nativeProps ) ;
40
53
}
41
- return true ;
42
54
}
43
-
44
- async imageDownloadBegin ( info ) {
55
+
56
+ imageDownloadBegin = info => {
45
57
switch ( info . statusCode ) {
46
58
case 404 :
47
59
case 403 :
@@ -52,14 +64,14 @@ class CacheableImage extends React.Component {
52
64
}
53
65
}
54
66
55
- async imageDownloadProgress ( info ) {
67
+ imageDownloadProgress = info => {
56
68
if ( ( info . contentLength / info . bytesWritten ) == 1 ) {
57
69
this . downloading = false ;
58
70
this . jobId = null ;
59
71
}
60
72
}
61
73
62
- async checkImageCache ( imageUri , cachePath , cacheKey ) {
74
+ checkImageCache = ( imageUri , cachePath , cacheKey ) => {
63
75
const dirPath = DocumentDirectoryPath + '/' + cachePath ;
64
76
const filePath = dirPath + '/' + cacheKey ;
65
77
@@ -154,7 +166,7 @@ class CacheableImage extends React.Component {
154
166
} ) ;
155
167
}
156
168
157
- _deleteFilePath ( filePath ) {
169
+ _deleteFilePath = ( filePath ) => {
158
170
RNFS
159
171
. exists ( filePath )
160
172
. then ( ( res ) => {
@@ -166,9 +178,10 @@ class CacheableImage extends React.Component {
166
178
} ) ;
167
179
}
168
180
169
- _processSource ( source , skipSourceCheck ) {
181
+ _processSource = ( source , skipSourceCheck ) => {
170
182
171
- if ( source !== null
183
+ if ( this . props . storagePermissionGranted
184
+ && source !== null
172
185
&& source != ''
173
186
&& typeof source === "object"
174
187
&& source . hasOwnProperty ( 'uri' )
@@ -210,17 +223,38 @@ class CacheableImage extends React.Component {
210
223
}
211
224
}
212
225
213
- _stopDownload ( ) {
226
+ _stopDownload = ( ) => {
214
227
if ( ! this . jobId ) return ;
215
228
216
229
this . downloading = false ;
217
230
RNFS . stopDownload ( this . jobId ) ;
218
231
this . jobId = null ;
219
232
}
220
233
234
+ _handleConnectivityChange = isConnected => {
235
+ this . networkAvailable = isConnected ;
236
+ if ( this . networkAvailable && this . state . isRemote && ! this . state . cachedImagePath ) {
237
+ this . _processSource ( this . props . source ) ;
238
+ }
239
+ }
240
+
241
+ componentWillReceiveProps ( nextProps ) {
242
+ if ( nextProps . source != this . props . source || nextProps . networkAvailable != this . networkAvailable ) {
243
+ this . networkAvailable = nextProps . networkAvailable ;
244
+ this . _processSource ( nextProps . source ) ;
245
+ }
246
+ }
247
+
248
+ shouldComponentUpdate ( nextProps , nextState ) {
249
+ if ( nextState === this . state && nextProps === this . props ) {
250
+ return false ;
251
+ }
252
+ return true ;
253
+ }
254
+
221
255
componentWillMount ( ) {
222
256
if ( this . props . checkNetwork ) {
223
- NetInfo . isConnected . addEventListener ( 'change ' , this . _handleConnectivityChange ) ;
257
+ NetInfo . isConnected . addEventListener ( 'connectionChange ' , this . _handleConnectivityChange ) ;
224
258
// componentWillUnmount unsets this._handleConnectivityChange in case the component unmounts before this fetch resolves
225
259
NetInfo . isConnected . fetch ( ) . done ( this . _handleConnectivityChange ) ;
226
260
}
@@ -230,21 +264,17 @@ class CacheableImage extends React.Component {
230
264
231
265
componentWillUnmount ( ) {
232
266
if ( this . props . checkNetwork ) {
233
- NetInfo . isConnected . removeEventListener ( 'change ' , this . _handleConnectivityChange ) ;
267
+ NetInfo . isConnected . removeEventListener ( 'connectionChange ' , this . _handleConnectivityChange ) ;
234
268
this . _handleConnectivityChange = null ;
235
269
}
236
270
237
271
if ( this . downloading && this . jobId ) {
238
272
this . _stopDownload ( ) ;
239
273
}
240
274
}
241
-
242
- async _handleConnectivityChange ( isConnected ) {
243
- this . networkAvailable = isConnected ;
244
- } ;
245
-
275
+
246
276
render ( ) {
247
- if ( ! this . state . isRemote && ! this . props . defaultSource ) {
277
+ if ( ( ! this . state . isRemote && ! this . props . defaultSource ) || ! this . props . storagePermissionGranted ) {
248
278
return this . renderLocal ( ) ;
249
279
}
250
280
@@ -256,15 +286,17 @@ class CacheableImage extends React.Component {
256
286
return this . renderDefaultSource ( ) ;
257
287
}
258
288
289
+ const { children, defaultSource, checkNetwork, networkAvailable, downloadInBackground, activityIndicatorProps, ...props } = this . props ;
290
+ const style = [ activityIndicatorProps . style , this . props . style ] ;
259
291
return (
260
- < ActivityIndicator { ...this . props . activityIndicatorProps } />
292
+ < ActivityIndicator { ...props } { ... activityIndicatorProps } style = { style } />
261
293
) ;
262
294
}
263
295
264
296
renderCache ( ) {
265
297
const { children, defaultSource, checkNetwork, networkAvailable, downloadInBackground, activityIndicatorProps, ...props } = this . props ;
266
298
return (
267
- < ResponsiveImage { ...props } source = { { uri : 'file://' + this . state . cachedImagePath } } >
299
+ < ResponsiveImage { ...props } source = { { uri : 'file://' + this . state . cachedImagePath } } ref = { component => this . _imageComponent = component } >
268
300
{ children }
269
301
</ ResponsiveImage >
270
302
) ;
@@ -273,7 +305,7 @@ class CacheableImage extends React.Component {
273
305
renderLocal ( ) {
274
306
const { children, defaultSource, checkNetwork, networkAvailable, downloadInBackground, activityIndicatorProps, ...props } = this . props ;
275
307
return (
276
- < ResponsiveImage { ...props } >
308
+ < ResponsiveImage { ...props } ref = { component => this . _imageComponent = component } >
277
309
{ children }
278
310
</ ResponsiveImage >
279
311
) ;
@@ -282,32 +314,9 @@ class CacheableImage extends React.Component {
282
314
renderDefaultSource ( ) {
283
315
const { children, defaultSource, checkNetwork, networkAvailable, ...props } = this . props ;
284
316
return (
285
- < CacheableImage { ...props } source = { defaultSource } checkNetwork = { false } networkAvailable = { this . networkAvailable } >
317
+ < CacheableImage { ...props } source = { defaultSource } checkNetwork = { false } networkAvailable = { this . networkAvailable } ref = { component => this . _imageComponent = component } >
286
318
{ children }
287
319
</ CacheableImage >
288
320
) ;
289
321
}
290
322
}
291
-
292
- CacheableImage . propTypes = {
293
- activityIndicatorProps : React . PropTypes . object ,
294
- defaultSource : Image . propTypes . source ,
295
- useQueryParamsInCacheKey : React . PropTypes . oneOfType ( [
296
- React . PropTypes . bool ,
297
- React . PropTypes . array
298
- ] ) ,
299
- checkNetwork : React . PropTypes . bool ,
300
- networkAvailable : React . PropTypes . bool ,
301
- downloadInBackground : React . PropTypes . bool
302
- } ;
303
-
304
- CacheableImage . defaultProps = {
305
- style : { backgroundColor : 'transparent' } ,
306
- activityIndicatorProps : {
307
- style : { backgroundColor : 'transparent' , flex : 1 }
308
- } ,
309
- useQueryParamsInCacheKey : false , // bc
310
- checkNetwork : true ,
311
- networkAvailable : false ,
312
- downloadInBackground : ( Platform . OS === 'ios' ) ? false : true
313
- } ;
0 commit comments