react-native-fast-image 8.9.0 → 8.11.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 +14 -2
- package/android/src/main/java/com/dylanvann/fastimage/FastImageRequestListener.java +16 -1
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java +5 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewModule.java +1 -12
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java +40 -4
- package/dist/index.cjs.js.flow +8 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js.flow +8 -1
- package/ios/FastImage/FFFastImageView.h +7 -0
- package/ios/FastImage/FFFastImageView.m +43 -9
- package/ios/FastImage/FFFastImageViewManager.m +1 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -186,6 +186,16 @@ Changing it restarts the animation.
|
|
|
186
186
|
|
|
187
187
|
---
|
|
188
188
|
|
|
189
|
+
### `imageRendering?: 'auto' | 'smooth' | 'pixelated'`
|
|
190
|
+
|
|
191
|
+
How the image is filtered when it's drawn smaller or larger than its size (like CSS's `image-rendering`):
|
|
192
|
+
|
|
193
|
+
- `'auto'` **(Default)** - The platform's usual filtering.
|
|
194
|
+
- `'smooth'` - iOS only. Keeps a large image drawn much smaller than its size (e.g. a big photo as a thumbnail, or fine lines and text) from looking jagged or noisy. **It uses more memory:** the image is also kept at smaller sizes for drawing, about a third more than the decoded image. On Android it's the same as `'auto'` (images are already decoded at about the view's size there).
|
|
195
|
+
- `'pixelated'` - Sharp pixels, without smoothing, e.g. for pixel art drawn larger than its size. On Android, animated images are still smoothed.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
189
199
|
### `onLoadStart?: () => void`
|
|
190
200
|
|
|
191
201
|
Called when the image starts to load.
|
|
@@ -208,9 +218,11 @@ e.g. `onLoad={e => console.log(e.nativeEvent.width, e.nativeEvent.height)}`
|
|
|
208
218
|
|
|
209
219
|
---
|
|
210
220
|
|
|
211
|
-
### `onError?: () => void`
|
|
221
|
+
### `onError?: (event) => void`
|
|
222
|
+
|
|
223
|
+
Called on an image fetching error, with a message describing it (e.g. the HTTP status code).
|
|
212
224
|
|
|
213
|
-
|
|
225
|
+
e.g. `onError={e => console.log(e.nativeEvent.error)}`
|
|
214
226
|
|
|
215
227
|
---
|
|
216
228
|
|
|
@@ -41,11 +41,26 @@ public class FastImageRequestListener implements RequestListener<Drawable> {
|
|
|
41
41
|
}
|
|
42
42
|
FastImageViewWithUrl view = (FastImageViewWithUrl) ((ImageViewTarget) target).getView();
|
|
43
43
|
view.onImageFailed(thumbnail);
|
|
44
|
-
|
|
44
|
+
WritableMap event = new WritableNativeMap();
|
|
45
|
+
event.putString("error", errorMessage(e));
|
|
46
|
+
FastImageEvents.send(view, REACT_ON_ERROR_EVENT, event);
|
|
45
47
|
FastImageEvents.send(view, REACT_ON_LOAD_END_EVENT);
|
|
46
48
|
return false;
|
|
47
49
|
}
|
|
48
50
|
|
|
51
|
+
// The first root cause's message, e.g. "Not Found, status code: 404".
|
|
52
|
+
// The first root cause's message, e.g. "Not Found, status code: 404" (also
|
|
53
|
+
// for preload results).
|
|
54
|
+
static String errorMessage(@androidx.annotation.Nullable GlideException e) {
|
|
55
|
+
if (e != null) {
|
|
56
|
+
for (Throwable cause : e.getRootCauses()) {
|
|
57
|
+
if (cause.getMessage() != null) return cause.getMessage();
|
|
58
|
+
}
|
|
59
|
+
if (e.getMessage() != null) return e.getMessage();
|
|
60
|
+
}
|
|
61
|
+
return "Failed to load the image";
|
|
62
|
+
}
|
|
63
|
+
|
|
49
64
|
@Override
|
|
50
65
|
public boolean onResourceReady(Drawable resource, Object model, final Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
|
|
51
66
|
if (!(target instanceof ImageViewTarget)) {
|
|
@@ -94,6 +94,11 @@ class FastImageViewManager extends SimpleViewManager<FastImageViewWithUrl> imple
|
|
|
94
94
|
view.setLoopCount(loopCount);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
@ReactProp(name = "imageRendering")
|
|
98
|
+
public void setImageRendering(FastImageViewWithUrl view, @Nullable String imageRendering) {
|
|
99
|
+
view.setImageRendering(imageRendering);
|
|
100
|
+
}
|
|
101
|
+
|
|
97
102
|
@ReactProp(name = "resizeMode")
|
|
98
103
|
public void setResizeMode(FastImageViewWithUrl view, String resizeMode) {
|
|
99
104
|
final FastImageViewWithUrl.ScaleType scaleType = FastImageViewConverter.getScaleType(resizeMode);
|
|
@@ -122,7 +122,7 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
122
122
|
.listener(new RequestListener<Drawable>() {
|
|
123
123
|
@Override
|
|
124
124
|
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
|
|
125
|
-
results[index] = failure(errorMessage(e));
|
|
125
|
+
results[index] = failure(FastImageRequestListener.errorMessage(e));
|
|
126
126
|
preloadsInFlight--;
|
|
127
127
|
finishOne.run();
|
|
128
128
|
startPendingPreloads();
|
|
@@ -164,17 +164,6 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
164
164
|
return result;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
// The first root cause's message, e.g. "Not Found, status code: 404".
|
|
168
|
-
private static String errorMessage(@Nullable GlideException e) {
|
|
169
|
-
if (e != null) {
|
|
170
|
-
for (Throwable cause : e.getRootCauses()) {
|
|
171
|
-
if (cause.getMessage() != null) return cause.getMessage();
|
|
172
|
-
}
|
|
173
|
-
if (e.getMessage() != null) return e.getMessage();
|
|
174
|
-
}
|
|
175
|
-
return "Failed to load the image";
|
|
176
|
-
}
|
|
177
|
-
|
|
178
167
|
@ReactMethod
|
|
179
168
|
public void clearMemoryCache(final Promise promise) {
|
|
180
169
|
final Activity activity = getCurrentActivity();
|
|
@@ -5,6 +5,7 @@ import static com.dylanvann.fastimage.FastImageRequestListener.REACT_ON_LOAD_END
|
|
|
5
5
|
|
|
6
6
|
import android.annotation.SuppressLint;
|
|
7
7
|
import android.content.Context;
|
|
8
|
+
import android.graphics.drawable.BitmapDrawable;
|
|
8
9
|
import android.graphics.drawable.Drawable;
|
|
9
10
|
|
|
10
11
|
import androidx.annotation.NonNull;
|
|
@@ -15,8 +16,10 @@ import androidx.core.view.ViewCompat;
|
|
|
15
16
|
import com.bumptech.glide.RequestBuilder;
|
|
16
17
|
import com.bumptech.glide.RequestManager;
|
|
17
18
|
import com.bumptech.glide.load.model.GlideUrl;
|
|
19
|
+
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy;
|
|
18
20
|
import com.bumptech.glide.load.resource.gif.GifDrawable;
|
|
19
21
|
import com.bumptech.glide.request.Request;
|
|
22
|
+
import com.bumptech.glide.request.RequestOptions;
|
|
20
23
|
import com.bumptech.glide.request.target.DrawableImageViewTarget;
|
|
21
24
|
import com.bumptech.glide.request.target.SizeReadyCallback;
|
|
22
25
|
import com.bumptech.glide.request.transition.Transition;
|
|
@@ -95,6 +98,13 @@ class FastImageViewWithUrl extends AppCompatImageView {
|
|
|
95
98
|
|
|
96
99
|
@Override
|
|
97
100
|
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
|
|
101
|
+
if (resource instanceof BitmapDrawable) {
|
|
102
|
+
if (mPixelated) {
|
|
103
|
+
// Scaled by the view without filtering: sharp pixels.
|
|
104
|
+
resource = resource.mutate();
|
|
105
|
+
resource.setFilterBitmap(false);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
98
108
|
if (resource instanceof GifDrawable) {
|
|
99
109
|
GifDrawable own = FastImageGif.copy(
|
|
100
110
|
getContext(), (GifDrawable) resource, mLoadingWidth, mLoadingHeight);
|
|
@@ -134,6 +144,33 @@ class FastImageViewWithUrl extends AppCompatImageView {
|
|
|
134
144
|
mNeedsReload = true;
|
|
135
145
|
}
|
|
136
146
|
|
|
147
|
+
// imageRendering="pixelated": no resampling by Glide, and drawn without
|
|
148
|
+
// filtering (sharp pixels). "smooth" is iOS only; here it's the same as
|
|
149
|
+
// "auto": Glide already decodes a large image at about the view's size, and
|
|
150
|
+
// averaging it properly would need a full-size decode. Part of the
|
|
151
|
+
// request, so a change reloads.
|
|
152
|
+
private boolean mPixelated = false;
|
|
153
|
+
|
|
154
|
+
public void setImageRendering(@Nullable String imageRendering) {
|
|
155
|
+
boolean pixelated = "pixelated".equals(imageRendering);
|
|
156
|
+
if (pixelated == mPixelated) return;
|
|
157
|
+
mPixelated = pixelated;
|
|
158
|
+
mNeedsReload = true;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// The scale type's options (what into() would apply), or none when
|
|
162
|
+
// pixelated.
|
|
163
|
+
private RequestOptions renderingOptions(Object model) {
|
|
164
|
+
if (mPixelated) {
|
|
165
|
+
// Decoded as it is, then scaled by the view without filtering (see
|
|
166
|
+
// OwnGifTarget).
|
|
167
|
+
return new RequestOptions()
|
|
168
|
+
.downsample(new FastImageSourceSize.Capture(DownsampleStrategy.NONE, String.valueOf(model)))
|
|
169
|
+
.dontTransform();
|
|
170
|
+
}
|
|
171
|
+
return FastImageSourceSize.scaleTypeOptions(getScaleType(), FastImageSourceSize.capture(getScaleType(), model));
|
|
172
|
+
}
|
|
173
|
+
|
|
137
174
|
// The request for the image the view shows once it has loaded, and the one
|
|
138
175
|
// loading. A new source starts with the shown one as a thumbnail, from the
|
|
139
176
|
// cache only, so the image stays until the new one has loaded instead of
|
|
@@ -308,7 +345,7 @@ class FastImageViewWithUrl extends AppCompatImageView {
|
|
|
308
345
|
// (#1028, #945).
|
|
309
346
|
if (mSource != null && (imageSource == null || imageSource.getUri().toString().length() == 0)) {
|
|
310
347
|
WritableMap event = new WritableNativeMap();
|
|
311
|
-
event.putString("
|
|
348
|
+
event.putString("error", "Invalid source: " + mSource);
|
|
312
349
|
FastImageEvents.send(this, REACT_ON_ERROR_EVENT, event);
|
|
313
350
|
FastImageEvents.send(this, REACT_ON_LOAD_END_EVENT);
|
|
314
351
|
|
|
@@ -353,7 +390,6 @@ class FastImageViewWithUrl extends AppCompatImageView {
|
|
|
353
390
|
if (requestManager != null) {
|
|
354
391
|
// Records the image's own size when Glide decodes it, for onLoad.
|
|
355
392
|
Object model = imageSource == null ? null : imageSource.getSourceForLoad();
|
|
356
|
-
FastImageSourceSize.Capture capture = FastImageSourceSize.capture(getScaleType(), model);
|
|
357
393
|
RequestBuilder<Drawable> builder =
|
|
358
394
|
requestManager
|
|
359
395
|
// This will make this work for remote and local images. e.g.
|
|
@@ -368,8 +404,8 @@ class FastImageViewWithUrl extends AppCompatImageView {
|
|
|
368
404
|
.placeholder(mDefaultSource) // show until loaded
|
|
369
405
|
.fallback(mDefaultSource)) // null will not be treated as error
|
|
370
406
|
// What into() would apply for the scale type, with
|
|
371
|
-
// the size capture.
|
|
372
|
-
.apply(
|
|
407
|
+
// the size capture, for imageRendering.
|
|
408
|
+
.apply(renderingOptions(model));
|
|
373
409
|
RequestBuilder<Drawable> request = builder.clone();
|
|
374
410
|
|
|
375
411
|
boolean thumbnail = shownRequest != null && model != null;
|
package/dist/index.cjs.js.flow
CHANGED
|
@@ -13,6 +13,12 @@ export type OnLoadEvent = SyntheticEvent<
|
|
|
13
13
|
}>,
|
|
14
14
|
>
|
|
15
15
|
|
|
16
|
+
export type OnErrorEvent = SyntheticEvent<
|
|
17
|
+
$ReadOnly<{|
|
|
18
|
+
error: string,
|
|
19
|
+
|}>,
|
|
20
|
+
>
|
|
21
|
+
|
|
16
22
|
export type OnProgressEvent = SyntheticEvent<
|
|
17
23
|
$ReadOnly<{|
|
|
18
24
|
loaded: number,
|
|
@@ -70,7 +76,7 @@ export type FastImageSource = {
|
|
|
70
76
|
|
|
71
77
|
export type FastImageProps = $ReadOnly<{|
|
|
72
78
|
...ViewProps,
|
|
73
|
-
onError?: ?() => void,
|
|
79
|
+
onError?: ?(event: OnErrorEvent) => void,
|
|
74
80
|
onLoad?: ?(event: OnLoadEvent) => void,
|
|
75
81
|
onLoadEnd?: ?() => void,
|
|
76
82
|
onLoadStart?: ?() => void,
|
|
@@ -84,6 +90,7 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
84
90
|
fallback?: ?boolean,
|
|
85
91
|
recyclingKey?: ?string,
|
|
86
92
|
loop?: ?(boolean | number),
|
|
93
|
+
imageRendering?: ?('auto' | 'smooth' | 'pixelated'),
|
|
87
94
|
testID?: ?string,
|
|
88
95
|
|}>
|
|
89
96
|
|
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,11 @@ export interface OnLoadEvent {
|
|
|
35
35
|
target?: number;
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
+
export interface OnErrorEvent {
|
|
39
|
+
nativeEvent: {
|
|
40
|
+
error: string;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
38
43
|
export interface OnProgressEvent {
|
|
39
44
|
nativeEvent: {
|
|
40
45
|
loaded: number;
|
|
@@ -75,10 +80,18 @@ export interface FastImageProps extends AccessibilityProps, ViewProps {
|
|
|
75
80
|
* or a number of times. Changing it restarts the animation.
|
|
76
81
|
*/
|
|
77
82
|
loop?: boolean | number;
|
|
83
|
+
/**
|
|
84
|
+
* How the image is filtered when it's drawn smaller or larger than its
|
|
85
|
+
* size: `'auto'` (default, the platform's usual filtering), `'smooth'`
|
|
86
|
+
* (iOS only: keeps a large image drawn much smaller from looking jagged
|
|
87
|
+
* or noisy; uses more memory, see the README) or `'pixelated'` (sharp
|
|
88
|
+
* pixels, e.g. for pixel art).
|
|
89
|
+
*/
|
|
90
|
+
imageRendering?: 'auto' | 'smooth' | 'pixelated';
|
|
78
91
|
onLoadStart?(): void;
|
|
79
92
|
onProgress?(event: OnProgressEvent): void;
|
|
80
93
|
onLoad?(event: OnLoadEvent): void;
|
|
81
|
-
onError?(): void;
|
|
94
|
+
onError?(event: OnErrorEvent): void;
|
|
82
95
|
onLoadEnd?(): void;
|
|
83
96
|
/**
|
|
84
97
|
* onLayout function
|
package/dist/index.js.flow
CHANGED
|
@@ -13,6 +13,12 @@ export type OnLoadEvent = SyntheticEvent<
|
|
|
13
13
|
}>,
|
|
14
14
|
>
|
|
15
15
|
|
|
16
|
+
export type OnErrorEvent = SyntheticEvent<
|
|
17
|
+
$ReadOnly<{|
|
|
18
|
+
error: string,
|
|
19
|
+
|}>,
|
|
20
|
+
>
|
|
21
|
+
|
|
16
22
|
export type OnProgressEvent = SyntheticEvent<
|
|
17
23
|
$ReadOnly<{|
|
|
18
24
|
loaded: number,
|
|
@@ -70,7 +76,7 @@ export type FastImageSource = {
|
|
|
70
76
|
|
|
71
77
|
export type FastImageProps = $ReadOnly<{|
|
|
72
78
|
...ViewProps,
|
|
73
|
-
onError?: ?() => void,
|
|
79
|
+
onError?: ?(event: OnErrorEvent) => void,
|
|
74
80
|
onLoad?: ?(event: OnLoadEvent) => void,
|
|
75
81
|
onLoadEnd?: ?() => void,
|
|
76
82
|
onLoadStart?: ?() => void,
|
|
@@ -84,6 +90,7 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
84
90
|
fallback?: ?boolean,
|
|
85
91
|
recyclingKey?: ?string,
|
|
86
92
|
loop?: ?(boolean | number),
|
|
93
|
+
imageRendering?: ?('auto' | 'smooth' | 'pixelated'),
|
|
87
94
|
testID?: ?string,
|
|
88
95
|
|}>
|
|
89
96
|
|
|
@@ -25,6 +25,13 @@
|
|
|
25
25
|
// How many times animated images play: -1 for the file's own loop count (the
|
|
26
26
|
// `loop` prop not set), 0 for forever, or a number of times.
|
|
27
27
|
@property (nonatomic, assign) NSInteger loopCount;
|
|
28
|
+
// How the image is filtered when drawn at another size: auto, smooth or
|
|
29
|
+
// pixelated.
|
|
30
|
+
@property (nonatomic, copy) NSString *imageRendering;
|
|
28
31
|
|
|
29
32
|
@end
|
|
30
33
|
|
|
34
|
+
// An error's description, with the HTTP status code when there is one.
|
|
35
|
+
FOUNDATION_EXTERN NSString *FFFErrorMessage(NSError *error);
|
|
36
|
+
|
|
37
|
+
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#import <SDWebImage/UIImage+MultiFormat.h>
|
|
3
3
|
#import <SDWebImage/UIView+WebCache.h>
|
|
4
4
|
#import <React/RCTUtils.h>
|
|
5
|
+
#import <SDWebImage/SDWebImageError.h>
|
|
5
6
|
|
|
6
7
|
@interface FFFastImageView ()
|
|
7
8
|
|
|
@@ -12,6 +13,7 @@
|
|
|
12
13
|
@property(nonatomic, assign) BOOL needsReload;
|
|
13
14
|
|
|
14
15
|
@property(nonatomic, strong) NSDictionary* onLoadEvent;
|
|
16
|
+
@property(nonatomic, strong) NSDictionary* onErrorEvent;
|
|
15
17
|
// The image before tinting, kept while a tint is applied so the tint can be
|
|
16
18
|
// changed or removed. nil when there's no tint (super.image is untinted).
|
|
17
19
|
@property(nonatomic, strong) UIImage* untintedImage;
|
|
@@ -51,6 +53,24 @@ static CFTimeInterval FFFEnteredBackgroundAt = 0;
|
|
|
51
53
|
return self;
|
|
52
54
|
}
|
|
53
55
|
|
|
56
|
+
- (void) setImageRendering: (NSString*)imageRendering {
|
|
57
|
+
_imageRendering = [imageRendering copy];
|
|
58
|
+
if ([imageRendering isEqualToString: @"smooth"]) {
|
|
59
|
+
// Trilinear: drawn smaller from mipmaps, so a large image drawn much
|
|
60
|
+
// smaller is smoothed instead of aliased (#445). The mipmaps take
|
|
61
|
+
// about a third more memory than the decoded image.
|
|
62
|
+
self.layer.minificationFilter = kCAFilterTrilinear;
|
|
63
|
+
self.layer.magnificationFilter = kCAFilterLinear;
|
|
64
|
+
} else if ([imageRendering isEqualToString: @"pixelated"]) {
|
|
65
|
+
// Nearest neighbor: sharp pixels, e.g. for pixel art (#926).
|
|
66
|
+
self.layer.minificationFilter = kCAFilterNearest;
|
|
67
|
+
self.layer.magnificationFilter = kCAFilterNearest;
|
|
68
|
+
} else {
|
|
69
|
+
self.layer.minificationFilter = kCAFilterLinear;
|
|
70
|
+
self.layer.magnificationFilter = kCAFilterLinear;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
54
74
|
- (void) setLoopCount: (NSInteger)loopCount {
|
|
55
75
|
if (_loopCount == loopCount) {
|
|
56
76
|
return;
|
|
@@ -120,7 +140,7 @@ static CFTimeInterval FFFEnteredBackgroundAt = 0;
|
|
|
120
140
|
- (void) setOnFastImageError: (RCTDirectEventBlock)onFastImageError {
|
|
121
141
|
_onFastImageError = onFastImageError;
|
|
122
142
|
if (self.hasErrored && _onFastImageError) {
|
|
123
|
-
_onFastImageError(
|
|
143
|
+
_onFastImageError(self.onErrorEvent);
|
|
124
144
|
}
|
|
125
145
|
}
|
|
126
146
|
|
|
@@ -194,6 +214,26 @@ static CFTimeInterval FFFEnteredBackgroundAt = 0;
|
|
|
194
214
|
[self updateContentMode];
|
|
195
215
|
}
|
|
196
216
|
|
|
217
|
+
// The error's description, with the HTTP status code when there is one (as on
|
|
218
|
+
// Android): SDWebImage keeps the code out of the description. Also for preload
|
|
219
|
+
// results.
|
|
220
|
+
NSString *FFFErrorMessage(NSError *error)
|
|
221
|
+
{
|
|
222
|
+
NSNumber *statusCode = error.userInfo[SDWebImageErrorDownloadStatusCodeKey];
|
|
223
|
+
if (statusCode) {
|
|
224
|
+
return [NSString stringWithFormat: @"%@, status code: %@", error.localizedDescription, statusCode];
|
|
225
|
+
}
|
|
226
|
+
return error.localizedDescription ?: @"Failed to load the image";
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
- (void) sendOnError: (nullable NSString*)message {
|
|
230
|
+
self.hasErrored = YES;
|
|
231
|
+
self.onErrorEvent = @{ @"error": message ?: @"Failed to load the image" };
|
|
232
|
+
if (self.onFastImageError) {
|
|
233
|
+
self.onFastImageError(self.onErrorEvent);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
197
237
|
- (void) sendOnLoad: (UIImage*)image {
|
|
198
238
|
self.onLoadEvent = @{
|
|
199
239
|
@"width": [NSNumber numberWithDouble: image.size.width],
|
|
@@ -258,10 +298,7 @@ static CFTimeInterval FFFEnteredBackgroundAt = 0;
|
|
|
258
298
|
// Not decodable: fail like a remote image, showing defaultSource.
|
|
259
299
|
[self setImage: _defaultSource];
|
|
260
300
|
self.showsLoadedImage = NO;
|
|
261
|
-
self
|
|
262
|
-
if (self.onFastImageError) {
|
|
263
|
-
self.onFastImageError(@{});
|
|
264
|
-
}
|
|
301
|
+
[self sendOnError: @"Failed to decode the image"];
|
|
265
302
|
if (self.onFastImageLoadEnd) {
|
|
266
303
|
self.onFastImageLoadEnd(@{});
|
|
267
304
|
}
|
|
@@ -391,10 +428,7 @@ static CFTimeInterval FFFEnteredBackgroundAt = 0;
|
|
|
391
428
|
if (error) {
|
|
392
429
|
// SDWebImage shows the placeholder (defaultSource or nothing).
|
|
393
430
|
weakSelf.showsLoadedImage = NO;
|
|
394
|
-
weakSelf
|
|
395
|
-
if (weakSelf.onFastImageError) {
|
|
396
|
-
weakSelf.onFastImageError(@{});
|
|
397
|
-
}
|
|
431
|
+
[weakSelf sendOnError: FFFErrorMessage(error)];
|
|
398
432
|
if (weakSelf.onFastImageLoadEnd) {
|
|
399
433
|
weakSelf.onFastImageLoadEnd(@{});
|
|
400
434
|
}
|
|
@@ -19,6 +19,7 @@ RCT_EXPORT_VIEW_PROPERTY(defaultSource, UIImage)
|
|
|
19
19
|
RCT_EXPORT_VIEW_PROPERTY(resizeMode, RCTResizeMode)
|
|
20
20
|
RCT_EXPORT_VIEW_PROPERTY(recyclingKey, NSString)
|
|
21
21
|
RCT_EXPORT_VIEW_PROPERTY(loopCount, NSInteger)
|
|
22
|
+
RCT_EXPORT_VIEW_PROPERTY(imageRendering, NSString)
|
|
22
23
|
RCT_EXPORT_VIEW_PROPERTY(onFastImageLoadStart, RCTDirectEventBlock)
|
|
23
24
|
RCT_EXPORT_VIEW_PROPERTY(onFastImageProgress, RCTDirectEventBlock)
|
|
24
25
|
RCT_EXPORT_VIEW_PROPERTY(onFastImageError, RCTDirectEventBlock)
|
|
@@ -26,16 +27,6 @@ RCT_EXPORT_VIEW_PROPERTY(onFastImageLoad, RCTDirectEventBlock)
|
|
|
26
27
|
RCT_EXPORT_VIEW_PROPERTY(onFastImageLoadEnd, RCTDirectEventBlock)
|
|
27
28
|
RCT_REMAP_VIEW_PROPERTY(tintColor, imageColor, UIColor)
|
|
28
29
|
|
|
29
|
-
// The error's description, with the HTTP status code when there is one.
|
|
30
|
-
static NSString *FFFErrorMessage(NSError *error)
|
|
31
|
-
{
|
|
32
|
-
NSNumber *statusCode = error.userInfo[SDWebImageErrorDownloadStatusCodeKey];
|
|
33
|
-
if (statusCode) {
|
|
34
|
-
return [NSString stringWithFormat:@"%@, status code: %@", error.localizedDescription, statusCode];
|
|
35
|
-
}
|
|
36
|
-
return error.localizedDescription ?: @"Failed to load the image";
|
|
37
|
-
}
|
|
38
|
-
|
|
39
30
|
// Preloads waiting to start, in the order they were added, and the number
|
|
40
31
|
// loading, across all preload calls. Like SDWebImagePrefetcher, at most
|
|
41
32
|
// maxConcurrentPrefetchCount load at a time, so a long list doesn't queue
|