react-native-fast-image 8.14.0 → 8.15.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
@@ -242,9 +242,19 @@ e.g. `onError={e => console.log(e.nativeEvent.error)}`
242
242
 
243
243
  ---
244
244
 
245
- ### `onLoadEnd?: () => void`
245
+ ### `onLoadEnd?: (result) => void`
246
246
 
247
- Called when the image finishes loading, whether it was successful or an error.
247
+ Called when the image finishes loading, whether it was successful or an error, with the result: `{ ok: true, width, height }` (the image's size, as `onLoad` gets it) or `{ ok: false, error }` (as `onError` gets it). TypeScript makes you check `ok` before reading the size or the error.
248
+
249
+ ```jsx
250
+ <FastImage
251
+ source={{ uri }}
252
+ onLoadEnd={(result) => {
253
+ if (result.ok) setAspectRatio(result.width / result.height)
254
+ else setFailed(result.error)
255
+ }}
256
+ />
257
+ ```
248
258
 
249
259
  ---
250
260
 
@@ -26,6 +26,24 @@ final class FastImageEvents {
26
26
  send(view, name, Arguments.createMap());
27
27
  }
28
28
 
29
+ // onLoadEnd with the load's result: ok with the image's size, as onLoad
30
+ // sent it.
31
+ static void sendLoadEnd(View view, int width, int height) {
32
+ WritableMap event = Arguments.createMap();
33
+ event.putBoolean("ok", true);
34
+ event.putInt("width", width);
35
+ event.putInt("height", height);
36
+ send(view, FastImageRequestListener.REACT_ON_LOAD_END_EVENT, event);
37
+ }
38
+
39
+ // onLoadEnd with the load's result: not ok, with the error onError sent.
40
+ static void sendLoadEnd(View view, String error) {
41
+ WritableMap event = Arguments.createMap();
42
+ event.putBoolean("ok", false);
43
+ event.putString("error", error);
44
+ send(view, FastImageRequestListener.REACT_ON_LOAD_END_EVENT, event);
45
+ }
46
+
29
47
  static void send(View view, String name, WritableMap data) {
30
48
  ReactContext context = FastImageViewManager.getReactContext(view.getContext());
31
49
  if (context == null) return;
@@ -41,10 +41,11 @@ public class FastImageRequestListener implements RequestListener<Drawable> {
41
41
  }
42
42
  FastImageViewWithUrl view = (FastImageViewWithUrl) ((ImageViewTarget) target).getView();
43
43
  view.onImageFailed(thumbnail);
44
+ String error = errorMessage(e);
44
45
  WritableMap event = new WritableNativeMap();
45
- event.putString("error", errorMessage(e));
46
+ event.putString("error", error);
46
47
  FastImageEvents.send(view, REACT_ON_ERROR_EVENT, event);
47
- FastImageEvents.send(view, REACT_ON_LOAD_END_EVENT);
48
+ FastImageEvents.sendLoadEnd(view, error);
48
49
  return false;
49
50
  }
50
51
 
@@ -98,6 +99,6 @@ public class FastImageRequestListener implements RequestListener<Drawable> {
98
99
  event.putInt("width", size[0]);
99
100
  event.putInt("height", size[1]);
100
101
  FastImageEvents.send(view, REACT_ON_LOAD_EVENT, event);
101
- FastImageEvents.send(view, REACT_ON_LOAD_END_EVENT);
102
+ FastImageEvents.sendLoadEnd(view, size[0], size[1]);
102
103
  }
103
104
  }
@@ -1,7 +1,6 @@
1
1
  package com.dylanvann.fastimage;
2
2
 
3
3
  import static com.dylanvann.fastimage.FastImageRequestListener.REACT_ON_ERROR_EVENT;
4
- import static com.dylanvann.fastimage.FastImageRequestListener.REACT_ON_LOAD_END_EVENT;
5
4
 
6
5
  import android.annotation.SuppressLint;
7
6
  import android.content.Context;
@@ -376,10 +375,11 @@ class FastImageViewWithUrl extends AppCompatImageView {
376
375
  // resolved: fire onError and onLoadEnd and show defaultSource, as on iOS
377
376
  // (#1028, #945).
378
377
  if (mSource != null && (imageSource == null || imageSource.getUri().toString().length() == 0)) {
378
+ String error = "Invalid source: " + mSource;
379
379
  WritableMap event = new WritableNativeMap();
380
- event.putString("error", "Invalid source: " + mSource);
380
+ event.putString("error", error);
381
381
  FastImageEvents.send(this, REACT_ON_ERROR_EVENT, event);
382
- FastImageEvents.send(this, REACT_ON_LOAD_END_EVENT);
382
+ FastImageEvents.sendLoadEnd(this, error);
383
383
 
384
384
  // Cancel existing requests.
385
385
  clearView(requestManager);
package/dist/index.cjs.js CHANGED
@@ -73,12 +73,24 @@ function loopCount(loop) {
73
73
  if (loop === false) return 1;
74
74
  return Number.isFinite(loop) ? Math.max(1, Math.floor(loop)) : 0;
75
75
  }
76
+ function loadResult(event) {
77
+ var _event$width, _event$height, _event$error;
78
+ return event.ok ? {
79
+ ok: true,
80
+ width: (_event$width = event.width) !== null && _event$width !== void 0 ? _event$width : 0,
81
+ height: (_event$height = event.height) !== null && _event$height !== void 0 ? _event$height : 0
82
+ } : {
83
+ ok: false,
84
+ error: (_event$error = event.error) !== null && _event$error !== void 0 ? _event$error : "Failed to load the image"
85
+ };
86
+ }
76
87
  function withoutCache(source) {
77
88
  const { cache: _cache, ...rest } = source || {};
78
89
  return rest;
79
90
  }
80
91
  function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgress, onLoad, onError, onLoadEnd, style, fallback, children, resizeMode = "cover", loop, forwardedRef, onLayout, pointerEvents, ...viewProps }) {
81
92
  const { onClick, ...props } = viewProps;
93
+ const fallbackResult = (0, react.useRef)(void 0);
82
94
  const wrapperProps = {
83
95
  onLayout,
84
96
  onClick,
@@ -103,9 +115,29 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
103
115
  defaultSource,
104
116
  onLoadStart,
105
117
  onProgress,
106
- onLoad,
107
- onError,
108
- onLoadEnd,
118
+ onLoad: onLoadEnd ? (event) => {
119
+ const { width, height } = event.nativeEvent.source;
120
+ fallbackResult.current = {
121
+ ok: true,
122
+ width,
123
+ height
124
+ };
125
+ onLoad === null || onLoad === void 0 || onLoad(event);
126
+ } : onLoad,
127
+ onError: onLoadEnd ? (event) => {
128
+ fallbackResult.current = {
129
+ ok: false,
130
+ error: String(event.nativeEvent.error)
131
+ };
132
+ onError === null || onError === void 0 || onError(event);
133
+ } : onError,
134
+ onLoadEnd: onLoadEnd && (() => {
135
+ var _fallbackResult$curre;
136
+ return onLoadEnd((_fallbackResult$curre = fallbackResult.current) !== null && _fallbackResult$curre !== void 0 ? _fallbackResult$curre : {
137
+ ok: false,
138
+ error: "Failed to load the image"
139
+ });
140
+ }),
109
141
  resizeMode
110
142
  }), children);
111
143
  }
@@ -126,7 +158,7 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
126
158
  onFastImageProgress: onProgress,
127
159
  onFastImageLoad: onLoad,
128
160
  onFastImageError: onError,
129
- onFastImageLoadEnd: onLoadEnd,
161
+ onFastImageLoadEnd: onLoadEnd && ((event) => onLoadEnd(loadResult(event.nativeEvent))),
130
162
  resizeMode
131
163
  }), children);
132
164
  }
@@ -49,6 +49,10 @@ export type ResizeModes = $Values<ResizeMode>
49
49
  export type Priorities = $Values<Priority>
50
50
  export type CacheControls = $Values<CacheControl>
51
51
 
52
+ export type LoadResult =
53
+ | {| ok: true, width: number, height: number |}
54
+ | {| ok: false, error: string |}
55
+
52
56
  export type PreloadSuccess = {|
53
57
  uri: string,
54
58
  ok: true,
@@ -78,7 +82,7 @@ export type FastImageProps = $ReadOnly<{|
78
82
  ...ViewProps,
79
83
  onError?: ?(event: OnErrorEvent) => void,
80
84
  onLoad?: ?(event: OnLoadEvent) => void,
81
- onLoadEnd?: ?() => void,
85
+ onLoadEnd?: ?(result: LoadResult) => void,
82
86
  onLoadStart?: ?() => void,
83
87
  onProgress?: ?(event: OnProgressEvent) => void,
84
88
 
package/dist/index.d.ts CHANGED
@@ -40,6 +40,14 @@ export interface OnErrorEvent {
40
40
  error: string;
41
41
  };
42
42
  }
43
+ export type LoadResult = {
44
+ ok: true;
45
+ width: number;
46
+ height: number;
47
+ } | {
48
+ ok: false;
49
+ error: string;
50
+ };
43
51
  export interface OnProgressEvent {
44
52
  nativeEvent: {
45
53
  loaded: number;
@@ -105,7 +113,11 @@ export interface FastImageProps extends AccessibilityProps, ViewProps {
105
113
  onProgress?(event: OnProgressEvent): void;
106
114
  onLoad?(event: OnLoadEvent): void;
107
115
  onError?(event: OnErrorEvent): void;
108
- onLoadEnd?(): void;
116
+ /**
117
+ * Called once the image has loaded or failed to, with the result: `ok` and
118
+ * the image's size, or not `ok` and the error.
119
+ */
120
+ onLoadEnd?(result: LoadResult): void;
109
121
  /**
110
122
  * onLayout function
111
123
  *
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import React, { forwardRef, memo } from "react";
1
+ import React, { forwardRef, memo, useRef } from "react";
2
2
  import { Image, NativeModules, Platform, StyleSheet, View, requireNativeComponent } from "react-native";
3
3
  //#region src/index.tsx
4
4
  const resizeMode = {
@@ -46,12 +46,24 @@ function loopCount(loop) {
46
46
  if (loop === false) return 1;
47
47
  return Number.isFinite(loop) ? Math.max(1, Math.floor(loop)) : 0;
48
48
  }
49
+ function loadResult(event) {
50
+ var _event$width, _event$height, _event$error;
51
+ return event.ok ? {
52
+ ok: true,
53
+ width: (_event$width = event.width) !== null && _event$width !== void 0 ? _event$width : 0,
54
+ height: (_event$height = event.height) !== null && _event$height !== void 0 ? _event$height : 0
55
+ } : {
56
+ ok: false,
57
+ error: (_event$error = event.error) !== null && _event$error !== void 0 ? _event$error : "Failed to load the image"
58
+ };
59
+ }
49
60
  function withoutCache(source) {
50
61
  const { cache: _cache, ...rest } = source || {};
51
62
  return rest;
52
63
  }
53
64
  function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgress, onLoad, onError, onLoadEnd, style, fallback, children, resizeMode = "cover", loop, forwardedRef, onLayout, pointerEvents, ...viewProps }) {
54
65
  const { onClick, ...props } = viewProps;
66
+ const fallbackResult = useRef(void 0);
55
67
  const wrapperProps = {
56
68
  onLayout,
57
69
  onClick,
@@ -76,9 +88,29 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
76
88
  defaultSource,
77
89
  onLoadStart,
78
90
  onProgress,
79
- onLoad,
80
- onError,
81
- onLoadEnd,
91
+ onLoad: onLoadEnd ? (event) => {
92
+ const { width, height } = event.nativeEvent.source;
93
+ fallbackResult.current = {
94
+ ok: true,
95
+ width,
96
+ height
97
+ };
98
+ onLoad === null || onLoad === void 0 || onLoad(event);
99
+ } : onLoad,
100
+ onError: onLoadEnd ? (event) => {
101
+ fallbackResult.current = {
102
+ ok: false,
103
+ error: String(event.nativeEvent.error)
104
+ };
105
+ onError === null || onError === void 0 || onError(event);
106
+ } : onError,
107
+ onLoadEnd: onLoadEnd && (() => {
108
+ var _fallbackResult$curre;
109
+ return onLoadEnd((_fallbackResult$curre = fallbackResult.current) !== null && _fallbackResult$curre !== void 0 ? _fallbackResult$curre : {
110
+ ok: false,
111
+ error: "Failed to load the image"
112
+ });
113
+ }),
82
114
  resizeMode
83
115
  }), children);
84
116
  }
@@ -99,7 +131,7 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
99
131
  onFastImageProgress: onProgress,
100
132
  onFastImageLoad: onLoad,
101
133
  onFastImageError: onError,
102
- onFastImageLoadEnd: onLoadEnd,
134
+ onFastImageLoadEnd: onLoadEnd && ((event) => onLoadEnd(loadResult(event.nativeEvent))),
103
135
  resizeMode
104
136
  }), children);
105
137
  }
@@ -49,6 +49,10 @@ export type ResizeModes = $Values<ResizeMode>
49
49
  export type Priorities = $Values<Priority>
50
50
  export type CacheControls = $Values<CacheControl>
51
51
 
52
+ export type LoadResult =
53
+ | {| ok: true, width: number, height: number |}
54
+ | {| ok: false, error: string |}
55
+
52
56
  export type PreloadSuccess = {|
53
57
  uri: string,
54
58
  ok: true,
@@ -78,7 +82,7 @@ export type FastImageProps = $ReadOnly<{|
78
82
  ...ViewProps,
79
83
  onError?: ?(event: OnErrorEvent) => void,
80
84
  onLoad?: ?(event: OnLoadEvent) => void,
81
- onLoadEnd?: ?() => void,
85
+ onLoadEnd?: ?(result: LoadResult) => void,
82
86
  onLoadStart?: ?() => void,
83
87
  onProgress?: ?(event: OnProgressEvent) => void,
84
88
 
@@ -161,7 +161,7 @@ static CFTimeInterval FFFEnteredBackgroundAt = 0;
161
161
  - (void) setOnFastImageLoadEnd: (RCTDirectEventBlock)onFastImageLoadEnd {
162
162
  _onFastImageLoadEnd = onFastImageLoadEnd;
163
163
  if (self.hasCompleted && _onFastImageLoadEnd) {
164
- _onFastImageLoadEnd(@{});
164
+ _onFastImageLoadEnd([self loadEndEvent: YES]);
165
165
  }
166
166
  }
167
167
 
@@ -284,6 +284,14 @@ NSString *FFFErrorMessage(NSError *error)
284
284
  }
285
285
  }
286
286
 
287
+ // onLoadEnd's event: the load's result, as onLoad or onError sent it (ok: its
288
+ // size, or not ok: the error).
289
+ - (NSDictionary*) loadEndEvent: (BOOL)ok {
290
+ NSMutableDictionary* event = [NSMutableDictionary dictionaryWithDictionary: (ok ? self.onLoadEvent : self.onErrorEvent) ?: @{}];
291
+ event[@"ok"] = @(ok);
292
+ return event;
293
+ }
294
+
287
295
  - (void) setSource: (FFFastImageSource*)source {
288
296
  if (_source != source) {
289
297
  _source = source;
@@ -429,7 +437,7 @@ NSString *FFFErrorMessage(NSError *error)
429
437
  self.showsLoadedImage = NO;
430
438
  [self sendOnError: @"Failed to decode the image"];
431
439
  if (self.onFastImageLoadEnd) {
432
- self.onFastImageLoadEnd(@{});
440
+ self.onFastImageLoadEnd([self loadEndEvent: NO]);
433
441
  }
434
442
  return;
435
443
  }
@@ -445,7 +453,7 @@ NSString *FFFErrorMessage(NSError *error)
445
453
  [self sendOnLoad: image];
446
454
 
447
455
  if (self.onFastImageLoadEnd) {
448
- self.onFastImageLoadEnd(@{});
456
+ self.onFastImageLoadEnd([self loadEndEvent: YES]);
449
457
  }
450
458
  return;
451
459
  }
@@ -621,14 +629,14 @@ NSString *FFFErrorMessage(NSError *error)
621
629
  weakSelf.showsLoadedImage = NO;
622
630
  [weakSelf sendOnError: FFFErrorMessage(error)];
623
631
  if (weakSelf.onFastImageLoadEnd) {
624
- weakSelf.onFastImageLoadEnd(@{});
632
+ weakSelf.onFastImageLoadEnd([weakSelf loadEndEvent: NO]);
625
633
  }
626
634
  } else {
627
635
  weakSelf.hasCompleted = YES;
628
636
  weakSelf.showsLoadedImage = YES;
629
637
  [weakSelf sendOnLoad: image];
630
638
  if (weakSelf.onFastImageLoadEnd) {
631
- weakSelf.onFastImageLoadEnd(@{});
639
+ weakSelf.onFastImageLoadEnd([weakSelf loadEndEvent: YES]);
632
640
  }
633
641
  }
634
642
  }];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-fast-image",
3
- "version": "8.14.0",
3
+ "version": "8.15.0",
4
4
  "description": "🚩 FastImage, performant React Native image component.",
5
5
  "keywords": [
6
6
  "cache",