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 +7 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageOkHttpProgressGlideModule.java +1 -1
- package/android/src/main/java/com/dylanvann/fastimage/FastImageRequestListener.java +1 -2
- package/android/src/main/java/com/dylanvann/fastimage/FastImageSource.java +1 -1
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewConverter.java +17 -22
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java +28 -93
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewModule.java +3 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewPackage.java +6 -2
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java +144 -0
- package/dist/index.cjs.js +28 -4
- package/dist/index.cjs.js.flow +2 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -5
- package/dist/index.js.flow +2 -1
- package/ios/FastImage/FFFastImageView.h +1 -0
- package/ios/FastImage/FFFastImageView.m +90 -82
- package/ios/FastImage/FFFastImageViewManager.m +1 -0
- package/package.json +2 -2
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).
|
package/android/src/main/java/com/dylanvann/fastimage/FastImageOkHttpProgressGlideModule.java
CHANGED
|
@@ -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
|
|
63
|
-
|
|
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
|
-
|
|
94
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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(
|
|
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.
|
|
173
|
+
return activity.isFinishing() || activity.isChangingConfigurations();
|
|
239
174
|
}
|
|
240
175
|
|
|
241
176
|
}
|
|
242
177
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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 =>
|
|
120
|
+
FastImage.preload = sources => reactNative.NativeModules.FastImageView.preload(sources);
|
|
97
121
|
|
|
98
|
-
FastImage.clearMemoryCache = () =>
|
|
122
|
+
FastImage.clearMemoryCache = () => reactNative.NativeModules.FastImageView.clearMemoryCache();
|
|
99
123
|
|
|
100
|
-
FastImage.clearDiskCache = () =>
|
|
124
|
+
FastImage.clearDiskCache = () => reactNative.NativeModules.FastImageView.clearDiskCache();
|
|
101
125
|
|
|
102
126
|
const styles = reactNative.StyleSheet.create({
|
|
103
127
|
imageContainer: {
|
package/dist/index.cjs.js.flow
CHANGED
|
@@ -56,7 +56,8 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
56
56
|
onLoadStart?: ?() => void,
|
|
57
57
|
onProgress?: ?(event: OnProgressEvent) => void,
|
|
58
58
|
|
|
59
|
-
source
|
|
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
|
|
57
|
+
source?: Source | ImageRequireSource;
|
|
58
|
+
defaultSource?: ImageRequireSource;
|
|
58
59
|
resizeMode?: ResizeMode;
|
|
59
60
|
fallback?: boolean;
|
|
60
61
|
onLoadStart?(): void;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAA;AAC/C,OAAO,EAMH,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,SAAS,EACZ,MAAM,cAAc,CAAA;
|
|
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 =>
|
|
113
|
+
FastImage.preload = sources => NativeModules.FastImageView.preload(sources);
|
|
90
114
|
|
|
91
|
-
FastImage.clearMemoryCache = () =>
|
|
115
|
+
FastImage.clearMemoryCache = () => NativeModules.FastImageView.clearMemoryCache();
|
|
92
116
|
|
|
93
|
-
FastImage.clearDiskCache = () =>
|
|
117
|
+
FastImage.clearDiskCache = () => NativeModules.FastImageView.clearDiskCache();
|
|
94
118
|
|
|
95
119
|
const styles = StyleSheet.create({
|
|
96
120
|
imageContainer: {
|
package/dist/index.js.flow
CHANGED
|
@@ -56,7 +56,8 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
56
56
|
onLoadStart?: ?() => void,
|
|
57
57
|
onProgress?: ?(event: OnProgressEvent) => void,
|
|
58
58
|
|
|
59
|
-
source
|
|
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
|
|
8
|
-
@property
|
|
9
|
-
@property
|
|
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
|
|
11
|
+
@property(nonatomic, assign) BOOL needsReload;
|
|
12
12
|
|
|
13
|
-
@property
|
|
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
|
|
65
|
+
- (void) setImageColor: (UIColor*)imageColor {
|
|
66
66
|
if (imageColor != nil) {
|
|
67
67
|
_imageColor = imageColor;
|
|
68
|
-
|
|
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
|
|
73
|
-
UIImage
|
|
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
|
|
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
|
|
92
|
+
- (void) sendOnLoad: (UIImage*)image {
|
|
91
93
|
self.onLoadEvent = @{
|
|
92
|
-
|
|
93
|
-
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
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
|
-
|
|
135
|
-
|
|
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
|
|
149
|
-
SDWebImageDownloaderRequestModifier
|
|
150
|
-
NSMutableURLRequest
|
|
151
|
-
for (NSString
|
|
152
|
-
NSString
|
|
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
|
|
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
|
|
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:
|
|
201
|
-
options:options
|
|
202
|
-
context:context
|
|
203
|
-
progress
|
|
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
|
-
|
|
207
|
-
|
|
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.
|
|
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.
|
|
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",
|