react-native-fast-image 8.5.12 → 8.6.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
@@ -143,6 +143,13 @@ Headers to load the image with. e.g. `{ Authorization: 'someAuthToken' }`.
143
143
 
144
144
  ---
145
145
 
146
+ ### `defaultSource?: number`
147
+
148
+ - An asset loaded with `require(...)`.
149
+ - Note that like the built-in `Image` implementation, on Android `defaultSource` does not work in debug mode. This is due to the fact that assets are sent from the dev server, but RN's functions only know how to load it from `res`.
150
+
151
+ ---
152
+
146
153
  ### `resizeMode?: enum`
147
154
 
148
155
  - `FastImage.resizeMode.contain` - Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or less than the corresponding dimension of the view (minus padding).
@@ -32,7 +32,7 @@ import okio.Source;
32
32
  @GlideModule
33
33
  public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
34
34
 
35
- private static DispatchingProgressListener progressListener = new DispatchingProgressListener();
35
+ private static final DispatchingProgressListener progressListener = new DispatchingProgressListener();
36
36
 
37
37
  @Override
38
38
  public void registerComponents(
@@ -16,8 +16,7 @@ public class FastImageRequestListener implements RequestListener<Drawable> {
16
16
  static final String REACT_ON_ERROR_EVENT = "onFastImageError";
17
17
  static final String REACT_ON_LOAD_EVENT = "onFastImageLoad";
18
18
  static final String REACT_ON_LOAD_END_EVENT = "onFastImageLoadEnd";
19
-
20
- private String key;
19
+ private final String key;
21
20
 
22
21
  FastImageRequestListener(String key) {
23
22
  this.key = key;
@@ -17,7 +17,7 @@ public class FastImageSource extends ImageSource {
17
17
  private static final String ANDROID_RESOURCE_SCHEME = "android.resource";
18
18
  private static final String ANDROID_CONTENT_SCHEME = "content";
19
19
  private static final String LOCAL_FILE_SCHEME = "file";
20
- private Headers mHeaders;
20
+ private final Headers mHeaders;
21
21
  private Uri mUri;
22
22
 
23
23
  public static boolean isBase64Uri(Uri uri) {
@@ -1,18 +1,16 @@
1
1
  package com.dylanvann.fastimage;
2
2
 
3
+ import static com.bumptech.glide.request.RequestOptions.signatureOf;
4
+
3
5
  import android.content.Context;
4
6
  import android.graphics.Color;
5
7
  import android.graphics.drawable.ColorDrawable;
6
8
  import android.graphics.drawable.Drawable;
7
- import android.media.Image;
8
- import android.net.Uri;
9
- import android.util.Log;
10
9
  import android.widget.ImageView;
11
10
  import android.widget.ImageView.ScaleType;
12
11
 
13
12
  import com.bumptech.glide.Priority;
14
13
  import com.bumptech.glide.load.engine.DiskCacheStrategy;
15
- import com.bumptech.glide.load.model.GlideUrl;
16
14
  import com.bumptech.glide.load.model.Headers;
17
15
  import com.bumptech.glide.load.model.LazyHeaders;
18
16
  import com.bumptech.glide.request.RequestOptions;
@@ -21,18 +19,12 @@ import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
21
19
  import com.facebook.react.bridge.NoSuchKeyException;
22
20
  import com.facebook.react.bridge.ReadableMap;
23
21
  import com.facebook.react.bridge.ReadableMapKeySetIterator;
24
- import com.facebook.react.views.imagehelper.ImageSource;
25
22
 
26
- import java.io.File;
27
- import java.net.URI;
28
- import java.net.URISyntaxException;
29
23
  import java.util.HashMap;
30
24
  import java.util.Map;
31
25
 
32
26
  import javax.annotation.Nullable;
33
27
 
34
- import static com.bumptech.glide.request.RequestOptions.signatureOf;
35
-
36
28
  class FastImageViewConverter {
37
29
  private static final Drawable TRANSPARENT_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
38
30
 
@@ -57,10 +49,13 @@ class FastImageViewConverter {
57
49
  put("stretch", ScaleType.FIT_XY);
58
50
  put("center", ScaleType.CENTER_INSIDE);
59
51
  }};
60
-
52
+
61
53
  // Resolve the source uri to a file path that android understands.
62
- static FastImageSource getImageSource(Context context, ReadableMap source) {
63
- return new FastImageSource(context, source.getString("uri"), getHeaders(source));
54
+ static @Nullable
55
+ FastImageSource getImageSource(Context context, @Nullable ReadableMap source) {
56
+ return source == null
57
+ ? null
58
+ : new FastImageSource(context, source.getString("uri"), getHeaders(source));
64
59
  }
65
60
 
66
61
  static Headers getHeaders(ReadableMap source) {
@@ -90,8 +85,8 @@ class FastImageViewConverter {
90
85
  // Get cache control method.
91
86
  final FastImageCacheControl cacheControl = FastImageViewConverter.getCacheControl(source);
92
87
  DiskCacheStrategy diskCacheStrategy = DiskCacheStrategy.AUTOMATIC;
93
- Boolean onlyFromCache = false;
94
- Boolean skipMemoryCache = false;
88
+ boolean onlyFromCache = false;
89
+ boolean skipMemoryCache = false;
95
90
  switch (cacheControl) {
96
91
  case WEB:
97
92
  // If using none then OkHttp integration should be used for caching.
@@ -107,12 +102,12 @@ class FastImageViewConverter {
107
102
  }
108
103
 
109
104
  RequestOptions options = new RequestOptions()
110
- .diskCacheStrategy(diskCacheStrategy)
111
- .onlyRetrieveFromCache(onlyFromCache)
112
- .skipMemoryCache(skipMemoryCache)
113
- .priority(priority)
114
- .placeholder(TRANSPARENT_DRAWABLE);
115
-
105
+ .diskCacheStrategy(diskCacheStrategy)
106
+ .onlyRetrieveFromCache(onlyFromCache)
107
+ .skipMemoryCache(skipMemoryCache)
108
+ .priority(priority)
109
+ .placeholder(TRANSPARENT_DRAWABLE);
110
+
116
111
  if (imageSource.isResource()) {
117
112
  // Every local resource (drawable) in Android has its own unique numeric id, which are
118
113
  // generated at build time. Although these ids are unique, they are not guaranteed unique
@@ -123,7 +118,7 @@ class FastImageViewConverter {
123
118
  options = options.apply(signatureOf(ApplicationVersionSignature.obtain(context)));
124
119
  }
125
120
 
126
- return options;
121
+ return options;
127
122
  }
128
123
 
129
124
  private static FastImageCacheControl getCacheControl(ReadableMap source) {
@@ -1,15 +1,19 @@
1
1
  package com.dylanvann.fastimage;
2
2
 
3
+ import static com.dylanvann.fastimage.FastImageRequestListener.REACT_ON_ERROR_EVENT;
4
+ import static com.dylanvann.fastimage.FastImageRequestListener.REACT_ON_LOAD_END_EVENT;
5
+ import static com.dylanvann.fastimage.FastImageRequestListener.REACT_ON_LOAD_EVENT;
6
+
3
7
  import android.app.Activity;
4
8
  import android.content.Context;
5
9
  import android.content.ContextWrapper;
6
10
  import android.graphics.PorterDuff;
7
11
  import android.os.Build;
8
12
 
13
+ import androidx.annotation.NonNull;
14
+
9
15
  import com.bumptech.glide.Glide;
10
16
  import com.bumptech.glide.RequestManager;
11
- import com.bumptech.glide.load.model.GlideUrl;
12
- import com.bumptech.glide.request.Request;
13
17
  import com.facebook.react.bridge.ReadableMap;
14
18
  import com.facebook.react.bridge.WritableMap;
15
19
  import com.facebook.react.bridge.WritableNativeMap;
@@ -18,36 +22,33 @@ import com.facebook.react.uimanager.SimpleViewManager;
18
22
  import com.facebook.react.uimanager.ThemedReactContext;
19
23
  import com.facebook.react.uimanager.annotations.ReactProp;
20
24
  import com.facebook.react.uimanager.events.RCTEventEmitter;
25
+ import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper;
21
26
 
22
- import java.util.ArrayList;
23
- import java.util.Collections;
24
27
  import java.util.List;
25
28
  import java.util.Map;
26
29
  import java.util.WeakHashMap;
27
30
 
28
31
  import javax.annotation.Nullable;
29
32
 
30
- import static com.dylanvann.fastimage.FastImageRequestListener.REACT_ON_ERROR_EVENT;
31
- import static com.dylanvann.fastimage.FastImageRequestListener.REACT_ON_LOAD_END_EVENT;
32
- import static com.dylanvann.fastimage.FastImageRequestListener.REACT_ON_LOAD_EVENT;
33
-
34
33
  class FastImageViewManager extends SimpleViewManager<FastImageViewWithUrl> implements FastImageProgressListener {
35
34
 
36
- private static final String REACT_CLASS = "FastImageView";
37
- private static final String REACT_ON_LOAD_START_EVENT = "onFastImageLoadStart";
38
- private static final String REACT_ON_PROGRESS_EVENT = "onFastImageProgress";
35
+ static final String REACT_CLASS = "FastImageView";
36
+ static final String REACT_ON_LOAD_START_EVENT = "onFastImageLoadStart";
37
+ static final String REACT_ON_PROGRESS_EVENT = "onFastImageProgress";
39
38
  private static final Map<String, List<FastImageViewWithUrl>> VIEWS_FOR_URLS = new WeakHashMap<>();
40
39
 
41
40
  @Nullable
42
41
  private RequestManager requestManager = null;
43
42
 
43
+ @NonNull
44
44
  @Override
45
45
  public String getName() {
46
46
  return REACT_CLASS;
47
47
  }
48
48
 
49
+ @NonNull
49
50
  @Override
50
- protected FastImageViewWithUrl createViewInstance(ThemedReactContext reactContext) {
51
+ protected FastImageViewWithUrl createViewInstance(@NonNull ThemedReactContext reactContext) {
51
52
  if (isValidContextForGlide(reactContext)) {
52
53
  requestManager = Glide.with(reactContext);
53
54
  }
@@ -56,76 +57,15 @@ class FastImageViewManager extends SimpleViewManager<FastImageViewWithUrl> imple
56
57
  }
57
58
 
58
59
  @ReactProp(name = "source")
59
- public void setSrc(FastImageViewWithUrl view, @Nullable ReadableMap source) {
60
- if (source == null || !source.hasKey("uri") || isNullOrEmpty(source.getString("uri"))) {
61
- // Cancel existing requests.
62
- clearView(view);
63
-
64
- if (view.glideUrl != null) {
65
- FastImageOkHttpProgressGlideModule.forget(view.glideUrl.toStringUrl());
66
- }
67
- // Clear the image.
68
- view.setImageDrawable(null);
69
- return;
70
- }
71
-
72
- //final GlideUrl glideUrl = FastImageViewConverter.getGlideUrl(view.getContext(), source);
73
- final FastImageSource imageSource = FastImageViewConverter.getImageSource(view.getContext(), source);
74
- if (imageSource.getUri().toString().length() == 0) {
75
- ThemedReactContext context = (ThemedReactContext) view.getContext();
76
- RCTEventEmitter eventEmitter = context.getJSModule(RCTEventEmitter.class);
77
- int viewId = view.getId();
78
- WritableMap event = new WritableNativeMap();
79
- event.putString("message", "Invalid source prop:" + source);
80
- eventEmitter.receiveEvent(viewId, REACT_ON_ERROR_EVENT, event);
81
-
82
- // Cancel existing requests.
83
- if (requestManager != null) {
84
- requestManager.clear(view);
85
- }
86
-
87
- if (view.glideUrl != null) {
88
- FastImageOkHttpProgressGlideModule.forget(view.glideUrl.toStringUrl());
89
- }
90
- // Clear the image.
91
- view.setImageDrawable(null);
92
- return;
93
- }
94
-
95
- final GlideUrl glideUrl = imageSource.getGlideUrl();
96
-
97
- // Cancel existing request.
98
- view.glideUrl = glideUrl;
99
- clearView(view);
100
-
101
- String key = glideUrl.toStringUrl();
102
- FastImageOkHttpProgressGlideModule.expect(key, this);
103
- List<FastImageViewWithUrl> viewsForKey = VIEWS_FOR_URLS.get(key);
104
- if (viewsForKey != null && !viewsForKey.contains(view)) {
105
- viewsForKey.add(view);
106
- } else if (viewsForKey == null) {
107
- List<FastImageViewWithUrl> newViewsForKeys = new ArrayList<>(Collections.singletonList(view));
108
- VIEWS_FOR_URLS.put(key, newViewsForKeys);
109
- }
60
+ public void setSource(FastImageViewWithUrl view, @Nullable ReadableMap source) {
61
+ view.setSource(source);
62
+ }
110
63
 
111
- ThemedReactContext context = (ThemedReactContext) view.getContext();
112
- RCTEventEmitter eventEmitter = context.getJSModule(RCTEventEmitter.class);
113
- int viewId = view.getId();
114
- eventEmitter.receiveEvent(viewId, REACT_ON_LOAD_START_EVENT, new WritableNativeMap());
115
-
116
- if (requestManager != null) {
117
- requestManager
118
- // This will make this work for remote and local images. e.g.
119
- // - file:///
120
- // - content://
121
- // - res:/
122
- // - android.resource://
123
- // - data:image/png;base64
124
- .load(imageSource.getSourceForLoad())
125
- .apply(FastImageViewConverter.getOptions(context, imageSource, source))
126
- .listener(new FastImageRequestListener(key))
127
- .into(view);
128
- }
64
+ @ReactProp(name = "defaultSource")
65
+ public void setDefaultSource(FastImageViewWithUrl view, @Nullable String source) {
66
+ view.setDefaultSource(
67
+ ResourceDrawableIdHelper.getInstance()
68
+ .getResourceDrawable(view.getContext(), source));
129
69
  }
130
70
 
131
71
  @ReactProp(name = "tintColor", customType = "Color")
@@ -144,9 +84,9 @@ class FastImageViewManager extends SimpleViewManager<FastImageViewWithUrl> imple
144
84
  }
145
85
 
146
86
  @Override
147
- public void onDropViewInstance(FastImageViewWithUrl view) {
87
+ public void onDropViewInstance(@NonNull FastImageViewWithUrl view) {
148
88
  // This will cancel existing requests.
149
- clearView(view);
89
+ view.clearView(requestManager);
150
90
 
151
91
  if (view.glideUrl != null) {
152
92
  final String key = view.glideUrl.toString();
@@ -193,11 +133,6 @@ class FastImageViewManager extends SimpleViewManager<FastImageViewWithUrl> imple
193
133
  return 0.5f;
194
134
  }
195
135
 
196
- private boolean isNullOrEmpty(final String url) {
197
- return url == null || url.trim().isEmpty();
198
- }
199
-
200
-
201
136
  private static boolean isValidContextForGlide(final Context context) {
202
137
  Activity activity = getActivityFromContext(context);
203
138
 
@@ -235,14 +170,14 @@ class FastImageViewManager extends SimpleViewManager<FastImageViewWithUrl> imple
235
170
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
236
171
  return activity.isDestroyed() || activity.isFinishing();
237
172
  } else {
238
- return activity.isDestroyed() || activity.isFinishing() || activity.isChangingConfigurations();
173
+ return activity.isFinishing() || activity.isChangingConfigurations();
239
174
  }
240
175
 
241
176
  }
242
177
 
243
- private void clearView(FastImageViewWithUrl view) {
244
- if (requestManager != null && view != null && view.getTag() != null && view.getTag() instanceof Request) {
245
- requestManager.clear(view);
246
- }
178
+ @Override
179
+ protected void onAfterUpdateTransaction(@NonNull FastImageViewWithUrl view) {
180
+ super.onAfterUpdateTransaction(view);
181
+ view.onAfterUpdate(this, requestManager, VIEWS_FOR_URLS);
247
182
  }
248
183
  }
@@ -2,6 +2,8 @@ package com.dylanvann.fastimage;
2
2
 
3
3
  import android.app.Activity;
4
4
 
5
+ import androidx.annotation.NonNull;
6
+
5
7
  import com.bumptech.glide.Glide;
6
8
  import com.bumptech.glide.load.model.GlideUrl;
7
9
  import com.facebook.react.bridge.Promise;
@@ -20,6 +22,7 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
20
22
  super(reactContext);
21
23
  }
22
24
 
25
+ @NonNull
23
26
  @Override
24
27
  public String getName() {
25
28
  return REACT_CLASS;
@@ -1,5 +1,7 @@
1
1
  package com.dylanvann.fastimage;
2
2
 
3
+ import androidx.annotation.NonNull;
4
+
3
5
  import com.facebook.react.ReactPackage;
4
6
  import com.facebook.react.bridge.NativeModule;
5
7
  import com.facebook.react.bridge.ReactApplicationContext;
@@ -9,13 +11,15 @@ import java.util.Collections;
9
11
  import java.util.List;
10
12
 
11
13
  public class FastImageViewPackage implements ReactPackage {
14
+ @NonNull
12
15
  @Override
13
- public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
16
+ public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
14
17
  return Collections.<NativeModule>singletonList(new FastImageViewModule(reactContext));
15
18
  }
16
19
 
20
+ @NonNull
17
21
  @Override
18
- public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
22
+ public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
19
23
  return Collections.<ViewManager>singletonList(new FastImageViewManager());
20
24
  }
21
25
  }
@@ -1,15 +1,159 @@
1
1
  package com.dylanvann.fastimage;
2
2
 
3
+ import static com.dylanvann.fastimage.FastImageRequestListener.REACT_ON_ERROR_EVENT;
4
+
5
+ import android.annotation.SuppressLint;
3
6
  import android.content.Context;
7
+ import android.graphics.drawable.Drawable;
4
8
 
9
+ import androidx.annotation.Nullable;
5
10
  import androidx.appcompat.widget.AppCompatImageView;
6
11
 
12
+ import com.bumptech.glide.RequestBuilder;
13
+ import com.bumptech.glide.RequestManager;
7
14
  import com.bumptech.glide.load.model.GlideUrl;
15
+ import com.bumptech.glide.request.Request;
16
+ import com.facebook.react.bridge.ReadableMap;
17
+ import com.facebook.react.bridge.WritableMap;
18
+ import com.facebook.react.bridge.WritableNativeMap;
19
+ import com.facebook.react.uimanager.ThemedReactContext;
20
+ import com.facebook.react.uimanager.events.RCTEventEmitter;
21
+
22
+ import java.util.ArrayList;
23
+ import java.util.Collections;
24
+ import java.util.List;
25
+ import java.util.Map;
26
+
27
+ import javax.annotation.Nonnull;
8
28
 
9
29
  class FastImageViewWithUrl extends AppCompatImageView {
30
+ private boolean mNeedsReload = false;
31
+ private ReadableMap mSource = null;
32
+ private Drawable mDefaultSource = null;
33
+
10
34
  public GlideUrl glideUrl;
11
35
 
12
36
  public FastImageViewWithUrl(Context context) {
13
37
  super(context);
14
38
  }
39
+
40
+ public void setSource(@Nullable ReadableMap source) {
41
+ mNeedsReload = true;
42
+ mSource = source;
43
+ }
44
+
45
+ public void setDefaultSource(@Nullable Drawable source) {
46
+ mNeedsReload = true;
47
+ mDefaultSource = source;
48
+ }
49
+
50
+ private boolean isNullOrEmpty(final String url) {
51
+ return url == null || url.trim().isEmpty();
52
+ }
53
+
54
+ @SuppressLint("CheckResult")
55
+ public void onAfterUpdate(
56
+ @Nonnull FastImageViewManager manager,
57
+ @Nullable RequestManager requestManager,
58
+ @Nonnull Map<String, List<FastImageViewWithUrl>> viewsForUrlsMap) {
59
+ if (!mNeedsReload)
60
+ return;
61
+
62
+ if ((mSource == null ||
63
+ !mSource.hasKey("uri") ||
64
+ isNullOrEmpty(mSource.getString("uri"))) &&
65
+ mDefaultSource == null) {
66
+
67
+ // Cancel existing requests.
68
+ clearView(requestManager);
69
+
70
+ if (glideUrl != null) {
71
+ FastImageOkHttpProgressGlideModule.forget(glideUrl.toStringUrl());
72
+ }
73
+
74
+ // Clear the image.
75
+ setImageDrawable(null);
76
+ return;
77
+ }
78
+
79
+ //final GlideUrl glideUrl = FastImageViewConverter.getGlideUrl(view.getContext(), mSource);
80
+ final FastImageSource imageSource = FastImageViewConverter.getImageSource(getContext(), mSource);
81
+
82
+ if (imageSource != null && imageSource.getUri().toString().length() == 0) {
83
+ ThemedReactContext context = (ThemedReactContext) getContext();
84
+ RCTEventEmitter eventEmitter = context.getJSModule(RCTEventEmitter.class);
85
+ int viewId = getId();
86
+ WritableMap event = new WritableNativeMap();
87
+ event.putString("message", "Invalid source prop:" + mSource);
88
+ eventEmitter.receiveEvent(viewId, REACT_ON_ERROR_EVENT, event);
89
+
90
+ // Cancel existing requests.
91
+ clearView(requestManager);
92
+
93
+ if (glideUrl != null) {
94
+ FastImageOkHttpProgressGlideModule.forget(glideUrl.toStringUrl());
95
+ }
96
+ // Clear the image.
97
+ setImageDrawable(null);
98
+ return;
99
+ }
100
+
101
+ // `imageSource` may be null and we still continue, if `defaultSource` is not null
102
+ final GlideUrl glideUrl = imageSource == null ? null : imageSource.getGlideUrl();
103
+
104
+ // Cancel existing request.
105
+ this.glideUrl = glideUrl;
106
+ clearView(requestManager);
107
+
108
+ String key = glideUrl == null ? null : glideUrl.toStringUrl();
109
+
110
+ if (glideUrl != null) {
111
+ FastImageOkHttpProgressGlideModule.expect(key, manager);
112
+ List<FastImageViewWithUrl> viewsForKey = viewsForUrlsMap.get(key);
113
+ if (viewsForKey != null && !viewsForKey.contains(this)) {
114
+ viewsForKey.add(this);
115
+ } else if (viewsForKey == null) {
116
+ List<FastImageViewWithUrl> newViewsForKeys = new ArrayList<>(Collections.singletonList(this));
117
+ viewsForUrlsMap.put(key, newViewsForKeys);
118
+ }
119
+ }
120
+
121
+ ThemedReactContext context = (ThemedReactContext) getContext();
122
+ if (imageSource != null) {
123
+ // This is an orphan even without a load/loadend when only loading a placeholder
124
+ RCTEventEmitter eventEmitter = context.getJSModule(RCTEventEmitter.class);
125
+ int viewId = this.getId();
126
+
127
+ eventEmitter.receiveEvent(viewId,
128
+ FastImageViewManager.REACT_ON_LOAD_START_EVENT,
129
+ new WritableNativeMap());
130
+ }
131
+
132
+ if (requestManager != null) {
133
+ RequestBuilder<Drawable> builder =
134
+ requestManager
135
+ // This will make this work for remote and local images. e.g.
136
+ // - file:///
137
+ // - content://
138
+ // - res:/
139
+ // - android.resource://
140
+ // - data:image/png;base64
141
+ .load(imageSource == null ? null : imageSource.getSourceForLoad())
142
+ .apply(FastImageViewConverter
143
+ .getOptions(context, imageSource, mSource)
144
+ .placeholder(mDefaultSource) // show until loaded
145
+ .fallback(mDefaultSource)); // null will not be treated as error
146
+
147
+ if (key != null)
148
+ builder.listener(new FastImageRequestListener(key));
149
+
150
+ builder.into(this);
151
+ }
152
+ }
153
+
154
+ public void clearView(@Nullable RequestManager requestManager) {
155
+ if (requestManager != null && getTag() != null && getTag() instanceof Request) {
156
+ requestManager.clear(this);
157
+ }
158
+ }
15
159
  }
package/dist/index.cjs.js CHANGED
@@ -9,7 +9,6 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
9
9
  var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
10
10
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
11
11
 
12
- const FastImageViewNativeModule = reactNative.NativeModules.FastImageView;
13
12
  const resizeMode = {
14
13
  contain: 'contain',
15
14
  cover: 'cover',
@@ -30,8 +29,30 @@ const cacheControl = {
30
29
  cacheOnly: 'cacheOnly'
31
30
  };
32
31
 
32
+ const resolveDefaultSource = defaultSource => {
33
+ if (!defaultSource) {
34
+ return null;
35
+ }
36
+
37
+ if (reactNative.Platform.OS === 'android') {
38
+ // Android receives a URI string, and resolves into a Drawable using RN's methods.
39
+ const resolved = reactNative.Image.resolveAssetSource(defaultSource);
40
+
41
+ if (resolved) {
42
+ return resolved.uri;
43
+ }
44
+
45
+ return null;
46
+ } // iOS or other number mapped assets
47
+ // In iOS the number is passed, and bridged automatically into a UIImage
48
+
49
+
50
+ return defaultSource;
51
+ };
52
+
33
53
  function FastImageBase({
34
54
  source,
55
+ defaultSource,
35
56
  tintColor,
36
57
  onLoadStart,
37
58
  onProgress,
@@ -57,6 +78,7 @@ function FastImageBase({
57
78
  }, /*#__PURE__*/React__default['default'].createElement(reactNative.Image, _extends__default['default']({}, props, {
58
79
  style: reactNative.StyleSheet.absoluteFill,
59
80
  source: resolvedSource,
81
+ defaultSource: defaultSource,
60
82
  onLoadStart: onLoadStart,
61
83
  onProgress: onProgress,
62
84
  onLoad: onLoad,
@@ -67,6 +89,7 @@ function FastImageBase({
67
89
  }
68
90
 
69
91
  const resolvedSource = reactNative.Image.resolveAssetSource(source);
92
+ const resolvedDefaultSource = resolveDefaultSource(defaultSource);
70
93
  return /*#__PURE__*/React__default['default'].createElement(reactNative.View, {
71
94
  style: [styles.imageContainer, style],
72
95
  ref: forwardedRef
@@ -74,6 +97,7 @@ function FastImageBase({
74
97
  tintColor: tintColor,
75
98
  style: reactNative.StyleSheet.absoluteFill,
76
99
  source: resolvedSource,
100
+ defaultSource: resolvedDefaultSource,
77
101
  onFastImageLoadStart: onLoadStart,
78
102
  onFastImageProgress: onProgress,
79
103
  onFastImageLoad: onLoad,
@@ -93,11 +117,11 @@ FastImage.resizeMode = resizeMode;
93
117
  FastImage.cacheControl = cacheControl;
94
118
  FastImage.priority = priority;
95
119
 
96
- FastImage.preload = sources => FastImageViewNativeModule.preload(sources);
120
+ FastImage.preload = sources => reactNative.NativeModules.FastImageView.preload(sources);
97
121
 
98
- FastImage.clearMemoryCache = () => FastImageViewNativeModule.clearMemoryCache();
122
+ FastImage.clearMemoryCache = () => reactNative.NativeModules.FastImageView.clearMemoryCache();
99
123
 
100
- FastImage.clearDiskCache = () => FastImageViewNativeModule.clearDiskCache();
124
+ FastImage.clearDiskCache = () => reactNative.NativeModules.FastImageView.clearDiskCache();
101
125
 
102
126
  const styles = reactNative.StyleSheet.create({
103
127
  imageContainer: {
@@ -56,7 +56,8 @@ export type FastImageProps = $ReadOnly<{|
56
56
  onLoadStart?: ?() => void,
57
57
  onProgress?: ?(event: OnProgressEvent) => void,
58
58
 
59
- source: FastImageSource | number,
59
+ source?: ?(FastImageSource | number),
60
+ defaultSource?: ?number
60
61
 
61
62
  resizeMode?: ?ResizeModes,
62
63
  fallback?: ?boolean,
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { FlexStyle, LayoutChangeEvent, ShadowStyleIOS, StyleProp, TransformsStyle, AccessibilityProps, ViewProps } from 'react-native';
2
+ import { FlexStyle, LayoutChangeEvent, ShadowStyleIOS, StyleProp, TransformsStyle, ImageRequireSource, AccessibilityProps, ViewProps } from 'react-native';
3
3
  export declare type ResizeMode = 'contain' | 'cover' | 'stretch' | 'center';
4
4
  declare const resizeMode: {
5
5
  readonly contain: "contain";
@@ -54,7 +54,8 @@ export interface ImageStyle extends FlexStyle, TransformsStyle, ShadowStyleIOS {
54
54
  opacity?: number;
55
55
  }
56
56
  export interface FastImageProps extends AccessibilityProps, ViewProps {
57
- source: Source | number;
57
+ source?: Source | ImageRequireSource;
58
+ defaultSource?: ImageRequireSource;
58
59
  resizeMode?: ResizeMode;
59
60
  fallback?: boolean;
60
61
  onLoadStart?(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import _extends from '@babel/runtime/helpers/extends';
2
2
  import React, { forwardRef, memo } from 'react';
3
- import { NativeModules, StyleSheet, requireNativeComponent, Image, View } from 'react-native';
3
+ import { NativeModules, StyleSheet, requireNativeComponent, Image, View, Platform } from 'react-native';
4
4
 
5
- const FastImageViewNativeModule = NativeModules.FastImageView;
6
5
  const resizeMode = {
7
6
  contain: 'contain',
8
7
  cover: 'cover',
@@ -23,8 +22,30 @@ const cacheControl = {
23
22
  cacheOnly: 'cacheOnly'
24
23
  };
25
24
 
25
+ const resolveDefaultSource = defaultSource => {
26
+ if (!defaultSource) {
27
+ return null;
28
+ }
29
+
30
+ if (Platform.OS === 'android') {
31
+ // Android receives a URI string, and resolves into a Drawable using RN's methods.
32
+ const resolved = Image.resolveAssetSource(defaultSource);
33
+
34
+ if (resolved) {
35
+ return resolved.uri;
36
+ }
37
+
38
+ return null;
39
+ } // iOS or other number mapped assets
40
+ // In iOS the number is passed, and bridged automatically into a UIImage
41
+
42
+
43
+ return defaultSource;
44
+ };
45
+
26
46
  function FastImageBase({
27
47
  source,
48
+ defaultSource,
28
49
  tintColor,
29
50
  onLoadStart,
30
51
  onProgress,
@@ -50,6 +71,7 @@ function FastImageBase({
50
71
  }, /*#__PURE__*/React.createElement(Image, _extends({}, props, {
51
72
  style: StyleSheet.absoluteFill,
52
73
  source: resolvedSource,
74
+ defaultSource: defaultSource,
53
75
  onLoadStart: onLoadStart,
54
76
  onProgress: onProgress,
55
77
  onLoad: onLoad,
@@ -60,6 +82,7 @@ function FastImageBase({
60
82
  }
61
83
 
62
84
  const resolvedSource = Image.resolveAssetSource(source);
85
+ const resolvedDefaultSource = resolveDefaultSource(defaultSource);
63
86
  return /*#__PURE__*/React.createElement(View, {
64
87
  style: [styles.imageContainer, style],
65
88
  ref: forwardedRef
@@ -67,6 +90,7 @@ function FastImageBase({
67
90
  tintColor: tintColor,
68
91
  style: StyleSheet.absoluteFill,
69
92
  source: resolvedSource,
93
+ defaultSource: resolvedDefaultSource,
70
94
  onFastImageLoadStart: onLoadStart,
71
95
  onFastImageProgress: onProgress,
72
96
  onFastImageLoad: onLoad,
@@ -86,11 +110,11 @@ FastImage.resizeMode = resizeMode;
86
110
  FastImage.cacheControl = cacheControl;
87
111
  FastImage.priority = priority;
88
112
 
89
- FastImage.preload = sources => FastImageViewNativeModule.preload(sources);
113
+ FastImage.preload = sources => NativeModules.FastImageView.preload(sources);
90
114
 
91
- FastImage.clearMemoryCache = () => FastImageViewNativeModule.clearMemoryCache();
115
+ FastImage.clearMemoryCache = () => NativeModules.FastImageView.clearMemoryCache();
92
116
 
93
- FastImage.clearDiskCache = () => FastImageViewNativeModule.clearDiskCache();
117
+ FastImage.clearDiskCache = () => NativeModules.FastImageView.clearDiskCache();
94
118
 
95
119
  const styles = StyleSheet.create({
96
120
  imageContainer: {
@@ -56,7 +56,8 @@ export type FastImageProps = $ReadOnly<{|
56
56
  onLoadStart?: ?() => void,
57
57
  onProgress?: ?(event: OnProgressEvent) => void,
58
58
 
59
- source: FastImageSource | number,
59
+ source?: ?(FastImageSource | number),
60
+ defaultSource?: ?number
60
61
 
61
62
  resizeMode?: ?ResizeModes,
62
63
  fallback?: ?boolean,
@@ -17,6 +17,7 @@
17
17
  @property (nonatomic, copy) RCTDirectEventBlock onFastImageLoadEnd;
18
18
  @property (nonatomic, assign) RCTResizeMode resizeMode;
19
19
  @property (nonatomic, strong) FFFastImageSource *source;
20
+ @property (nonatomic, strong) UIImage *defaultSource;
20
21
  @property (nonatomic, strong) UIColor *imageColor;
21
22
 
22
23
  @end
@@ -2,15 +2,15 @@
2
2
  #import <SDWebImage/UIImage+MultiFormat.h>
3
3
  #import <SDWebImage/UIView+WebCache.h>
4
4
 
5
- @interface FFFastImageView()
5
+ @interface FFFastImageView ()
6
6
 
7
- @property (nonatomic, assign) BOOL hasSentOnLoadStart;
8
- @property (nonatomic, assign) BOOL hasCompleted;
9
- @property (nonatomic, assign) BOOL hasErrored;
7
+ @property(nonatomic, assign) BOOL hasSentOnLoadStart;
8
+ @property(nonatomic, assign) BOOL hasCompleted;
9
+ @property(nonatomic, assign) BOOL hasErrored;
10
10
  // Whether the latest change of props requires the image to be reloaded
11
- @property (nonatomic, assign) BOOL needsReload;
11
+ @property(nonatomic, assign) BOOL needsReload;
12
12
 
13
- @property (nonatomic, strong) NSDictionary* onLoadEvent;
13
+ @property(nonatomic, strong) NSDictionary* onLoadEvent;
14
14
 
15
15
  @end
16
16
 
@@ -23,35 +23,35 @@
23
23
  return self;
24
24
  }
25
25
 
26
- - (void)setResizeMode:(RCTResizeMode)resizeMode {
26
+ - (void) setResizeMode: (RCTResizeMode)resizeMode {
27
27
  if (_resizeMode != resizeMode) {
28
28
  _resizeMode = resizeMode;
29
- self.contentMode = (UIViewContentMode)resizeMode;
29
+ self.contentMode = (UIViewContentMode) resizeMode;
30
30
  }
31
31
  }
32
32
 
33
- - (void)setOnFastImageLoadEnd:(RCTDirectEventBlock)onFastImageLoadEnd {
33
+ - (void) setOnFastImageLoadEnd: (RCTDirectEventBlock)onFastImageLoadEnd {
34
34
  _onFastImageLoadEnd = onFastImageLoadEnd;
35
35
  if (self.hasCompleted) {
36
36
  _onFastImageLoadEnd(@{});
37
37
  }
38
38
  }
39
39
 
40
- - (void)setOnFastImageLoad:(RCTDirectEventBlock)onFastImageLoad {
40
+ - (void) setOnFastImageLoad: (RCTDirectEventBlock)onFastImageLoad {
41
41
  _onFastImageLoad = onFastImageLoad;
42
42
  if (self.hasCompleted) {
43
43
  _onFastImageLoad(self.onLoadEvent);
44
44
  }
45
45
  }
46
46
 
47
- - (void)setOnFastImageError:(RCTDirectEventBlock)onFastImageError {
47
+ - (void) setOnFastImageError: (RCTDirectEventBlock)onFastImageError {
48
48
  _onFastImageError = onFastImageError;
49
49
  if (self.hasErrored) {
50
50
  _onFastImageError(@{});
51
51
  }
52
52
  }
53
53
 
54
- - (void)setOnFastImageLoadStart:(RCTDirectEventBlock)onFastImageLoadStart {
54
+ - (void) setOnFastImageLoadStart: (RCTDirectEventBlock)onFastImageLoadStart {
55
55
  if (_source && !self.hasSentOnLoadStart) {
56
56
  _onFastImageLoadStart = onFastImageLoadStart;
57
57
  onFastImageLoadStart(@{});
@@ -62,100 +62,106 @@
62
62
  }
63
63
  }
64
64
 
65
- - (void)setImageColor:(UIColor *)imageColor {
65
+ - (void) setImageColor: (UIColor*)imageColor {
66
66
  if (imageColor != nil) {
67
67
  _imageColor = imageColor;
68
- super.image = [self makeImage:super.image withTint:self.imageColor];
68
+ if (super.image) {
69
+ super.image = [self makeImage: super.image withTint: self.imageColor];
70
+ }
69
71
  }
70
72
  }
71
73
 
72
- - (UIImage*)makeImage:(UIImage *)image withTint:(UIColor *)color {
73
- UIImage *newImage = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
74
+ - (UIImage*) makeImage: (UIImage*)image withTint: (UIColor*)color {
75
+ UIImage* newImage = [image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate];
74
76
  UIGraphicsBeginImageContextWithOptions(image.size, NO, newImage.scale);
75
77
  [color set];
76
- [newImage drawInRect:CGRectMake(0, 0, image.size.width, newImage.size.height)];
78
+ [newImage drawInRect: CGRectMake(0, 0, image.size.width, newImage.size.height)];
77
79
  newImage = UIGraphicsGetImageFromCurrentImageContext();
78
80
  UIGraphicsEndImageContext();
79
81
  return newImage;
80
82
  }
81
83
 
82
- - (void)setImage:(UIImage *)image {
84
+ - (void) setImage: (UIImage*)image {
83
85
  if (self.imageColor != nil) {
84
- super.image = [self makeImage:image withTint:self.imageColor];
86
+ super.image = [self makeImage: image withTint: self.imageColor];
85
87
  } else {
86
88
  super.image = image;
87
89
  }
88
90
  }
89
91
 
90
- - (void)sendOnLoad:(UIImage *)image {
92
+ - (void) sendOnLoad: (UIImage*)image {
91
93
  self.onLoadEvent = @{
92
- @"width":[NSNumber numberWithDouble:image.size.width],
93
- @"height":[NSNumber numberWithDouble:image.size.height]
94
- };
94
+ @"width": [NSNumber numberWithDouble: image.size.width],
95
+ @"height": [NSNumber numberWithDouble: image.size.height]
96
+ };
95
97
  if (self.onFastImageLoad) {
96
98
  self.onFastImageLoad(self.onLoadEvent);
97
99
  }
98
100
  }
99
101
 
100
- - (void)setSource:(FFFastImageSource *)source {
102
+ - (void) setSource: (FFFastImageSource*)source {
101
103
  if (_source != source) {
102
104
  _source = source;
103
105
  _needsReload = YES;
104
106
  }
105
107
  }
106
108
 
107
- - (void)didSetProps:(NSArray<NSString *> *)changedProps
108
- {
109
+ - (void) setDefaultSource: (UIImage*)defaultSource {
110
+ if (_defaultSource != defaultSource) {
111
+ _defaultSource = defaultSource;
112
+ _needsReload = YES;
113
+ }
114
+ }
115
+
116
+ - (void) didSetProps: (NSArray<NSString*>*)changedProps {
109
117
  if (_needsReload) {
110
118
  [self reloadImage];
111
119
  }
112
120
  }
113
121
 
114
- - (void)reloadImage
115
- {
122
+ - (void) reloadImage {
116
123
  _needsReload = NO;
117
124
 
118
125
  if (_source) {
119
-
120
126
  // Load base64 images.
121
127
  NSString* url = [_source.url absoluteString];
122
- if (url && [url hasPrefix:@"data:image"]) {
128
+ if (url && [url hasPrefix: @"data:image"]) {
123
129
  if (self.onFastImageLoadStart) {
124
130
  self.onFastImageLoadStart(@{});
125
131
  self.hasSentOnLoadStart = YES;
126
- } {
132
+ } else {
127
133
  self.hasSentOnLoadStart = NO;
128
134
  }
129
135
  // Use SDWebImage API to support external format like WebP images
130
- UIImage *image = [UIImage sd_imageWithData:[NSData dataWithContentsOfURL:_source.url]];
131
- [self setImage:image];
136
+ UIImage* image = [UIImage sd_imageWithData: [NSData dataWithContentsOfURL: _source.url]];
137
+ [self setImage: image];
132
138
  if (self.onFastImageProgress) {
133
139
  self.onFastImageProgress(@{
134
- @"loaded": @(1),
135
- @"total": @(1)
136
- });
140
+ @"loaded": @(1),
141
+ @"total": @(1)
142
+ });
137
143
  }
138
144
  self.hasCompleted = YES;
139
- [self sendOnLoad:image];
140
-
145
+ [self sendOnLoad: image];
146
+
141
147
  if (self.onFastImageLoadEnd) {
142
148
  self.onFastImageLoadEnd(@{});
143
149
  }
144
150
  return;
145
151
  }
146
-
152
+
147
153
  // Set headers.
148
- NSDictionary *headers = _source.headers;
149
- SDWebImageDownloaderRequestModifier *requestModifier = [SDWebImageDownloaderRequestModifier requestModifierWithBlock:^NSURLRequest * _Nullable(NSURLRequest * _Nonnull request) {
150
- NSMutableURLRequest *mutableRequest = [request mutableCopy];
151
- for (NSString *header in headers) {
152
- NSString *value = headers[header];
153
- [mutableRequest setValue:value forHTTPHeaderField:header];
154
+ NSDictionary* headers = _source.headers;
155
+ SDWebImageDownloaderRequestModifier* requestModifier = [SDWebImageDownloaderRequestModifier requestModifierWithBlock: ^NSURLRequest* _Nullable (NSURLRequest* _Nonnull request) {
156
+ NSMutableURLRequest* mutableRequest = [request mutableCopy];
157
+ for (NSString* header in headers) {
158
+ NSString* value = headers[header];
159
+ [mutableRequest setValue: value forHTTPHeaderField: header];
154
160
  }
155
161
  return [mutableRequest copy];
156
162
  }];
157
- SDWebImageContext *context = @{SDWebImageContextDownloadRequestModifier : requestModifier};
158
-
163
+ SDWebImageContext* context = @{SDWebImageContextDownloadRequestModifier: requestModifier};
164
+
159
165
  // Set priority.
160
166
  SDWebImageOptions options = SDWebImageRetryFailed | SDWebImageHandleCookies;
161
167
  switch (_source.priority) {
@@ -169,7 +175,7 @@
169
175
  options |= SDWebImageHighPriority;
170
176
  break;
171
177
  }
172
-
178
+
173
179
  switch (_source.cacheControl) {
174
180
  case FFFCacheControlWeb:
175
181
  options |= SDWebImageRefreshCached;
@@ -180,56 +186,58 @@
180
186
  case FFFCacheControlImmutable:
181
187
  break;
182
188
  }
183
-
189
+
184
190
  if (self.onFastImageLoadStart) {
185
191
  self.onFastImageLoadStart(@{});
186
192
  self.hasSentOnLoadStart = YES;
187
- } {
193
+ } else {
188
194
  self.hasSentOnLoadStart = NO;
189
195
  }
190
196
  self.hasCompleted = NO;
191
197
  self.hasErrored = NO;
192
-
193
- [self downloadImage:_source options:options context:context];
198
+
199
+ [self downloadImage: _source options: options context: context];
200
+ } else if (_defaultSource) {
201
+ [self setImage: _defaultSource];
194
202
  }
195
203
  }
196
204
 
197
- - (void)downloadImage:(FFFastImageSource *) source options:(SDWebImageOptions) options context:(SDWebImageContext *)context {
205
+ - (void) downloadImage: (FFFastImageSource*)source options: (SDWebImageOptions)options context: (SDWebImageContext*)context {
198
206
  __weak typeof(self) weakSelf = self; // Always use a weak reference to self in blocks
199
- [self sd_setImageWithURL:_source.url
200
- placeholderImage:nil
201
- options:options
202
- context:context
203
- progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
207
+ [self sd_setImageWithURL: _source.url
208
+ placeholderImage: _defaultSource
209
+ options: options
210
+ context: context
211
+ progress: ^(NSInteger receivedSize, NSInteger expectedSize, NSURL* _Nullable targetURL) {
204
212
  if (weakSelf.onFastImageProgress) {
205
213
  weakSelf.onFastImageProgress(@{
206
- @"loaded": @(receivedSize),
207
- @"total": @(expectedSize)
208
- });
209
- }
210
- } completed:^(UIImage * _Nullable image,
211
- NSError * _Nullable error,
212
- SDImageCacheType cacheType,
213
- NSURL * _Nullable imageURL) {
214
- if (error) {
215
- weakSelf.hasErrored = YES;
216
- if (weakSelf.onFastImageError) {
217
- weakSelf.onFastImageError(@{});
218
- }
219
- if (weakSelf.onFastImageLoadEnd) {
220
- weakSelf.onFastImageLoadEnd(@{});
221
- }
222
- } else {
223
- weakSelf.hasCompleted = YES;
224
- [weakSelf sendOnLoad:image];
225
- if (weakSelf.onFastImageLoadEnd) {
226
- weakSelf.onFastImageLoadEnd(@{});
227
- }
214
+ @"loaded": @(receivedSize),
215
+ @"total": @(expectedSize)
216
+ });
228
217
  }
229
- }];
218
+ } completed: ^(UIImage* _Nullable image,
219
+ NSError* _Nullable error,
220
+ SDImageCacheType cacheType,
221
+ NSURL* _Nullable imageURL) {
222
+ if (error) {
223
+ weakSelf.hasErrored = YES;
224
+ if (weakSelf.onFastImageError) {
225
+ weakSelf.onFastImageError(@{});
226
+ }
227
+ if (weakSelf.onFastImageLoadEnd) {
228
+ weakSelf.onFastImageLoadEnd(@{});
229
+ }
230
+ } else {
231
+ weakSelf.hasCompleted = YES;
232
+ [weakSelf sendOnLoad: image];
233
+ if (weakSelf.onFastImageLoadEnd) {
234
+ weakSelf.onFastImageLoadEnd(@{});
235
+ }
236
+ }
237
+ }];
230
238
  }
231
239
 
232
- - (void)dealloc {
240
+ - (void) dealloc {
233
241
  [self sd_cancelCurrentImageLoad];
234
242
  }
235
243
 
@@ -13,6 +13,7 @@ RCT_EXPORT_MODULE(FastImageView)
13
13
  }
14
14
 
15
15
  RCT_EXPORT_VIEW_PROPERTY(source, FFFastImageSource)
16
+ RCT_EXPORT_VIEW_PROPERTY(defaultSource, UIImage)
16
17
  RCT_EXPORT_VIEW_PROPERTY(resizeMode, RCTResizeMode)
17
18
  RCT_EXPORT_VIEW_PROPERTY(onFastImageLoadStart, RCTDirectEventBlock)
18
19
  RCT_EXPORT_VIEW_PROPERTY(onFastImageProgress, RCTDirectEventBlock)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-fast-image",
3
- "version": "8.5.12",
3
+ "version": "8.6.0",
4
4
  "description": "🚩 FastImage, performant React Native image component.",
5
5
  "keywords": [
6
6
  "cache",
@@ -64,7 +64,7 @@
64
64
  "@babel/runtime": "^7.14.6",
65
65
  "@types/jest": "^26.0.24",
66
66
  "@types/react": "^17.0.14",
67
- "@types/react-native": "^0.64.12",
67
+ "@types/react-native": "^0.69.5",
68
68
  "@types/react-test-renderer": "^17.0.1",
69
69
  "dv-scripts": "^1.6.0",
70
70
  "eslint-config-dv-scripts": "^1.1.1",