react-native-fast-image 8.15.0 → 8.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageKeyedGlideUrl.java +37 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageSource.java +17 -3
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewConverter.java +4 -0
- package/dist/index.cjs.js.flow +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js.flow +1 -0
- package/ios/FastImage/FFFDownsampledImage.h +2 -2
- package/ios/FastImage/FFFDownsampledImage.m +4 -4
- package/ios/FastImage/FFFastImageSource.h +11 -0
- package/ios/FastImage/FFFastImageSource.m +25 -0
- package/ios/FastImage/FFFastImageView.m +4 -12
- package/ios/FastImage/FFFastImageViewManager.m +14 -3
- package/ios/FastImage/RCTConvert+FFFastImage.m +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -146,6 +146,23 @@ Indicates the load order priority of an image. Images with `FastImage.priority.h
|
|
|
146
146
|
|
|
147
147
|
---
|
|
148
148
|
|
|
149
|
+
### `source.cacheKey?: string`
|
|
150
|
+
|
|
151
|
+
The key the image is cached under, instead of its uri. Use it for urls that change while the image stays the same, e.g. signed urls with a token or an expiry. Use something that identifies the image, and change it when the image changes (e.g. include a version or the time it was updated), or the old image keeps showing:
|
|
152
|
+
|
|
153
|
+
```jsx
|
|
154
|
+
<FastImage
|
|
155
|
+
source={{
|
|
156
|
+
uri: signedUrl,
|
|
157
|
+
cacheKey: `avatar-${user.id}-${user.avatarUpdatedAt}`,
|
|
158
|
+
}}
|
|
159
|
+
/>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Not used with `cache: 'web'`, which follows the HTTP cache (keyed by url).
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
149
166
|
### `defaultSource?: number`
|
|
150
167
|
|
|
151
168
|
- An asset loaded with `require(...)`.
|
|
@@ -332,6 +349,8 @@ for (const result of results) {
|
|
|
332
349
|
}
|
|
333
350
|
```
|
|
334
351
|
|
|
352
|
+
Each source's `cache` applies, as for a view: with `web` the preload follows the HTTP cache, and with `cacheOnly` it doesn't download. A `cacheOnly` preload resolves `ok` only if the image is cached, and loads it from the disk cache into memory, so a view shows it at once.
|
|
353
|
+
|
|
335
354
|
### `FastImage.clearMemoryCache: () => Promise<void>`
|
|
336
355
|
|
|
337
356
|
Clear all images from memory cache.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
package com.dylanvann.fastimage;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
|
|
6
|
+
import com.bumptech.glide.load.model.GlideUrl;
|
|
7
|
+
import com.bumptech.glide.load.model.Headers;
|
|
8
|
+
|
|
9
|
+
// A url cached under the source's `cacheKey` instead of the url. Glide keys
|
|
10
|
+
// its disk cache by getCacheKey(), and its memory cache by equals() and
|
|
11
|
+
// hashCode(), which also compare the headers: here they only use the key, so
|
|
12
|
+
// a url whose token or headers change still hits both caches. The request
|
|
13
|
+
// still uses the url and headers.
|
|
14
|
+
class FastImageKeyedGlideUrl extends GlideUrl {
|
|
15
|
+
private final String mCacheKey;
|
|
16
|
+
|
|
17
|
+
FastImageKeyedGlideUrl(String url, Headers headers, @NonNull String cacheKey) {
|
|
18
|
+
super(url, headers);
|
|
19
|
+
mCacheKey = cacheKey;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@Override
|
|
23
|
+
public String getCacheKey() {
|
|
24
|
+
return mCacheKey;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Override
|
|
28
|
+
public boolean equals(@Nullable Object other) {
|
|
29
|
+
return other instanceof FastImageKeyedGlideUrl
|
|
30
|
+
&& mCacheKey.equals(((FastImageKeyedGlideUrl) other).mCacheKey);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Override
|
|
34
|
+
public int hashCode() {
|
|
35
|
+
return mCacheKey.hashCode();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -124,9 +124,23 @@ public class FastImageSource extends ImageSource {
|
|
|
124
124
|
mWebCache = webCache;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
// `cacheKey`: the key to cache the image under instead of its url.
|
|
128
|
+
@Nullable
|
|
129
|
+
private String mCacheKey = null;
|
|
130
|
+
|
|
131
|
+
void setCacheKey(@Nullable String cacheKey) {
|
|
132
|
+
mCacheKey = cacheKey == null || cacheKey.isEmpty() ? null : cacheKey;
|
|
133
|
+
}
|
|
134
|
+
|
|
127
135
|
public GlideUrl getGlideUrl() {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
136
|
+
String url = getUri().toString();
|
|
137
|
+
if (mWebCache) {
|
|
138
|
+
// Follows the HTTP cache, which is keyed by url.
|
|
139
|
+
return new FastImageWebGlideUrl(url, getHeaders());
|
|
140
|
+
}
|
|
141
|
+
if (mCacheKey != null) {
|
|
142
|
+
return new FastImageKeyedGlideUrl(url, getHeaders(), mCacheKey);
|
|
143
|
+
}
|
|
144
|
+
return new GlideUrl(url, getHeaders());
|
|
131
145
|
}
|
|
132
146
|
}
|
|
@@ -19,6 +19,7 @@ import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
|
|
19
19
|
import com.facebook.react.bridge.NoSuchKeyException;
|
|
20
20
|
import com.facebook.react.bridge.ReadableMap;
|
|
21
21
|
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
|
22
|
+
import com.facebook.react.bridge.ReadableType;
|
|
22
23
|
|
|
23
24
|
import java.util.HashMap;
|
|
24
25
|
import java.util.Map;
|
|
@@ -63,6 +64,9 @@ class FastImageViewConverter {
|
|
|
63
64
|
if (source == null) return null;
|
|
64
65
|
FastImageSource imageSource = new FastImageSource(context, source.getString("uri"), getHeaders(source));
|
|
65
66
|
imageSource.setWebCache(getCacheControl(source) == FastImageCacheControl.WEB);
|
|
67
|
+
if (source.hasKey("cacheKey") && source.getType("cacheKey") == ReadableType.String) {
|
|
68
|
+
imageSource.setCacheKey(source.getString("cacheKey"));
|
|
69
|
+
}
|
|
66
70
|
return imageSource;
|
|
67
71
|
}
|
|
68
72
|
|
package/dist/index.cjs.js.flow
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,12 @@ export type Source = {
|
|
|
27
27
|
};
|
|
28
28
|
priority?: Priority;
|
|
29
29
|
cache?: Cache;
|
|
30
|
+
/**
|
|
31
|
+
* The key the image is cached under, instead of its uri. For urls that
|
|
32
|
+
* change while the image stays the same, e.g. signed urls with a token or
|
|
33
|
+
* an expiry: use something stable, like the image's id.
|
|
34
|
+
*/
|
|
35
|
+
cacheKey?: string;
|
|
30
36
|
};
|
|
31
37
|
export interface OnLoadEvent {
|
|
32
38
|
nativeEvent: {
|
package/dist/index.js.flow
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
+ (NSURL*) loadURLForURL: (NSURL*)url;
|
|
15
15
|
|
|
16
16
|
// Sets a load's context to decode the image for a box (in pixels) to cover
|
|
17
|
-
// or fit in.
|
|
18
|
-
+ (void) addToContext: (SDWebImageMutableContext*)context
|
|
17
|
+
// or fit in. `key` is the source's cache key (its url, or its cacheKey).
|
|
18
|
+
+ (void) addToContext: (SDWebImageMutableContext*)context forKey: (NSString*)key box: (CGSize)box cover: (BOOL)cover;
|
|
19
19
|
|
|
20
20
|
// The size of the full image (in points, like UIImage's size) that an image
|
|
21
21
|
// loaded this way was decoded from, for onLoad, or zero for other images.
|
|
@@ -100,11 +100,11 @@ static CGSize FFFPixelSize(NSData* data) {
|
|
|
100
100
|
return components.URL ?: url;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
+ (void) addToContext: (SDWebImageMutableContext*)context
|
|
103
|
+
+ (void) addToContext: (SDWebImageMutableContext*)context forKey: (NSString*)key box: (CGSize)box cover: (BOOL)cover {
|
|
104
104
|
context[SDWebImageContextAnimatedImageClass] = [FFFDownsampledImage class];
|
|
105
|
-
// Cached under the
|
|
106
|
-
// keeps one download for every size and for loads
|
|
107
|
-
|
|
105
|
+
// Cached under the source's own key (not the url from loadURLForURL:),
|
|
106
|
+
// so the disk cache keeps one download for every size and for loads
|
|
107
|
+
// that aren't downsampled.
|
|
108
108
|
context[SDWebImageContextCacheKeyFilter] = [SDWebImageCacheKeyFilter cacheKeyFilterWithBlock: ^NSString* (NSURL* _Nonnull loadURL) {
|
|
109
109
|
return key;
|
|
110
110
|
}];
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#import <Foundation/Foundation.h>
|
|
2
2
|
#import <UIKit/UIKit.h>
|
|
3
3
|
#import <SDWebImage/SDWebImageDownloaderRequestModifier.h>
|
|
4
|
+
#import <SDWebImage/SDWebImageCacheKeyFilter.h>
|
|
5
|
+
#import <SDWebImage/SDWebImageDefine.h>
|
|
4
6
|
|
|
5
7
|
typedef NS_ENUM(NSInteger, FFFPriority) {
|
|
6
8
|
FFFPriorityLow,
|
|
@@ -27,6 +29,8 @@ typedef NS_ENUM(NSInteger, FFFCacheControl) {
|
|
|
27
29
|
@property (nonatomic) NSDictionary *headers;
|
|
28
30
|
// cache control mode
|
|
29
31
|
@property (nonatomic) FFFCacheControl cacheControl;
|
|
32
|
+
// The key to cache the image under instead of its url, or nil.
|
|
33
|
+
@property (nonatomic, copy) NSString *cacheKey;
|
|
30
34
|
|
|
31
35
|
- (instancetype)initWithURL:(NSURL *)url
|
|
32
36
|
priority:(FFFPriority)priority
|
|
@@ -36,4 +40,11 @@ typedef NS_ENUM(NSInteger, FFFCacheControl) {
|
|
|
36
40
|
// Adds this source's headers to its image requests.
|
|
37
41
|
- (SDWebImageDownloaderRequestModifier *)requestModifier;
|
|
38
42
|
|
|
43
|
+
// Caches the image under cacheKey, or nil without one.
|
|
44
|
+
- (SDWebImageCacheKeyFilter *)cacheKeyFilter;
|
|
45
|
+
|
|
46
|
+
// The load options for `cache`: web follows the HTTP cache, cacheOnly never
|
|
47
|
+
// downloads. For views and preload alike.
|
|
48
|
+
- (SDWebImageOptions)cacheOptions;
|
|
49
|
+
|
|
39
50
|
@end
|
|
@@ -17,6 +17,31 @@
|
|
|
17
17
|
return self;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
- (SDWebImageCacheKeyFilter *)cacheKeyFilter
|
|
21
|
+
{
|
|
22
|
+
NSString* cacheKey = _cacheKey;
|
|
23
|
+
// `cache: 'web'` follows the HTTP cache, which is keyed by url.
|
|
24
|
+
if (cacheKey.length == 0 || _cacheControl == FFFCacheControlWeb) {
|
|
25
|
+
return nil;
|
|
26
|
+
}
|
|
27
|
+
return [SDWebImageCacheKeyFilter cacheKeyFilterWithBlock: ^NSString* _Nullable (NSURL* _Nonnull url) {
|
|
28
|
+
return cacheKey;
|
|
29
|
+
}];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
- (SDWebImageOptions)cacheOptions
|
|
33
|
+
{
|
|
34
|
+
switch (_cacheControl) {
|
|
35
|
+
case FFFCacheControlWeb:
|
|
36
|
+
return SDWebImageRefreshCached;
|
|
37
|
+
case FFFCacheControlCacheOnly:
|
|
38
|
+
return SDWebImageFromCacheOnly;
|
|
39
|
+
case FFFCacheControlImmutable:
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
20
45
|
- (SDWebImageDownloaderRequestModifier *)requestModifier
|
|
21
46
|
{
|
|
22
47
|
NSDictionary* headers = _headers;
|
|
@@ -500,17 +500,7 @@ NSString *FFFErrorMessage(NSError *error)
|
|
|
500
500
|
break;
|
|
501
501
|
}
|
|
502
502
|
|
|
503
|
-
|
|
504
|
-
case FFFCacheControlWeb:
|
|
505
|
-
options |= SDWebImageRefreshCached;
|
|
506
|
-
break;
|
|
507
|
-
case FFFCacheControlCacheOnly:
|
|
508
|
-
options |= SDWebImageFromCacheOnly;
|
|
509
|
-
break;
|
|
510
|
-
case FFFCacheControlImmutable:
|
|
511
|
-
break;
|
|
512
|
-
}
|
|
513
|
-
return options;
|
|
503
|
+
return options | [_source cacheOptions];
|
|
514
504
|
}
|
|
515
505
|
|
|
516
506
|
// Headers, and the size to decode at (see FFFDownsampledImage), which it
|
|
@@ -518,6 +508,7 @@ NSString *FFFErrorMessage(NSError *error)
|
|
|
518
508
|
- (SDWebImageContext*) loadContext {
|
|
519
509
|
SDWebImageMutableContext* context = [NSMutableDictionary dictionary];
|
|
520
510
|
context[SDWebImageContextDownloadRequestModifier] = _source.requestModifier;
|
|
511
|
+
context[SDWebImageContextCacheKeyFilter] = _source.cacheKeyFilter;
|
|
521
512
|
CGSize box = [self decodeBox];
|
|
522
513
|
self.decodedBox = box;
|
|
523
514
|
self.decodedCover = [self decodeCovers];
|
|
@@ -525,7 +516,8 @@ NSString *FFFErrorMessage(NSError *error)
|
|
|
525
516
|
context[SDWebImageContextAnimatedImageClass] = [SDAnimatedImage class];
|
|
526
517
|
return context;
|
|
527
518
|
}
|
|
528
|
-
|
|
519
|
+
NSString* key = _source.cacheKeyFilter ? _source.cacheKey : _source.url.absoluteString;
|
|
520
|
+
[FFFDownsampledImage addToContext: context forKey: key box: box cover: self.decodedCover];
|
|
529
521
|
return context;
|
|
530
522
|
}
|
|
531
523
|
|
|
@@ -37,6 +37,15 @@ RCT_REMAP_VIEW_PROPERTY(tintColor, imageColor, UIColor)
|
|
|
37
37
|
static NSMutableArray<dispatch_block_t> *FFFPendingPreloads;
|
|
38
38
|
static NSUInteger FFFPreloadsInFlight;
|
|
39
39
|
|
|
40
|
+
// A preload's context: the source's headers and cache key.
|
|
41
|
+
static SDWebImageMutableContext *FFFPreloadContext(FFFastImageSource *source)
|
|
42
|
+
{
|
|
43
|
+
SDWebImageMutableContext *context = [NSMutableDictionary dictionary];
|
|
44
|
+
context[SDWebImageContextDownloadRequestModifier] = source.requestModifier;
|
|
45
|
+
context[SDWebImageContextCacheKeyFilter] = source.cacheKeyFilter;
|
|
46
|
+
return context;
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
static NSUInteger FFFPreloadLimit(void)
|
|
41
50
|
{
|
|
42
51
|
NSUInteger limit = [SDWebImagePrefetcher sharedImagePrefetcher].maxConcurrentPrefetchCount;
|
|
@@ -80,8 +89,9 @@ RCT_EXPORT_METHOD(preload:(nonnull NSArray<FFFastImageSource *> *)sources
|
|
|
80
89
|
}
|
|
81
90
|
};
|
|
82
91
|
// With the prefetcher's options (low priority), but one source at a
|
|
83
|
-
// time (not SDWebImagePrefetcher), to get each source's result
|
|
84
|
-
// send its headers with its own request only
|
|
92
|
+
// time (not SDWebImagePrefetcher), to get each source's result, to
|
|
93
|
+
// send its headers with its own request only, and to follow its
|
|
94
|
+
// `cache` (#406).
|
|
85
95
|
SDWebImageOptions prefetcherOptions = [SDWebImagePrefetcher sharedImagePrefetcher].options;
|
|
86
96
|
|
|
87
97
|
[sources enumerateObjectsUsingBlock:^(FFFastImageSource * _Nonnull source, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
@@ -103,13 +113,14 @@ RCT_EXPORT_METHOD(preload:(nonnull NSArray<FFFastImageSource *> *)sources
|
|
|
103
113
|
options |= SDWebImageHighPriority;
|
|
104
114
|
}
|
|
105
115
|
}
|
|
116
|
+
options |= [source cacheOptions];
|
|
106
117
|
[FFFPendingPreloads addObject:[^{
|
|
107
118
|
// Once per slot: SDWebImage calls this once with finished set
|
|
108
119
|
// (a progressive load calls it more, without).
|
|
109
120
|
__block BOOL done = NO;
|
|
110
121
|
[[SDWebImageManager sharedManager] loadImageWithURL:source.url
|
|
111
122
|
options:options
|
|
112
|
-
context
|
|
123
|
+
context:[FFFPreloadContext(source) copy]
|
|
113
124
|
progress:nil
|
|
114
125
|
completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
|
|
115
126
|
if (!finished || done) {
|
|
@@ -47,6 +47,8 @@ RCT_ENUM_CONVERTER(FFFCacheControl, (@{
|
|
|
47
47
|
FFFastImageSource *imageSource = [[FFFastImageSource alloc] initWithURL:uri priority:priority headers:headers cacheControl:cacheControl];
|
|
48
48
|
id priorityJSON = json[@"priority"];
|
|
49
49
|
imageSource.hasPriority = priorityJSON && priorityJSON != (id)kCFNull;
|
|
50
|
+
NSString *cacheKey = [self NSString:json[@"cacheKey"]];
|
|
51
|
+
imageSource.cacheKey = cacheKey.length > 0 ? cacheKey : nil;
|
|
50
52
|
|
|
51
53
|
return imageSource;
|
|
52
54
|
}
|