react-native-fast-image 9.3.6 → 9.4.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/android/src/main/java/com/dylanvann/fastimage/FastImageViewConverter.java +10 -8
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java +14 -7
- package/dist/index.cjs.js +24 -2
- package/dist/index.cjs.js.flow +10 -1
- package/dist/index.cjs.web.js.flow +10 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +24 -2
- package/dist/index.js.flow +10 -1
- package/dist/index.web.js.flow +10 -1
- package/dist/reactNativeCache.d.ts +4 -0
- package/ios/FastImage/RCTConvert+FFFastImage.m +3 -0
- package/package.json +1 -1
|
@@ -16,7 +16,6 @@ import com.bumptech.glide.load.model.LazyHeaders;
|
|
|
16
16
|
import com.bumptech.glide.request.RequestOptions;
|
|
17
17
|
import com.bumptech.glide.signature.ApplicationVersionSignature;
|
|
18
18
|
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
|
19
|
-
import com.facebook.react.bridge.NoSuchKeyException;
|
|
20
19
|
import com.facebook.react.bridge.ReadableMap;
|
|
21
20
|
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
|
22
21
|
import com.facebook.react.bridge.ReadableType;
|
|
@@ -34,6 +33,10 @@ class FastImageViewConverter {
|
|
|
34
33
|
put("immutable", FastImageCacheControl.IMMUTABLE);
|
|
35
34
|
put("web", FastImageCacheControl.WEB);
|
|
36
35
|
put("cacheOnly", FastImageCacheControl.CACHE_ONLY);
|
|
36
|
+
// React Native's ImageURISource value, which views take. Its
|
|
37
|
+
// others (e.g. 'reload') are immutable, as any value this map
|
|
38
|
+
// doesn't have (see getValueFromSource).
|
|
39
|
+
put("only-if-cached", FastImageCacheControl.CACHE_ONLY);
|
|
37
40
|
}};
|
|
38
41
|
|
|
39
42
|
private static final Map<String, Priority> FAST_IMAGE_PRIORITY_MAP =
|
|
@@ -174,13 +177,12 @@ class FastImageViewConverter {
|
|
|
174
177
|
return value;
|
|
175
178
|
}
|
|
176
179
|
|
|
180
|
+
// A value the map doesn't have (e.g. React Native's `cache: 'reload'`, or
|
|
181
|
+
// one that isn't a string) gets the default, as on iOS.
|
|
177
182
|
private static <T> T getValueFromSource(String propName, String defaultProp, Map<String, T> map, ReadableMap source) {
|
|
178
|
-
String
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
propValue = null;
|
|
183
|
-
}
|
|
184
|
-
return getValue(propName, defaultProp, map, propValue);
|
|
183
|
+
T value = source != null && source.hasKey(propName) && source.getType(propName) == ReadableType.String
|
|
184
|
+
? map.get(source.getString(propName))
|
|
185
|
+
: null;
|
|
186
|
+
return value != null ? value : map.get(defaultProp);
|
|
185
187
|
}
|
|
186
188
|
}
|
|
@@ -780,13 +780,15 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
780
780
|
private ScaleType mLayoutScaleType = ScaleType.FIT_CENTER;
|
|
781
781
|
|
|
782
782
|
// Glide crops or fits the bitmap for the scale type when it loads, so a
|
|
783
|
-
// new resizeMode needs a reload to take effect (#762)
|
|
783
|
+
// new resizeMode needs a reload to take effect (#762): the image that's
|
|
784
|
+
// showing, loaded again quietly (see reblur), as for a new blurRadius,
|
|
785
|
+
// without the load events, as on iOS.
|
|
784
786
|
public void setResizeMode(ScaleType scaleType, boolean repeat, boolean inPixels) {
|
|
785
787
|
if (scaleType == mResizeScaleType && repeat == mRepeat && inPixels == mInPixels) return;
|
|
786
788
|
mResizeScaleType = scaleType;
|
|
787
789
|
mInPixels = inPixels;
|
|
788
790
|
mRepeat = repeat;
|
|
789
|
-
|
|
791
|
+
mFitChanged = true;
|
|
790
792
|
// A loaded image on screen was cropped or fitted for the old scale
|
|
791
793
|
// type: it keeps its layout until the image for the new one is ready
|
|
792
794
|
// (onImageLoaded), or the load fails. Laid out for the new one, a
|
|
@@ -946,6 +948,8 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
946
948
|
// reblur for a change).
|
|
947
949
|
private float mBlurRadius = 0;
|
|
948
950
|
private boolean mBlurChanged = false;
|
|
951
|
+
// resizeMode or objectFit changed (setResizeMode).
|
|
952
|
+
private boolean mFitChanged = false;
|
|
949
953
|
|
|
950
954
|
public void setBlurRadius(float blurRadius) {
|
|
951
955
|
if (blurRadius == mBlurRadius) return;
|
|
@@ -1123,10 +1127,11 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
1123
1127
|
into(shown, builder, meanwhile, true);
|
|
1124
1128
|
}
|
|
1125
1129
|
|
|
1126
|
-
// blurRadius changed, and nothing else that needs a reload:
|
|
1127
|
-
// that's showing, blurred again, with no events, as
|
|
1128
|
-
// decoded again from the cache and blurred
|
|
1129
|
-
//
|
|
1130
|
+
// blurRadius or resizeMode changed, and nothing else that needs a reload:
|
|
1131
|
+
// the image that's showing, blurred or fitted again, with no events, as
|
|
1132
|
+
// reloadForSize does: it's decoded again from the cache and blurred or
|
|
1133
|
+
// fitted on Glide's threads, and the view keeps the current image (and its
|
|
1134
|
+
// layout, see onImageLoaded) until then. If that fails, it shows the image
|
|
1130
1135
|
// from Glide's caches; cache: 'web' skips them, so the view shows
|
|
1131
1136
|
// defaultSource (or nothing) then. Also while it's loading again that way
|
|
1132
1137
|
// (e.g. the blur changes every frame): that load is replaced. A load that
|
|
@@ -1240,8 +1245,9 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
1240
1245
|
@Nullable RequestManager requestManager) {
|
|
1241
1246
|
if (mDropped) return;
|
|
1242
1247
|
mManager = manager;
|
|
1243
|
-
if (mBlurChanged && !mNeedsReload) {
|
|
1248
|
+
if ((mBlurChanged || mFitChanged) && !mNeedsReload) {
|
|
1244
1249
|
mBlurChanged = false;
|
|
1250
|
+
mFitChanged = false;
|
|
1245
1251
|
reblur();
|
|
1246
1252
|
}
|
|
1247
1253
|
if (!mNeedsReload)
|
|
@@ -1272,6 +1278,7 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
1272
1278
|
// defaultSource, resizeMode), not for every prop update.
|
|
1273
1279
|
mNeedsReload = false;
|
|
1274
1280
|
mBlurChanged = false;
|
|
1281
|
+
mFitChanged = false;
|
|
1275
1282
|
boolean switching = mSwitchesSource;
|
|
1276
1283
|
mSwitchesSource = false;
|
|
1277
1284
|
boolean restarting = mRestarting;
|
package/dist/index.cjs.js
CHANGED
|
@@ -82,6 +82,24 @@ function resolveObjectFit(objectFit, style, resizeMode) {
|
|
|
82
82
|
return (_RESIZE_MODE_FIT$resi = RESIZE_MODE_FIT[resizeMode]) !== null && _RESIZE_MODE_FIT$resi !== void 0 ? _RESIZE_MODE_FIT$resi : "cover";
|
|
83
83
|
}
|
|
84
84
|
//#endregion
|
|
85
|
+
//#region src/reactNativeCache.ts
|
|
86
|
+
const REACT_NATIVE_CACHE = [
|
|
87
|
+
"default",
|
|
88
|
+
"reload",
|
|
89
|
+
"force-cache",
|
|
90
|
+
"only-if-cached"
|
|
91
|
+
];
|
|
92
|
+
const isReactNativeCache = (cache) => REACT_NATIVE_CACHE.includes(cache);
|
|
93
|
+
let warnedReload = false;
|
|
94
|
+
function warnIfReload(source) {
|
|
95
|
+
if (warnedReload || typeof __DEV__ === "undefined" || !__DEV__) return;
|
|
96
|
+
for (const entry of Array.isArray(source) ? source : [source]) if ((entry === null || entry === void 0 ? void 0 : entry.cache) === "reload") {
|
|
97
|
+
warnedReload = true;
|
|
98
|
+
console.warn("react-native-fast-image: `cache: 'reload'` loads the image as the default, `'immutable'`: it isn't loaded again each time. For an image that changes at the same url, use `cache: 'web'` (it follows the server's cache headers), or change its `cacheKey`.");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
85
103
|
//#region src/index.tsx
|
|
86
104
|
const resolveDefaultSource = (defaultSource) => {
|
|
87
105
|
if (!defaultSource) return null;
|
|
@@ -139,8 +157,11 @@ function transitionProps(transition) {
|
|
|
139
157
|
};
|
|
140
158
|
}
|
|
141
159
|
function withoutCache(source) {
|
|
142
|
-
const { cache
|
|
143
|
-
return
|
|
160
|
+
const { cache, ...rest } = source || {};
|
|
161
|
+
return isReactNativeCache(cache) ? {
|
|
162
|
+
...rest,
|
|
163
|
+
cache
|
|
164
|
+
} : rest;
|
|
144
165
|
}
|
|
145
166
|
function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgress, onLoad, onError, onLoadEnd, style, fallback, children, objectFit, resizeMode = "cover", loop, transition, forwardedRef, onLayout, pointerEvents, hitSlop, onStartShouldSetResponder, onStartShouldSetResponderCapture, onMoveShouldSetResponder, onMoveShouldSetResponderCapture, onResponderGrant, onResponderReject, onResponderStart, onResponderMove, onResponderEnd, onResponderRelease, onResponderTerminationRequest, onResponderTerminate, onTouchStart, onTouchMove, onTouchEnd, onTouchCancel, onTouchEndCapture, ...viewProps }) {
|
|
146
167
|
const { onClick, ...props } = viewProps;
|
|
@@ -214,6 +235,7 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
|
|
|
214
235
|
resizeMode: mode === "none" || mode === "scale-down" ? "center" : mode
|
|
215
236
|
}), children);
|
|
216
237
|
}
|
|
238
|
+
warnIfReload(source);
|
|
217
239
|
const sources = Array.isArray(source) ? source.length === 1 ? void 0 : source : void 0;
|
|
218
240
|
const single = Array.isArray(source) ? source[0] : source;
|
|
219
241
|
const resolvedSource = sources ? void 0 : react_native.Image.resolveAssetSource(single);
|
package/dist/index.cjs.js.flow
CHANGED
|
@@ -112,6 +112,15 @@ export type FastImageSource = {
|
|
|
112
112
|
scale?: number,
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
// React Native's ImageURISource cache values, which the views' `source` takes
|
|
116
|
+
// so a React Native source works as it is: native reads 'only-if-cached' as
|
|
117
|
+
// 'cacheOnly', and the others as the default, 'immutable'.
|
|
118
|
+
type ReactNativeCache = 'default' | 'reload' | 'force-cache' | 'only-if-cached'
|
|
119
|
+
type ViewSource = {
|
|
120
|
+
...FastImageSource,
|
|
121
|
+
cache?: CacheControls | ReactNativeCache,
|
|
122
|
+
}
|
|
123
|
+
|
|
115
124
|
export type FastImageProps = $ReadOnly<{|
|
|
116
125
|
...ViewProps,
|
|
117
126
|
onError?: ?(event: OnErrorEvent) => void,
|
|
@@ -120,7 +129,7 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
120
129
|
onLoadStart?: ?() => void,
|
|
121
130
|
onProgress?: ?(event: OnProgressEvent) => void,
|
|
122
131
|
|
|
123
|
-
source?: ?(
|
|
132
|
+
source?: ?(ViewSource | Array<ViewSource> | number),
|
|
124
133
|
defaultSource?: ?number,
|
|
125
134
|
|
|
126
135
|
tintColor?: number | string,
|
|
@@ -112,6 +112,15 @@ export type FastImageSource = {
|
|
|
112
112
|
scale?: number,
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
// React Native's ImageURISource cache values, which the views' `source` takes
|
|
116
|
+
// so a React Native source works as it is: native reads 'only-if-cached' as
|
|
117
|
+
// 'cacheOnly', and the others as the default, 'immutable'.
|
|
118
|
+
type ReactNativeCache = 'default' | 'reload' | 'force-cache' | 'only-if-cached'
|
|
119
|
+
type ViewSource = {
|
|
120
|
+
...FastImageSource,
|
|
121
|
+
cache?: CacheControls | ReactNativeCache,
|
|
122
|
+
}
|
|
123
|
+
|
|
115
124
|
export type FastImageProps = $ReadOnly<{|
|
|
116
125
|
...ViewProps,
|
|
117
126
|
onError?: ?(event: OnErrorEvent) => void,
|
|
@@ -120,7 +129,7 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
120
129
|
onLoadStart?: ?() => void,
|
|
121
130
|
onProgress?: ?(event: OnProgressEvent) => void,
|
|
122
131
|
|
|
123
|
-
source?: ?(
|
|
132
|
+
source?: ?(ViewSource | Array<ViewSource> | number),
|
|
124
133
|
defaultSource?: ?number,
|
|
125
134
|
|
|
126
135
|
tintColor?: number | string,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ColorValue, View, StyleProp, ViewStyle, ImageRequireSource, AccessibilityProps, ViewProps } from 'react-native';
|
|
3
3
|
import { cacheControl, priority, resizeMode } from './constants';
|
|
4
|
+
import { type ReactNativeCache } from './reactNativeCache';
|
|
4
5
|
/** How the image fits the view: see [`objectFit`](#objectfit). */
|
|
5
6
|
export type ObjectFit = 'fill' | 'contain' | 'cover' | 'none' | 'scale-down';
|
|
6
7
|
/** How the image fits the view: see [`resizeMode`](#resizemode). */
|
|
@@ -99,6 +100,9 @@ export type Source = {
|
|
|
99
100
|
/** With several sources, the scale `width` and `height` are multiplied by. */
|
|
100
101
|
scale?: number;
|
|
101
102
|
};
|
|
103
|
+
type ViewSource = Source | (Omit<Source, 'cache'> & {
|
|
104
|
+
cache?: ReactNativeCache;
|
|
105
|
+
});
|
|
102
106
|
/** How the image fades in: see [`transition`](#transition). */
|
|
103
107
|
export type Transition = {
|
|
104
108
|
/**
|
|
@@ -277,7 +281,7 @@ export interface FastImageProps extends AccessibilityProps, ViewProps {
|
|
|
277
281
|
* `{ ok: false, error }`.
|
|
278
282
|
* - An array of one is the same as that source.
|
|
279
283
|
*/
|
|
280
|
-
source?:
|
|
284
|
+
source?: ViewSource | ViewSource[] | ImageRequireSource;
|
|
281
285
|
/**
|
|
282
286
|
* An asset loaded with `require(...)`, shown while the first image loads,
|
|
283
287
|
* and if an image fails to load. When `source` changes, the previous image
|
package/dist/index.js
CHANGED
|
@@ -55,6 +55,24 @@ function resolveObjectFit(objectFit, style, resizeMode) {
|
|
|
55
55
|
return (_RESIZE_MODE_FIT$resi = RESIZE_MODE_FIT[resizeMode]) !== null && _RESIZE_MODE_FIT$resi !== void 0 ? _RESIZE_MODE_FIT$resi : "cover";
|
|
56
56
|
}
|
|
57
57
|
//#endregion
|
|
58
|
+
//#region src/reactNativeCache.ts
|
|
59
|
+
const REACT_NATIVE_CACHE = [
|
|
60
|
+
"default",
|
|
61
|
+
"reload",
|
|
62
|
+
"force-cache",
|
|
63
|
+
"only-if-cached"
|
|
64
|
+
];
|
|
65
|
+
const isReactNativeCache = (cache) => REACT_NATIVE_CACHE.includes(cache);
|
|
66
|
+
let warnedReload = false;
|
|
67
|
+
function warnIfReload(source) {
|
|
68
|
+
if (warnedReload || typeof __DEV__ === "undefined" || !__DEV__) return;
|
|
69
|
+
for (const entry of Array.isArray(source) ? source : [source]) if ((entry === null || entry === void 0 ? void 0 : entry.cache) === "reload") {
|
|
70
|
+
warnedReload = true;
|
|
71
|
+
console.warn("react-native-fast-image: `cache: 'reload'` loads the image as the default, `'immutable'`: it isn't loaded again each time. For an image that changes at the same url, use `cache: 'web'` (it follows the server's cache headers), or change its `cacheKey`.");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
58
76
|
//#region src/index.tsx
|
|
59
77
|
const resolveDefaultSource = (defaultSource) => {
|
|
60
78
|
if (!defaultSource) return null;
|
|
@@ -112,8 +130,11 @@ function transitionProps(transition) {
|
|
|
112
130
|
};
|
|
113
131
|
}
|
|
114
132
|
function withoutCache(source) {
|
|
115
|
-
const { cache
|
|
116
|
-
return
|
|
133
|
+
const { cache, ...rest } = source || {};
|
|
134
|
+
return isReactNativeCache(cache) ? {
|
|
135
|
+
...rest,
|
|
136
|
+
cache
|
|
137
|
+
} : rest;
|
|
117
138
|
}
|
|
118
139
|
function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgress, onLoad, onError, onLoadEnd, style, fallback, children, objectFit, resizeMode = "cover", loop, transition, forwardedRef, onLayout, pointerEvents, hitSlop, onStartShouldSetResponder, onStartShouldSetResponderCapture, onMoveShouldSetResponder, onMoveShouldSetResponderCapture, onResponderGrant, onResponderReject, onResponderStart, onResponderMove, onResponderEnd, onResponderRelease, onResponderTerminationRequest, onResponderTerminate, onTouchStart, onTouchMove, onTouchEnd, onTouchCancel, onTouchEndCapture, ...viewProps }) {
|
|
119
140
|
const { onClick, ...props } = viewProps;
|
|
@@ -187,6 +208,7 @@ function FastImageBase({ source, defaultSource, tintColor, onLoadStart, onProgre
|
|
|
187
208
|
resizeMode: mode === "none" || mode === "scale-down" ? "center" : mode
|
|
188
209
|
}), children);
|
|
189
210
|
}
|
|
211
|
+
warnIfReload(source);
|
|
190
212
|
const sources = Array.isArray(source) ? source.length === 1 ? void 0 : source : void 0;
|
|
191
213
|
const single = Array.isArray(source) ? source[0] : source;
|
|
192
214
|
const resolvedSource = sources ? void 0 : Image.resolveAssetSource(single);
|
package/dist/index.js.flow
CHANGED
|
@@ -112,6 +112,15 @@ export type FastImageSource = {
|
|
|
112
112
|
scale?: number,
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
// React Native's ImageURISource cache values, which the views' `source` takes
|
|
116
|
+
// so a React Native source works as it is: native reads 'only-if-cached' as
|
|
117
|
+
// 'cacheOnly', and the others as the default, 'immutable'.
|
|
118
|
+
type ReactNativeCache = 'default' | 'reload' | 'force-cache' | 'only-if-cached'
|
|
119
|
+
type ViewSource = {
|
|
120
|
+
...FastImageSource,
|
|
121
|
+
cache?: CacheControls | ReactNativeCache,
|
|
122
|
+
}
|
|
123
|
+
|
|
115
124
|
export type FastImageProps = $ReadOnly<{|
|
|
116
125
|
...ViewProps,
|
|
117
126
|
onError?: ?(event: OnErrorEvent) => void,
|
|
@@ -120,7 +129,7 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
120
129
|
onLoadStart?: ?() => void,
|
|
121
130
|
onProgress?: ?(event: OnProgressEvent) => void,
|
|
122
131
|
|
|
123
|
-
source?: ?(
|
|
132
|
+
source?: ?(ViewSource | Array<ViewSource> | number),
|
|
124
133
|
defaultSource?: ?number,
|
|
125
134
|
|
|
126
135
|
tintColor?: number | string,
|
package/dist/index.web.js.flow
CHANGED
|
@@ -112,6 +112,15 @@ export type FastImageSource = {
|
|
|
112
112
|
scale?: number,
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
// React Native's ImageURISource cache values, which the views' `source` takes
|
|
116
|
+
// so a React Native source works as it is: native reads 'only-if-cached' as
|
|
117
|
+
// 'cacheOnly', and the others as the default, 'immutable'.
|
|
118
|
+
type ReactNativeCache = 'default' | 'reload' | 'force-cache' | 'only-if-cached'
|
|
119
|
+
type ViewSource = {
|
|
120
|
+
...FastImageSource,
|
|
121
|
+
cache?: CacheControls | ReactNativeCache,
|
|
122
|
+
}
|
|
123
|
+
|
|
115
124
|
export type FastImageProps = $ReadOnly<{|
|
|
116
125
|
...ViewProps,
|
|
117
126
|
onError?: ?(event: OnErrorEvent) => void,
|
|
@@ -120,7 +129,7 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
120
129
|
onLoadStart?: ?() => void,
|
|
121
130
|
onProgress?: ?(event: OnProgressEvent) => void,
|
|
122
131
|
|
|
123
|
-
source?: ?(
|
|
132
|
+
source?: ?(ViewSource | Array<ViewSource> | number),
|
|
124
133
|
defaultSource?: ?number,
|
|
125
134
|
|
|
126
135
|
tintColor?: number | string,
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type ReactNativeCache = 'default' | 'reload' | 'force-cache' | 'only-if-cached';
|
|
2
|
+
export declare const isReactNativeCache: (cache: unknown) => cache is ReactNativeCache;
|
|
3
|
+
export declare function resetReloadWarning(): void;
|
|
4
|
+
export declare function warnIfReload(source: unknown): void;
|
|
@@ -24,6 +24,9 @@ RCT_ENUM_CONVERTER(FFFCacheControl, (@{
|
|
|
24
24
|
@"immutable": @(FFFCacheControlImmutable),
|
|
25
25
|
@"web": @(FFFCacheControlWeb),
|
|
26
26
|
@"cacheOnly": @(FFFCacheControlCacheOnly),
|
|
27
|
+
// React Native's ImageURISource value, which views
|
|
28
|
+
// take. Its others (e.g. 'reload') are the default.
|
|
29
|
+
@"only-if-cached": @(FFFCacheControlCacheOnly),
|
|
27
30
|
}), FFFCacheControlImmutable, integerValue);
|
|
28
31
|
|
|
29
32
|
+ (FFFastImageSource *)FFFastImageSource:(id)json {
|