react-native-fast-image 8.15.0 → 8.16.0
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 +17 -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 +6 -0
- package/ios/FastImage/FFFastImageSource.m +12 -0
- package/ios/FastImage/FFFastImageView.m +3 -1
- package/ios/FastImage/FFFastImageViewManager.m +10 -1
- 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(...)`.
|
|
@@ -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,7 @@
|
|
|
1
1
|
#import <Foundation/Foundation.h>
|
|
2
2
|
#import <UIKit/UIKit.h>
|
|
3
3
|
#import <SDWebImage/SDWebImageDownloaderRequestModifier.h>
|
|
4
|
+
#import <SDWebImage/SDWebImageCacheKeyFilter.h>
|
|
4
5
|
|
|
5
6
|
typedef NS_ENUM(NSInteger, FFFPriority) {
|
|
6
7
|
FFFPriorityLow,
|
|
@@ -27,6 +28,8 @@ typedef NS_ENUM(NSInteger, FFFCacheControl) {
|
|
|
27
28
|
@property (nonatomic) NSDictionary *headers;
|
|
28
29
|
// cache control mode
|
|
29
30
|
@property (nonatomic) FFFCacheControl cacheControl;
|
|
31
|
+
// The key to cache the image under instead of its url, or nil.
|
|
32
|
+
@property (nonatomic, copy) NSString *cacheKey;
|
|
30
33
|
|
|
31
34
|
- (instancetype)initWithURL:(NSURL *)url
|
|
32
35
|
priority:(FFFPriority)priority
|
|
@@ -36,4 +39,7 @@ typedef NS_ENUM(NSInteger, FFFCacheControl) {
|
|
|
36
39
|
// Adds this source's headers to its image requests.
|
|
37
40
|
- (SDWebImageDownloaderRequestModifier *)requestModifier;
|
|
38
41
|
|
|
42
|
+
// Caches the image under cacheKey, or nil without one.
|
|
43
|
+
- (SDWebImageCacheKeyFilter *)cacheKeyFilter;
|
|
44
|
+
|
|
39
45
|
@end
|
|
@@ -17,6 +17,18 @@
|
|
|
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
|
+
|
|
20
32
|
- (SDWebImageDownloaderRequestModifier *)requestModifier
|
|
21
33
|
{
|
|
22
34
|
NSDictionary* headers = _headers;
|
|
@@ -518,6 +518,7 @@ NSString *FFFErrorMessage(NSError *error)
|
|
|
518
518
|
- (SDWebImageContext*) loadContext {
|
|
519
519
|
SDWebImageMutableContext* context = [NSMutableDictionary dictionary];
|
|
520
520
|
context[SDWebImageContextDownloadRequestModifier] = _source.requestModifier;
|
|
521
|
+
context[SDWebImageContextCacheKeyFilter] = _source.cacheKeyFilter;
|
|
521
522
|
CGSize box = [self decodeBox];
|
|
522
523
|
self.decodedBox = box;
|
|
523
524
|
self.decodedCover = [self decodeCovers];
|
|
@@ -525,7 +526,8 @@ NSString *FFFErrorMessage(NSError *error)
|
|
|
525
526
|
context[SDWebImageContextAnimatedImageClass] = [SDAnimatedImage class];
|
|
526
527
|
return context;
|
|
527
528
|
}
|
|
528
|
-
|
|
529
|
+
NSString* key = _source.cacheKeyFilter ? _source.cacheKey : _source.url.absoluteString;
|
|
530
|
+
[FFFDownsampledImage addToContext: context forKey: key box: box cover: self.decodedCover];
|
|
529
531
|
return context;
|
|
530
532
|
}
|
|
531
533
|
|
|
@@ -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;
|
|
@@ -109,7 +118,7 @@ RCT_EXPORT_METHOD(preload:(nonnull NSArray<FFFastImageSource *> *)sources
|
|
|
109
118
|
__block BOOL done = NO;
|
|
110
119
|
[[SDWebImageManager sharedManager] loadImageWithURL:source.url
|
|
111
120
|
options:options
|
|
112
|
-
context
|
|
121
|
+
context:[FFFPreloadContext(source) copy]
|
|
113
122
|
progress:nil
|
|
114
123
|
completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
|
|
115
124
|
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
|
}
|