react-native-fast-image 8.19.0 → 8.20.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 CHANGED
@@ -230,9 +230,9 @@ Called when the image starts to load.
230
230
 
231
231
  ### `onProgress?: (event) => void`
232
232
 
233
- Called when the image is loading.
233
+ Called while the image downloads, with the bytes `loaded` so far, the `total`, and `progress` (`loaded / total`, from 0 to 1; the last event has 1). Not called while the total is unknown (a response without a `Content-Length`).
234
234
 
235
- e.g. `onProgress={e => console.log(e.nativeEvent.loaded / e.nativeEvent.total)}`
235
+ e.g. `onProgress={e => console.log(e.nativeEvent.progress)}`
236
236
 
237
237
  ---
238
238
 
package/dist/index.cjs.js CHANGED
@@ -84,6 +84,13 @@ function loadResult(event) {
84
84
  error: (_event$error = event.error) !== null && _event$error !== void 0 ? _event$error : "Failed to load the image"
85
85
  };
86
86
  }
87
+ function withProgress(onProgress) {
88
+ return onProgress && ((event) => {
89
+ const { loaded, total } = event.nativeEvent;
90
+ event.nativeEvent.progress = total > 0 ? Math.min(1, Math.max(0, loaded / total)) : 0;
91
+ onProgress(event);
92
+ });
93
+ }
87
94
  function withoutCache(source) {
88
95
  const { cache: _cache, ...rest } = source || {};
89
96
  return rest;
@@ -114,7 +121,7 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
114
121
  source: resolvedSource,
115
122
  defaultSource,
116
123
  onLoadStart,
117
- onProgress,
124
+ onProgress: withProgress(onProgress),
118
125
  onLoad: onLoadEnd ? (event) => {
119
126
  const { width, height } = event.nativeEvent.source;
120
127
  fallbackResult.current = {
@@ -155,7 +162,7 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
155
162
  source: resolvedSource,
156
163
  defaultSource: resolvedDefaultSource,
157
164
  onFastImageLoadStart: onLoadStart,
158
- onFastImageProgress: onProgress,
165
+ onFastImageProgress: withProgress(onProgress),
159
166
  onFastImageLoad: onLoad,
160
167
  onFastImageError: onError,
161
168
  onFastImageLoadEnd: onLoadEnd && ((event) => onLoadEnd(loadResult(event.nativeEvent))),
@@ -23,6 +23,8 @@ export type OnProgressEvent = SyntheticEvent<
23
23
  $ReadOnly<{|
24
24
  loaded: number,
25
25
  total: number,
26
+ // loaded / total, from 0 to 1.
27
+ progress: number,
26
28
  |}>,
27
29
  >
28
30
 
package/dist/index.d.ts CHANGED
@@ -84,6 +84,7 @@ export interface OnProgressEvent {
84
84
  nativeEvent: {
85
85
  loaded: number;
86
86
  total: number;
87
+ progress: number;
87
88
  };
88
89
  }
89
90
  export interface ImageStyle extends ViewStyle {
package/dist/index.js CHANGED
@@ -57,6 +57,13 @@ function loadResult(event) {
57
57
  error: (_event$error = event.error) !== null && _event$error !== void 0 ? _event$error : "Failed to load the image"
58
58
  };
59
59
  }
60
+ function withProgress(onProgress) {
61
+ return onProgress && ((event) => {
62
+ const { loaded, total } = event.nativeEvent;
63
+ event.nativeEvent.progress = total > 0 ? Math.min(1, Math.max(0, loaded / total)) : 0;
64
+ onProgress(event);
65
+ });
66
+ }
60
67
  function withoutCache(source) {
61
68
  const { cache: _cache, ...rest } = source || {};
62
69
  return rest;
@@ -87,7 +94,7 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
87
94
  source: resolvedSource,
88
95
  defaultSource,
89
96
  onLoadStart,
90
- onProgress,
97
+ onProgress: withProgress(onProgress),
91
98
  onLoad: onLoadEnd ? (event) => {
92
99
  const { width, height } = event.nativeEvent.source;
93
100
  fallbackResult.current = {
@@ -128,7 +135,7 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
128
135
  source: resolvedSource,
129
136
  defaultSource: resolvedDefaultSource,
130
137
  onFastImageLoadStart: onLoadStart,
131
- onFastImageProgress: onProgress,
138
+ onFastImageProgress: withProgress(onProgress),
132
139
  onFastImageLoad: onLoad,
133
140
  onFastImageError: onError,
134
141
  onFastImageLoadEnd: onLoadEnd && ((event) => onLoadEnd(loadResult(event.nativeEvent))),
@@ -23,6 +23,8 @@ export type OnProgressEvent = SyntheticEvent<
23
23
  $ReadOnly<{|
24
24
  loaded: number,
25
25
  total: number,
26
+ // loaded / total, from 0 to 1.
27
+ progress: number,
26
28
  |}>,
27
29
  >
28
30
 
@@ -3,6 +3,7 @@
3
3
  #import <SDWebImage/UIView+WebCache.h>
4
4
  #import <React/RCTUtils.h>
5
5
  #import <SDWebImage/SDWebImageError.h>
6
+ #import <SDWebImage/SDImageTransformer.h>
6
7
  #import "FFFDownsampledImage.h"
7
8
 
8
9
  @interface FFFastImageView ()
@@ -58,6 +59,9 @@ static CFTimeInterval FFFEnteredBackgroundAt = 0;
58
59
  self = [super init];
59
60
  self.resizeMode = RCTResizeModeCover;
60
61
  self.clipsToBounds = YES;
62
+ // The tint (tintColor) stays as it is while an alert or sheet is shown,
63
+ // rather than dimming like the system's controls.
64
+ self.tintAdjustmentMode = UIViewTintAdjustmentModeNormal;
61
65
  _loopCount = -1;
62
66
  return self;
63
67
  }
@@ -197,53 +201,47 @@ static CFTimeInterval FFFEnteredBackgroundAt = 0;
197
201
  // Re-apply to the untinted image, so the tint can change or be removed.
198
202
  UIImage* image = self.untintedImage ?: super.image;
199
203
  if (image) {
204
+ // SDAnimatedImageView ignores the image it already shows, which would
205
+ // keep an animated image's frames as they were tinted.
206
+ super.image = nil;
200
207
  [self setImage: image];
201
208
  }
202
209
  }
203
210
 
204
- - (UIImage*) makeImage: (UIImage*)image withTint: (UIColor*)color {
205
- // FIX: Prevent crash on zero/invalid image dimensions
206
- if (!image || image.size.width <= 0 || image.size.height <= 0) {
207
- return image;
208
- }
209
-
210
- UIImage* templateImage = [image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate];
211
- CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
212
- UIImage* newImage;
213
- if (@available(iOS 10.0, tvOS 10.0, *)) {
214
- // UIGraphicsBeginImageContextWithOptions is deprecated since iOS 17.
215
- // Keep the source image's scale and a standard-range (8-bit) bitmap,
216
- // matching what it produced.
217
- UIGraphicsImageRendererFormat* format = [[UIGraphicsImageRendererFormat alloc] init];
218
- format.scale = image.scale;
219
- format.opaque = NO;
220
- if (@available(iOS 12.0, tvOS 12.0, *)) {
221
- format.preferredRange = UIGraphicsImageRendererFormatRangeStandard;
222
- } else {
223
- format.prefersExtendedRange = NO;
224
- }
225
- UIGraphicsImageRenderer* renderer = [[UIGraphicsImageRenderer alloc] initWithSize: image.size format: format];
226
- newImage = [renderer imageWithActions: ^(UIGraphicsImageRendererContext* context) {
227
- [color set];
228
- [templateImage drawInRect: rect];
229
- }];
230
- } else {
231
- // iOS/tvOS 9. Remove this branch once the minimum is iOS 10+.
232
- UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
233
- [color set];
234
- [templateImage drawInRect: rect];
235
- newImage = UIGraphicsGetImageFromCurrentImageContext();
236
- UIGraphicsEndImageContext();
237
- }
238
- return newImage;
211
+ // Whether SDAnimatedImageView can tint the frames of an animated image as
212
+ // they're decoded (animationTransformer, SDWebImage 5.20+).
213
+ - (BOOL) tintsFrames {
214
+ return [self respondsToSelector: @selector(setAnimationTransformer:)];
239
215
  }
240
216
 
241
217
  - (void) setImage: (UIImage*)image {
242
- if (self.imageColor != nil) {
243
- self.untintedImage = image;
244
- super.image = [self makeImage: image withTint: self.imageColor];
218
+ // Tinted as React Native's Image does it: UIKit draws a template image in
219
+ // the view's tintColor, so no tinted copy of the image is made.
220
+ // SDAnimatedImageView draws the frames of an animated image itself,
221
+ // without the tint, so each frame is tinted as it's decoded (source-in,
222
+ // as the template is), or, before SDWebImage 5.20, the first frame shows.
223
+ UIColor* tint = image ? self.imageColor : nil;
224
+ BOOL animated = [image conformsToProtocol: @protocol(SDAnimatedImage)] && [(id<SDAnimatedImage>)image animatedImageFrameCount] > 1;
225
+ self.untintedImage = tint ? image : nil;
226
+ self.tintColor = tint;
227
+ if ([self tintsFrames]) {
228
+ [self setValue: tint && animated ? [SDImageTintTransformer transformerWithColor: tint] : nil forKey: @"animationTransformer"];
229
+ }
230
+ if (tint && animated && [self tintsFrames]) {
231
+ BOOL changed = super.image != image;
232
+ super.image = image;
233
+ // Shows the first frame tinted now, also while paused (the player
234
+ // only draws frames as it plays; until then the view draws the
235
+ // untinted image).
236
+ if (changed) {
237
+ [self.player seekToFrameAtIndex: 0 loopCount: 0];
238
+ }
239
+ } else if (tint) {
240
+ if (animated) {
241
+ image = [UIImage imageWithCGImage: image.CGImage scale: image.scale orientation: image.imageOrientation];
242
+ }
243
+ super.image = [image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate];
245
244
  } else {
246
- self.untintedImage = nil;
247
245
  super.image = image;
248
246
  }
249
247
  [self updateContentMode];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-fast-image",
3
- "version": "8.19.0",
3
+ "version": "8.20.0",
4
4
  "description": "🚩 FastImage, performant React Native image component.",
5
5
  "keywords": [
6
6
  "cache",