@depup/react-native-fast-image 8.6.3-depup.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/LICENSE +21 -0
- package/README.md +25 -0
- package/RNFastImage.podspec +21 -0
- package/android/build.gradle +68 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageCacheControl.java +8 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageGlideModule.java +9 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageOkHttpProgressGlideModule.java +176 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageProgressListener.java +14 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageRequestListener.java +60 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageSource.java +112 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewConverter.java +153 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java +183 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewModule.java +89 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewPackage.java +25 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java +159 -0
- package/changes.json +5 -0
- package/dist/index.cjs.js +144 -0
- package/dist/index.cjs.js.flow +75 -0
- package/dist/index.d.ts +103 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +137 -0
- package/dist/index.js.flow +75 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/ios/FastImage/FFFastImageSource.h +33 -0
- package/ios/FastImage/FFFastImageSource.m +20 -0
- package/ios/FastImage/FFFastImageView.h +24 -0
- package/ios/FastImage/FFFastImageView.m +244 -0
- package/ios/FastImage/FFFastImageViewManager.h +5 -0
- package/ios/FastImage/FFFastImageViewManager.m +52 -0
- package/ios/FastImage/RCTConvert+FFFastImage.h +9 -0
- package/ios/FastImage/RCTConvert+FFFastImage.m +53 -0
- package/ios/FastImage.xcodeproj/project.pbxproj +479 -0
- package/ios/FastImage.xcodeproj/xcshareddata/xcschemes/FastImage-tvOS.xcscheme +80 -0
- package/package.json +98 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Dylan Vann
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @depup/react-native-fast-image
|
|
2
|
+
|
|
3
|
+
> Dependency-bumped version of [react-native-fast-image](https://www.npmjs.com/package/react-native-fast-image)
|
|
4
|
+
|
|
5
|
+
Generated by [DepUp](https://github.com/depup/npm) -- all production
|
|
6
|
+
dependencies bumped to latest versions.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @depup/react-native-fast-image
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
| Field | Value |
|
|
15
|
+
|-------|-------|
|
|
16
|
+
| Original | [react-native-fast-image](https://www.npmjs.com/package/react-native-fast-image) @ 8.6.3 |
|
|
17
|
+
| Processed | 2026-03-18 |
|
|
18
|
+
| Smoke test | failed |
|
|
19
|
+
| Deps updated | 0 |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
Source: https://github.com/depup/npm | Original: https://www.npmjs.com/package/react-native-fast-image
|
|
24
|
+
|
|
25
|
+
License inherited from the original package.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
Pod::Spec.new do |s|
|
|
4
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
5
|
+
|
|
6
|
+
s.name = "RNFastImage"
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.authors = { "Dylan Vann" => "dylan@dylanvann.com" }
|
|
10
|
+
s.homepage = "https://github.com/DylanVann/react-native-fast-image#readme"
|
|
11
|
+
s.license = "MIT"
|
|
12
|
+
s.platforms = { :ios => "8.0", :tvos => "9.0" }
|
|
13
|
+
s.framework = 'UIKit'
|
|
14
|
+
s.requires_arc = true
|
|
15
|
+
s.source = { :git => "https://github.com/DylanVann/react-native-fast-image.git", :tag => "v#{s.version}" }
|
|
16
|
+
s.source_files = "ios/**/*.{h,m}"
|
|
17
|
+
|
|
18
|
+
s.dependency 'React-Core'
|
|
19
|
+
s.dependency 'SDWebImage', '~> 5.11.1'
|
|
20
|
+
s.dependency 'SDWebImageWebPCoder', '~> 0.8.4'
|
|
21
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
def safeExtGet(prop, fallback) {
|
|
2
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
buildscript {
|
|
6
|
+
// The Android Gradle plugin is only required when opening the android folder stand-alone.
|
|
7
|
+
// This avoids unnecessary downloads and potential conflicts when the library is included as a
|
|
8
|
+
// module dependency in an application project.
|
|
9
|
+
if (project == rootProject) {
|
|
10
|
+
repositories {
|
|
11
|
+
google()
|
|
12
|
+
mavenCentral()
|
|
13
|
+
}
|
|
14
|
+
dependencies {
|
|
15
|
+
classpath 'com.android.tools.build:gradle:3.5.3'
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
apply plugin: 'com.android.library'
|
|
21
|
+
|
|
22
|
+
android {
|
|
23
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 28)
|
|
24
|
+
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
|
|
25
|
+
defaultConfig {
|
|
26
|
+
minSdkVersion safeExtGet('minSdkVersion', 16)
|
|
27
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 28)
|
|
28
|
+
versionCode 1
|
|
29
|
+
versionName "1.0"
|
|
30
|
+
}
|
|
31
|
+
sourceSets {
|
|
32
|
+
main {
|
|
33
|
+
java {
|
|
34
|
+
if (safeExtGet('excludeAppGlideModule', false)) {
|
|
35
|
+
srcDir "src"
|
|
36
|
+
exclude "**/FastImageGlideModule.java"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
lintOptions {
|
|
42
|
+
abortOnError false
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
repositories {
|
|
47
|
+
mavenLocal()
|
|
48
|
+
maven {
|
|
49
|
+
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
|
50
|
+
url "$rootDir/../node_modules/react-native/android"
|
|
51
|
+
}
|
|
52
|
+
maven {
|
|
53
|
+
// Android JSC is installed from npm
|
|
54
|
+
url "$rootDir/../node_modules/jsc-android/dist"
|
|
55
|
+
}
|
|
56
|
+
google()
|
|
57
|
+
mavenCentral()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
def glideVersion = safeExtGet('glideVersion', '4.12.0')
|
|
61
|
+
|
|
62
|
+
dependencies {
|
|
63
|
+
//noinspection GradleDynamicVersion
|
|
64
|
+
implementation 'com.facebook.react:react-native:+' // From node_modules
|
|
65
|
+
implementation "com.github.bumptech.glide:glide:${glideVersion}"
|
|
66
|
+
implementation "com.github.bumptech.glide:okhttp3-integration:${glideVersion}"
|
|
67
|
+
annotationProcessor "com.github.bumptech.glide:compiler:${glideVersion}"
|
|
68
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
package com.dylanvann.fastimage;
|
|
2
|
+
|
|
3
|
+
import com.bumptech.glide.annotation.GlideModule;
|
|
4
|
+
import com.bumptech.glide.module.AppGlideModule;
|
|
5
|
+
|
|
6
|
+
// We need an AppGlideModule to be present for progress events to work.
|
|
7
|
+
@GlideModule
|
|
8
|
+
public final class FastImageGlideModule extends AppGlideModule {
|
|
9
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
package com.dylanvann.fastimage;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
import androidx.annotation.NonNull;
|
|
5
|
+
|
|
6
|
+
import com.bumptech.glide.Glide;
|
|
7
|
+
import com.bumptech.glide.Registry;
|
|
8
|
+
import com.bumptech.glide.annotation.GlideModule;
|
|
9
|
+
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
|
|
10
|
+
import com.bumptech.glide.load.model.GlideUrl;
|
|
11
|
+
import com.bumptech.glide.module.LibraryGlideModule;
|
|
12
|
+
import com.facebook.react.modules.network.OkHttpClientProvider;
|
|
13
|
+
|
|
14
|
+
import java.io.IOException;
|
|
15
|
+
import java.io.InputStream;
|
|
16
|
+
import java.util.HashMap;
|
|
17
|
+
import java.util.Map;
|
|
18
|
+
import java.util.WeakHashMap;
|
|
19
|
+
|
|
20
|
+
import okhttp3.Interceptor;
|
|
21
|
+
import okhttp3.MediaType;
|
|
22
|
+
import okhttp3.OkHttpClient;
|
|
23
|
+
import okhttp3.Request;
|
|
24
|
+
import okhttp3.Response;
|
|
25
|
+
import okhttp3.ResponseBody;
|
|
26
|
+
import okio.Buffer;
|
|
27
|
+
import okio.BufferedSource;
|
|
28
|
+
import okio.ForwardingSource;
|
|
29
|
+
import okio.Okio;
|
|
30
|
+
import okio.Source;
|
|
31
|
+
|
|
32
|
+
@GlideModule
|
|
33
|
+
public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
|
|
34
|
+
|
|
35
|
+
private static final DispatchingProgressListener progressListener = new DispatchingProgressListener();
|
|
36
|
+
|
|
37
|
+
@Override
|
|
38
|
+
public void registerComponents(
|
|
39
|
+
@NonNull Context context,
|
|
40
|
+
@NonNull Glide glide,
|
|
41
|
+
@NonNull Registry registry
|
|
42
|
+
) {
|
|
43
|
+
OkHttpClient client = OkHttpClientProvider
|
|
44
|
+
.getOkHttpClient()
|
|
45
|
+
.newBuilder()
|
|
46
|
+
.addInterceptor(createInterceptor(progressListener))
|
|
47
|
+
.build();
|
|
48
|
+
OkHttpUrlLoader.Factory factory = new OkHttpUrlLoader.Factory(client);
|
|
49
|
+
registry.replace(GlideUrl.class, InputStream.class, factory);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private static Interceptor createInterceptor(final ResponseProgressListener listener) {
|
|
53
|
+
return new Interceptor() {
|
|
54
|
+
@Override
|
|
55
|
+
public Response intercept(Chain chain) throws IOException {
|
|
56
|
+
Request request = chain.request();
|
|
57
|
+
Response response = chain.proceed(request);
|
|
58
|
+
final String key = request.url().toString();
|
|
59
|
+
return response
|
|
60
|
+
.newBuilder()
|
|
61
|
+
.body(new OkHttpProgressResponseBody(key, response.body(), listener))
|
|
62
|
+
.build();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static void forget(String key) {
|
|
68
|
+
progressListener.forget(key);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static void expect(String key, FastImageProgressListener listener) {
|
|
72
|
+
progressListener.expect(key, listener);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private interface ResponseProgressListener {
|
|
76
|
+
void update(String key, long bytesRead, long contentLength);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private static class DispatchingProgressListener implements ResponseProgressListener {
|
|
80
|
+
private final Map<String, FastImageProgressListener> LISTENERS = new WeakHashMap<>();
|
|
81
|
+
private final Map<String, Long> PROGRESSES = new HashMap<>();
|
|
82
|
+
|
|
83
|
+
void forget(String key) {
|
|
84
|
+
LISTENERS.remove(key);
|
|
85
|
+
PROGRESSES.remove(key);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
void expect(String key, FastImageProgressListener listener) {
|
|
89
|
+
LISTENERS.put(key, listener);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@Override
|
|
93
|
+
public void update(final String key, final long bytesRead, final long contentLength) {
|
|
94
|
+
final FastImageProgressListener listener = LISTENERS.get(key);
|
|
95
|
+
if (listener == null) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (contentLength <= bytesRead) {
|
|
99
|
+
forget(key);
|
|
100
|
+
}
|
|
101
|
+
if (needsDispatch(key, bytesRead, contentLength, listener.getGranularityPercentage())) {
|
|
102
|
+
listener.onProgress(key, bytesRead, contentLength);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private boolean needsDispatch(String key, long current, long total, float granularity) {
|
|
107
|
+
if (granularity == 0 || current == 0 || total == current) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
float percent = 100f * current / total;
|
|
111
|
+
long currentProgress = (long) (percent / granularity);
|
|
112
|
+
Long lastProgress = PROGRESSES.get(key);
|
|
113
|
+
if (lastProgress == null || currentProgress != lastProgress) {
|
|
114
|
+
PROGRESSES.put(key, currentProgress);
|
|
115
|
+
return true;
|
|
116
|
+
} else {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private static class OkHttpProgressResponseBody extends ResponseBody {
|
|
123
|
+
private final String key;
|
|
124
|
+
private final ResponseBody responseBody;
|
|
125
|
+
private final ResponseProgressListener progressListener;
|
|
126
|
+
private BufferedSource bufferedSource;
|
|
127
|
+
|
|
128
|
+
OkHttpProgressResponseBody(
|
|
129
|
+
String key,
|
|
130
|
+
ResponseBody responseBody,
|
|
131
|
+
ResponseProgressListener progressListener
|
|
132
|
+
) {
|
|
133
|
+
this.key = key;
|
|
134
|
+
this.responseBody = responseBody;
|
|
135
|
+
this.progressListener = progressListener;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@Override
|
|
139
|
+
public MediaType contentType() {
|
|
140
|
+
return responseBody.contentType();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@Override
|
|
144
|
+
public long contentLength() {
|
|
145
|
+
return responseBody.contentLength();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@Override
|
|
149
|
+
public BufferedSource source() {
|
|
150
|
+
if (bufferedSource == null) {
|
|
151
|
+
bufferedSource = Okio.buffer(source(responseBody.source()));
|
|
152
|
+
}
|
|
153
|
+
return bufferedSource;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private Source source(Source source) {
|
|
157
|
+
return new ForwardingSource(source) {
|
|
158
|
+
long totalBytesRead = 0L;
|
|
159
|
+
|
|
160
|
+
@Override
|
|
161
|
+
public long read(Buffer sink, long byteCount) throws IOException {
|
|
162
|
+
long bytesRead = super.read(sink, byteCount);
|
|
163
|
+
long fullLength = responseBody.contentLength();
|
|
164
|
+
if (bytesRead == -1) {
|
|
165
|
+
// this source is exhausted
|
|
166
|
+
totalBytesRead = fullLength;
|
|
167
|
+
} else {
|
|
168
|
+
totalBytesRead += bytesRead;
|
|
169
|
+
}
|
|
170
|
+
progressListener.update(key, totalBytesRead, fullLength);
|
|
171
|
+
return bytesRead;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package com.dylanvann.fastimage;
|
|
2
|
+
|
|
3
|
+
public interface FastImageProgressListener {
|
|
4
|
+
|
|
5
|
+
void onProgress(String key, long bytesRead, long expectedLength);
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Control how often the listener needs an update. 0% and 100% will always be dispatched.
|
|
9
|
+
*
|
|
10
|
+
* @return in percentage (0.2 = call {@link #onProgress} around every 0.2 percent of progress)
|
|
11
|
+
*/
|
|
12
|
+
float getGranularityPercentage();
|
|
13
|
+
|
|
14
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
package com.dylanvann.fastimage;
|
|
2
|
+
|
|
3
|
+
import android.graphics.drawable.Drawable;
|
|
4
|
+
|
|
5
|
+
import com.bumptech.glide.load.DataSource;
|
|
6
|
+
import com.bumptech.glide.load.engine.GlideException;
|
|
7
|
+
import com.bumptech.glide.request.RequestListener;
|
|
8
|
+
import com.bumptech.glide.request.target.ImageViewTarget;
|
|
9
|
+
import com.bumptech.glide.request.target.Target;
|
|
10
|
+
import com.facebook.react.bridge.WritableMap;
|
|
11
|
+
import com.facebook.react.bridge.WritableNativeMap;
|
|
12
|
+
import com.facebook.react.uimanager.ThemedReactContext;
|
|
13
|
+
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
|
14
|
+
|
|
15
|
+
public class FastImageRequestListener implements RequestListener<Drawable> {
|
|
16
|
+
static final String REACT_ON_ERROR_EVENT = "onFastImageError";
|
|
17
|
+
static final String REACT_ON_LOAD_EVENT = "onFastImageLoad";
|
|
18
|
+
static final String REACT_ON_LOAD_END_EVENT = "onFastImageLoadEnd";
|
|
19
|
+
private final String key;
|
|
20
|
+
|
|
21
|
+
FastImageRequestListener(String key) {
|
|
22
|
+
this.key = key;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private static WritableMap mapFromResource(Drawable resource) {
|
|
26
|
+
WritableMap resourceData = new WritableNativeMap();
|
|
27
|
+
resourceData.putInt("width", resource.getIntrinsicWidth());
|
|
28
|
+
resourceData.putInt("height", resource.getIntrinsicHeight());
|
|
29
|
+
return resourceData;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@Override
|
|
33
|
+
public boolean onLoadFailed(@androidx.annotation.Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
|
|
34
|
+
FastImageOkHttpProgressGlideModule.forget(key);
|
|
35
|
+
if (!(target instanceof ImageViewTarget)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
FastImageViewWithUrl view = (FastImageViewWithUrl) ((ImageViewTarget) target).getView();
|
|
39
|
+
ThemedReactContext context = (ThemedReactContext) view.getContext();
|
|
40
|
+
RCTEventEmitter eventEmitter = context.getJSModule(RCTEventEmitter.class);
|
|
41
|
+
int viewId = view.getId();
|
|
42
|
+
eventEmitter.receiveEvent(viewId, REACT_ON_ERROR_EVENT, new WritableNativeMap());
|
|
43
|
+
eventEmitter.receiveEvent(viewId, REACT_ON_LOAD_END_EVENT, new WritableNativeMap());
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@Override
|
|
48
|
+
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
|
|
49
|
+
if (!(target instanceof ImageViewTarget)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
FastImageViewWithUrl view = (FastImageViewWithUrl) ((ImageViewTarget) target).getView();
|
|
53
|
+
ThemedReactContext context = (ThemedReactContext) view.getContext();
|
|
54
|
+
RCTEventEmitter eventEmitter = context.getJSModule(RCTEventEmitter.class);
|
|
55
|
+
int viewId = view.getId();
|
|
56
|
+
eventEmitter.receiveEvent(viewId, REACT_ON_LOAD_EVENT, mapFromResource(resource));
|
|
57
|
+
eventEmitter.receiveEvent(viewId, REACT_ON_LOAD_END_EVENT, new WritableNativeMap());
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
package com.dylanvann.fastimage;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
import android.content.res.Resources;
|
|
5
|
+
import android.net.Uri;
|
|
6
|
+
import android.text.TextUtils;
|
|
7
|
+
|
|
8
|
+
import com.bumptech.glide.load.model.GlideUrl;
|
|
9
|
+
import com.bumptech.glide.load.model.Headers;
|
|
10
|
+
import com.facebook.react.views.imagehelper.ImageSource;
|
|
11
|
+
|
|
12
|
+
import javax.annotation.Nullable;
|
|
13
|
+
|
|
14
|
+
public class FastImageSource extends ImageSource {
|
|
15
|
+
private static final String DATA_SCHEME = "data";
|
|
16
|
+
private static final String LOCAL_RESOURCE_SCHEME = "res";
|
|
17
|
+
private static final String ANDROID_RESOURCE_SCHEME = "android.resource";
|
|
18
|
+
private static final String ANDROID_CONTENT_SCHEME = "content";
|
|
19
|
+
private static final String LOCAL_FILE_SCHEME = "file";
|
|
20
|
+
private final Headers mHeaders;
|
|
21
|
+
private Uri mUri;
|
|
22
|
+
|
|
23
|
+
public static boolean isBase64Uri(Uri uri) {
|
|
24
|
+
return DATA_SCHEME.equals(uri.getScheme());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public static boolean isLocalResourceUri(Uri uri) {
|
|
28
|
+
return LOCAL_RESOURCE_SCHEME.equals(uri.getScheme());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public static boolean isResourceUri(Uri uri) {
|
|
32
|
+
return ANDROID_RESOURCE_SCHEME.equals(uri.getScheme());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public static boolean isContentUri(Uri uri) {
|
|
36
|
+
return ANDROID_CONTENT_SCHEME.equals(uri.getScheme());
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public static boolean isLocalFileUri(Uri uri) {
|
|
40
|
+
return LOCAL_FILE_SCHEME.equals(uri.getScheme());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public FastImageSource(Context context, String source) {
|
|
44
|
+
this(context, source, null);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public FastImageSource(Context context, String source, @Nullable Headers headers) {
|
|
48
|
+
this(context, source, 0.0d, 0.0d, headers);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public FastImageSource(Context context, String source, double width, double height, @Nullable Headers headers) {
|
|
52
|
+
super(context, source, width, height);
|
|
53
|
+
mHeaders = headers == null ? Headers.DEFAULT : headers;
|
|
54
|
+
mUri = super.getUri();
|
|
55
|
+
|
|
56
|
+
if (isResource() && TextUtils.isEmpty(mUri.toString())) {
|
|
57
|
+
throw new Resources.NotFoundException("Local Resource Not Found. Resource: '" + getSource() + "'.");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (isLocalResourceUri(mUri)) {
|
|
61
|
+
// Convert res:/ scheme to android.resource:// so
|
|
62
|
+
// glide can understand the uri.
|
|
63
|
+
mUri = Uri.parse(mUri.toString().replace("res:/", ANDROID_RESOURCE_SCHEME + "://" + context.getPackageName() + "/"));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
public boolean isBase64Resource() {
|
|
69
|
+
return mUri != null && FastImageSource.isBase64Uri(mUri);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public boolean isResource() {
|
|
73
|
+
return mUri != null && FastImageSource.isResourceUri(mUri);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public boolean isLocalFile() {
|
|
77
|
+
return mUri != null && FastImageSource.isLocalFileUri(mUri);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public boolean isContentUri() {
|
|
81
|
+
return mUri != null && FastImageSource.isContentUri(mUri);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public Object getSourceForLoad() {
|
|
85
|
+
if (isContentUri()) {
|
|
86
|
+
return getSource();
|
|
87
|
+
}
|
|
88
|
+
if (isBase64Resource()) {
|
|
89
|
+
return getSource();
|
|
90
|
+
}
|
|
91
|
+
if (isResource()) {
|
|
92
|
+
return getUri();
|
|
93
|
+
}
|
|
94
|
+
if (isLocalFile()) {
|
|
95
|
+
return getUri().toString();
|
|
96
|
+
}
|
|
97
|
+
return getGlideUrl();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@Override
|
|
101
|
+
public Uri getUri() {
|
|
102
|
+
return mUri;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public Headers getHeaders() {
|
|
106
|
+
return mHeaders;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public GlideUrl getGlideUrl() {
|
|
110
|
+
return new GlideUrl(getUri().toString(), getHeaders());
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
package com.dylanvann.fastimage;
|
|
2
|
+
|
|
3
|
+
import static com.bumptech.glide.request.RequestOptions.signatureOf;
|
|
4
|
+
|
|
5
|
+
import android.content.Context;
|
|
6
|
+
import android.graphics.Color;
|
|
7
|
+
import android.graphics.drawable.ColorDrawable;
|
|
8
|
+
import android.graphics.drawable.Drawable;
|
|
9
|
+
import android.widget.ImageView;
|
|
10
|
+
import android.widget.ImageView.ScaleType;
|
|
11
|
+
|
|
12
|
+
import com.bumptech.glide.Priority;
|
|
13
|
+
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
|
14
|
+
import com.bumptech.glide.load.model.Headers;
|
|
15
|
+
import com.bumptech.glide.load.model.LazyHeaders;
|
|
16
|
+
import com.bumptech.glide.request.RequestOptions;
|
|
17
|
+
import com.bumptech.glide.signature.ApplicationVersionSignature;
|
|
18
|
+
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
|
19
|
+
import com.facebook.react.bridge.NoSuchKeyException;
|
|
20
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
21
|
+
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
|
22
|
+
|
|
23
|
+
import java.util.HashMap;
|
|
24
|
+
import java.util.Map;
|
|
25
|
+
|
|
26
|
+
import javax.annotation.Nullable;
|
|
27
|
+
|
|
28
|
+
class FastImageViewConverter {
|
|
29
|
+
private static final Drawable TRANSPARENT_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
|
|
30
|
+
|
|
31
|
+
private static final Map<String, FastImageCacheControl> FAST_IMAGE_CACHE_CONTROL_MAP =
|
|
32
|
+
new HashMap<String, FastImageCacheControl>() {{
|
|
33
|
+
put("immutable", FastImageCacheControl.IMMUTABLE);
|
|
34
|
+
put("web", FastImageCacheControl.WEB);
|
|
35
|
+
put("cacheOnly", FastImageCacheControl.CACHE_ONLY);
|
|
36
|
+
}};
|
|
37
|
+
|
|
38
|
+
private static final Map<String, Priority> FAST_IMAGE_PRIORITY_MAP =
|
|
39
|
+
new HashMap<String, Priority>() {{
|
|
40
|
+
put("low", Priority.LOW);
|
|
41
|
+
put("normal", Priority.NORMAL);
|
|
42
|
+
put("high", Priority.HIGH);
|
|
43
|
+
}};
|
|
44
|
+
|
|
45
|
+
private static final Map<String, ImageView.ScaleType> FAST_IMAGE_RESIZE_MODE_MAP =
|
|
46
|
+
new HashMap<String, ImageView.ScaleType>() {{
|
|
47
|
+
put("contain", ScaleType.FIT_CENTER);
|
|
48
|
+
put("cover", ScaleType.CENTER_CROP);
|
|
49
|
+
put("stretch", ScaleType.FIT_XY);
|
|
50
|
+
put("center", ScaleType.CENTER_INSIDE);
|
|
51
|
+
}};
|
|
52
|
+
|
|
53
|
+
// Resolve the source uri to a file path that android understands.
|
|
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));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static Headers getHeaders(ReadableMap source) {
|
|
62
|
+
Headers headers = Headers.DEFAULT;
|
|
63
|
+
|
|
64
|
+
if (source.hasKey("headers")) {
|
|
65
|
+
ReadableMap headersMap = source.getMap("headers");
|
|
66
|
+
ReadableMapKeySetIterator iterator = headersMap.keySetIterator();
|
|
67
|
+
LazyHeaders.Builder builder = new LazyHeaders.Builder();
|
|
68
|
+
|
|
69
|
+
while (iterator.hasNextKey()) {
|
|
70
|
+
String header = iterator.nextKey();
|
|
71
|
+
String value = headersMap.getString(header);
|
|
72
|
+
|
|
73
|
+
builder.addHeader(header, value);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
headers = builder.build();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return headers;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static RequestOptions getOptions(Context context, FastImageSource imageSource, ReadableMap source) {
|
|
83
|
+
// Get priority.
|
|
84
|
+
final Priority priority = FastImageViewConverter.getPriority(source);
|
|
85
|
+
// Get cache control method.
|
|
86
|
+
final FastImageCacheControl cacheControl = FastImageViewConverter.getCacheControl(source);
|
|
87
|
+
DiskCacheStrategy diskCacheStrategy = DiskCacheStrategy.AUTOMATIC;
|
|
88
|
+
boolean onlyFromCache = false;
|
|
89
|
+
boolean skipMemoryCache = false;
|
|
90
|
+
switch (cacheControl) {
|
|
91
|
+
case WEB:
|
|
92
|
+
// If using none then OkHttp integration should be used for caching.
|
|
93
|
+
diskCacheStrategy = DiskCacheStrategy.NONE;
|
|
94
|
+
skipMemoryCache = true;
|
|
95
|
+
break;
|
|
96
|
+
case CACHE_ONLY:
|
|
97
|
+
onlyFromCache = true;
|
|
98
|
+
break;
|
|
99
|
+
case IMMUTABLE:
|
|
100
|
+
// Use defaults.
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
RequestOptions options = new RequestOptions()
|
|
105
|
+
.diskCacheStrategy(diskCacheStrategy)
|
|
106
|
+
.onlyRetrieveFromCache(onlyFromCache)
|
|
107
|
+
.skipMemoryCache(skipMemoryCache)
|
|
108
|
+
.priority(priority)
|
|
109
|
+
.placeholder(TRANSPARENT_DRAWABLE);
|
|
110
|
+
|
|
111
|
+
if (imageSource.isResource()) {
|
|
112
|
+
// Every local resource (drawable) in Android has its own unique numeric id, which are
|
|
113
|
+
// generated at build time. Although these ids are unique, they are not guaranteed unique
|
|
114
|
+
// across builds. The underlying glide implementation caches these resources. To make
|
|
115
|
+
// sure the cache does not return the wrong image, we should clear the cache when the
|
|
116
|
+
// application version changes. Adding a cache signature for only these local resources
|
|
117
|
+
// solves this issue: https://github.com/DylanVann/react-native-fast-image/issues/402
|
|
118
|
+
options = options.apply(signatureOf(ApplicationVersionSignature.obtain(context)));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return options;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private static FastImageCacheControl getCacheControl(ReadableMap source) {
|
|
125
|
+
return getValueFromSource("cache", "immutable", FAST_IMAGE_CACHE_CONTROL_MAP, source);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private static Priority getPriority(ReadableMap source) {
|
|
129
|
+
return getValueFromSource("priority", "normal", FAST_IMAGE_PRIORITY_MAP, source);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
static ScaleType getScaleType(String propValue) {
|
|
133
|
+
return getValue("resizeMode", "cover", FAST_IMAGE_RESIZE_MODE_MAP, propValue);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private static <T> T getValue(String propName, String defaultPropValue, Map<String, T> map, String propValue) {
|
|
137
|
+
if (propValue == null) propValue = defaultPropValue;
|
|
138
|
+
T value = map.get(propValue);
|
|
139
|
+
if (value == null)
|
|
140
|
+
throw new JSApplicationIllegalArgumentException("FastImage, invalid " + propName + " : " + propValue);
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private static <T> T getValueFromSource(String propName, String defaultProp, Map<String, T> map, ReadableMap source) {
|
|
145
|
+
String propValue;
|
|
146
|
+
try {
|
|
147
|
+
propValue = source != null ? source.getString(propName) : null;
|
|
148
|
+
} catch (NoSuchKeyException e) {
|
|
149
|
+
propValue = null;
|
|
150
|
+
}
|
|
151
|
+
return getValue(propName, defaultProp, map, propValue);
|
|
152
|
+
}
|
|
153
|
+
}
|