react-native-fast-image 8.31.0 → 8.31.1
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 +6 -3
- package/android/build.gradle +13 -1
- package/android/src/glide-4.15/java/com/dylanvann/fastimage/FastImageAnimated.java +2 -2
- package/android/src/main/java/com/dylanvann/fastimage/FastImageApng.java +2 -2
- package/android/src/main/java/com/dylanvann/fastimage/FastImageGif.java +1 -1
- package/android/src/main/java/com/dylanvann/fastimage/FastImageGlide.java +76 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageGlideModule.java +1 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageOkHttpProgressGlideModule.java +25 -51
- 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/FastImageSourceSize.java +1 -1
- package/android/src/main/java/com/dylanvann/fastimage/FastImageSvg.java +2 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageUrl.java +36 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewConverter.java +2 -1
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java +1 -0
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewModule.java +13 -10
- package/android/src/main/java/com/dylanvann/fastimage/FastImageWebGlideUrl.java +1 -0
- package/dist/index.d.ts +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@ Performant React Native image component.
|
|
|
5
5
|
[![Version][version-badge]][package]
|
|
6
6
|
[![Downloads][downloads-badge]][npmtrends]
|
|
7
7
|
[![Build Status][build-badge]][build]
|
|
8
|
+
[![Docs][docs-badge]][docs]
|
|
8
9
|
|
|
9
10
|
React Native's `Image` component handles image caching like browsers for the most part. If the server is returning proper cache control headers for images you'll generally get the sort of built in caching behavior you'd have in a browser. Even so, many people have noticed:
|
|
10
11
|
|
|
@@ -622,7 +623,7 @@ await FastImage.configureCache({ maxDiskSize: 500 * 1024 * 1024 })
|
|
|
622
623
|
const { maxDiskSize, diskSize } = await FastImage.configureCache()
|
|
623
624
|
```
|
|
624
625
|
|
|
625
|
-
On Android, if your app has its own `AppGlideModule` (see [using FastImage with an AppGlideModule](docs/android-build-settings.md#if-your-app-has-its-own-appglidemodule)), set the disk cache size there instead: `maxDiskSize` isn't applied or reported.
|
|
626
|
+
On Android, if your app has its own `AppGlideModule` (see [using FastImage with an AppGlideModule](docs/android-build-settings.md#if-your-app-has-its-own-appglidemodule)), set the disk cache size there instead: `maxDiskSize` isn't applied or reported. Likewise in an app with [expo-image](docs/android-build-settings.md#with-expo-image), whose Glide setup sets the disk cache.
|
|
626
627
|
|
|
627
628
|
Images with `cache: 'web'` are kept in their own HTTP cache instead, up to 50 MB on each platform, which these limits don't change.
|
|
628
629
|
|
|
@@ -658,7 +659,7 @@ How fresh an image must be: see [`source.cache`](#sourcecache).
|
|
|
658
659
|
|
|
659
660
|
### `CacheState`
|
|
660
661
|
|
|
661
|
-
`configureCache`'s result: the limits in effect (0 for no limit), and the bytes the disk cache uses now. Android only has `maxDiskSize` and `diskSize`, and neither if the app has its own `AppGlideModule
|
|
662
|
+
`configureCache`'s result: the limits in effect (0 for no limit), and the bytes the disk cache uses now. Android only has `maxDiskSize` and `diskSize`, and neither if the app has its own `AppGlideModule` (or expo-image, which has one).
|
|
662
663
|
|
|
663
664
|
- `maxDiskSize?` (`number`)
|
|
664
665
|
- `maxDiskAge?` (`number`)
|
|
@@ -799,7 +800,7 @@ In `android/app/src/main/AndroidManifest.xml`, inside `<application>`:
|
|
|
799
800
|
<meta-data android:name="fastimage.MAX_DISK_SIZE" android:value="209715200" />
|
|
800
801
|
```
|
|
801
802
|
|
|
802
|
-
If your app has its own `AppGlideModule` (see [using FastImage with an AppGlideModule](docs/android-build-settings.md#if-your-app-has-its-own-appglidemodule)), set the disk cache size there instead.
|
|
803
|
+
If your app has its own `AppGlideModule` (see [using FastImage with an AppGlideModule](docs/android-build-settings.md#if-your-app-has-its-own-appglidemodule)), set the disk cache size there instead. In an app with [expo-image](docs/android-build-settings.md#with-expo-image), expo-image's Glide setup sets it.
|
|
803
804
|
|
|
804
805
|
[^glide-memory]: Glide's default, which FastImage keeps: room for two screenfuls of decoded images (2 × the screen's width × height × 4 bytes, about 20 MB on a 1080 × 2400 screen), plus a pool of bitmaps to reuse (one screenful on Android 8 and later, four before). Together they're limited to 40% of the memory Android gives the app (33% on low-memory devices), and both shrink to fit.
|
|
805
806
|
|
|
@@ -846,6 +847,8 @@ Thanks to [@mobinni](https://github.com/mobinni) for helping with the conceptual
|
|
|
846
847
|
|
|
847
848
|
[build-badge]: https://github.com/DylanVann/react-native-fast-image/actions/workflows/ci.yml/badge.svg
|
|
848
849
|
[build]: https://github.com/DylanVann/react-native-fast-image/actions/workflows/ci.yml
|
|
850
|
+
[docs-badge]: https://img.shields.io/badge/docs-website-blue.svg
|
|
851
|
+
[docs]: https://react-native-fast-image.dylanvann.workers.dev
|
|
849
852
|
[downloads-badge]: https://img.shields.io/npm/dm/react-native-fast-image.svg
|
|
850
853
|
[npmtrends]: http://www.npmtrends.com/react-native-fast-image
|
|
851
854
|
[package]: https://www.npmjs.com/package/react-native-fast-image
|
package/android/build.gradle
CHANGED
|
@@ -19,6 +19,18 @@ buildscript {
|
|
|
19
19
|
|
|
20
20
|
apply plugin: 'com.android.library'
|
|
21
21
|
|
|
22
|
+
// Whether the app has expo-image (in a node_modules folder above the app's
|
|
23
|
+
// android folder, as Node finds it), which ships its own AppGlideModule.
|
|
24
|
+
def appHasExpoImage = {
|
|
25
|
+
for (def dir = rootProject.projectDir; dir != null; dir = dir.parentFile) {
|
|
26
|
+
if (new File(dir, "node_modules/expo-image/package.json").isFile()) return true
|
|
27
|
+
}
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
// An app has one AppGlideModule: with expo-image, FastImage's is left out,
|
|
31
|
+
// and FastImage registers its Glide components itself (FastImageGlide).
|
|
32
|
+
def excludeAppGlideModule = safeExtGet('excludeAppGlideModule', appHasExpoImage())
|
|
33
|
+
|
|
22
34
|
// When changing the default, revisit the Glide rules in consumer-rules.pro.
|
|
23
35
|
// 4.15+ animates animated WebP (Android 9+) and AVIF (Android 12+).
|
|
24
36
|
def glideVersion = safeExtGet('glideVersion', '4.16.0')
|
|
@@ -56,7 +68,7 @@ android {
|
|
|
56
68
|
}
|
|
57
69
|
java {
|
|
58
70
|
srcDir glideHasAnimatedDecoder ? "src/glide-4.15/java" : "src/glide-older/java"
|
|
59
|
-
if (
|
|
71
|
+
if (excludeAppGlideModule) {
|
|
60
72
|
srcDir "src"
|
|
61
73
|
exclude "**/FastImageGlideModule.java"
|
|
62
74
|
// Only the one chosen above.
|
|
@@ -194,7 +194,7 @@ final class FastImageAnimated {
|
|
|
194
194
|
|
|
195
195
|
@Override
|
|
196
196
|
public boolean handles(@NonNull ByteBuffer source, @NonNull Options options) throws IOException {
|
|
197
|
-
return glide.handles(source, options);
|
|
197
|
+
return FastImageGlide.isRequest(options) && glide.handles(source, options);
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
@Nullable
|
|
@@ -229,7 +229,7 @@ final class FastImageAnimated {
|
|
|
229
229
|
|
|
230
230
|
@Override
|
|
231
231
|
public boolean handles(@NonNull InputStream source, @NonNull Options options) throws IOException {
|
|
232
|
-
return glide.handles(source, options);
|
|
232
|
+
return FastImageGlide.isRequest(options) && glide.handles(source, options);
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
// Read whole, as Glide's own does.
|
|
@@ -99,7 +99,7 @@ final class FastImageApng {
|
|
|
99
99
|
private static final class BufferDecoder implements ResourceDecoder<ByteBuffer, Drawable> {
|
|
100
100
|
@Override
|
|
101
101
|
public boolean handles(@NonNull ByteBuffer source, @NonNull Options options) {
|
|
102
|
-
return animates(options) && plays(source) >= 0;
|
|
102
|
+
return FastImageGlide.isRequest(options) && animates(options) && plays(source) >= 0;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
@Nullable
|
|
@@ -113,7 +113,7 @@ final class FastImageApng {
|
|
|
113
113
|
private static final class StreamDecoder implements ResourceDecoder<InputStream, Drawable> {
|
|
114
114
|
@Override
|
|
115
115
|
public boolean handles(@NonNull InputStream source, @NonNull Options options) throws IOException {
|
|
116
|
-
if (!animates(options)) return false;
|
|
116
|
+
if (!FastImageGlide.isRequest(options) || !animates(options)) return false;
|
|
117
117
|
byte[] head = new byte[HEAD_LENGTH];
|
|
118
118
|
source.mark(HEAD_LENGTH);
|
|
119
119
|
int read = 0;
|
|
@@ -40,7 +40,7 @@ final class FastImageGif {
|
|
|
40
40
|
ByteBuffer data = gif.getBuffer();
|
|
41
41
|
GifHeader header = new GifHeaderParser().setData(data).parseHeader();
|
|
42
42
|
if (header.getNumFrames() <= 0 || header.getStatus() != GifDecoder.STATUS_OK) return null;
|
|
43
|
-
Glide glide =
|
|
43
|
+
Glide glide = FastImageGlide.get(context);
|
|
44
44
|
BitmapPool bitmapPool = glide.getBitmapPool();
|
|
45
45
|
GifDecoder decoder = new StandardGifDecoder(
|
|
46
46
|
new GifBitmapProvider(bitmapPool, glide.getArrayPool()),
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
package com.dylanvann.fastimage;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
6
|
+
|
|
7
|
+
import com.bumptech.glide.Glide;
|
|
8
|
+
import com.bumptech.glide.Registry;
|
|
9
|
+
import com.bumptech.glide.load.Option;
|
|
10
|
+
import com.bumptech.glide.load.Options;
|
|
11
|
+
|
|
12
|
+
// FastImage's use of Glide, which the app may share with other libraries.
|
|
13
|
+
final class FastImageGlide {
|
|
14
|
+
private FastImageGlide() {}
|
|
15
|
+
|
|
16
|
+
// Set on FastImage's requests, so its decoders (animated WebP and AVIF,
|
|
17
|
+
// APNG, SVG) only take its own images: another library's images (e.g.
|
|
18
|
+
// expo-image's) keep that library's decoders.
|
|
19
|
+
static final Option<Boolean> REQUEST = Option.memory("com.dylanvann.fastimage.Request", false);
|
|
20
|
+
|
|
21
|
+
static boolean isRequest(@NonNull Options options) {
|
|
22
|
+
return Boolean.TRUE.equals(options.get(REQUEST));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// The Glide instance FastImage's components (FastImageOkHttpProgressGlideModule)
|
|
26
|
+
// were registered with.
|
|
27
|
+
private static volatile Glide registered;
|
|
28
|
+
|
|
29
|
+
// Whether Glide started with FastImage's AppGlideModule (as the app's).
|
|
30
|
+
private static volatile boolean appModule;
|
|
31
|
+
|
|
32
|
+
static void appModuleStarted() {
|
|
33
|
+
appModule = true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static void registered(@NonNull Glide glide) {
|
|
37
|
+
registered = glide;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Glide, with FastImage's components. Glide registers them if the app's
|
|
41
|
+
// generated Glide module lists FastImage's module, as FastImage's
|
|
42
|
+
// AppGlideModule's does. Another library's (e.g. expo-image's, which ships
|
|
43
|
+
// one) only lists the modules it was built with, so then they're
|
|
44
|
+
// registered here, before FastImage's first request.
|
|
45
|
+
@NonNull
|
|
46
|
+
static Glide get(@NonNull Context context) {
|
|
47
|
+
Glide glide = Glide.get(context);
|
|
48
|
+
// Glide registers them itself, when its registry is first used (in
|
|
49
|
+
// the background, by the first load: Glide 4.15+ builds it lazily).
|
|
50
|
+
if (appModule) return glide;
|
|
51
|
+
// Builds the registry, which registers them if the app's module lists
|
|
52
|
+
// FastImage's.
|
|
53
|
+
Registry registry = glide.getRegistry();
|
|
54
|
+
if (registered != glide) {
|
|
55
|
+
synchronized (FastImageGlide.class) {
|
|
56
|
+
if (registered != glide) {
|
|
57
|
+
new FastImageOkHttpProgressGlideModule()
|
|
58
|
+
.registerComponents(context.getApplicationContext(), glide, registry);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return glide;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Glide, with FastImage's components registered now, for callers in the
|
|
66
|
+
// background that use them directly rather than through a load (the HTTP
|
|
67
|
+
// cache of `cache: 'web'` images, which registering them sets up): with
|
|
68
|
+
// FastImage's AppGlideModule, Glide registers them only when its registry
|
|
69
|
+
// is first used, e.g. by FastImage's first load.
|
|
70
|
+
@NonNull
|
|
71
|
+
static Glide getRegistered(@NonNull Context context) {
|
|
72
|
+
Glide glide = get(context);
|
|
73
|
+
glide.getRegistry();
|
|
74
|
+
return glide;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -16,6 +16,7 @@ public final class FastImageGlideModule extends AppGlideModule {
|
|
|
16
16
|
// FastImageCacheLimits), in Glide's default folder.
|
|
17
17
|
@Override
|
|
18
18
|
public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
|
|
19
|
+
FastImageGlide.appModuleStarted();
|
|
19
20
|
long maxDiskSize = FastImageCacheLimits.maxDiskSize(context);
|
|
20
21
|
builder.setDiskCache(new InternalCacheDiskCacheFactory(context, maxDiskSize == 0 ? Long.MAX_VALUE : maxDiskSize));
|
|
21
22
|
FastImageCacheLimits.startedMaxDiskSize = maxDiskSize;
|
package/android/src/main/java/com/dylanvann/fastimage/FastImageOkHttpProgressGlideModule.java
CHANGED
|
@@ -119,11 +119,6 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
|
|
|
119
119
|
builder.cookieJar(new JavaNetCookieJar(new FastImageCookieHandler(context)));
|
|
120
120
|
}
|
|
121
121
|
OkHttpClient client = builder.build();
|
|
122
|
-
registry.replace(GlideUrl.class, InputStream.class, new UrlLoaderFactory(client));
|
|
123
|
-
FastImageSvg.register(registry, glide.getBitmapPool());
|
|
124
|
-
FastImageAnimated.register(context, glide, registry);
|
|
125
|
-
FastImageApng.register(registry);
|
|
126
|
-
|
|
127
122
|
// `cache: 'web'` skips Glide's caches and relies on HTTP caching, so
|
|
128
123
|
// those urls get a client with an HTTP cache (#280): one of their own,
|
|
129
124
|
// not the app's (if it gave React Native's shared client one), so
|
|
@@ -132,70 +127,49 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
|
|
|
132
127
|
// store them twice).
|
|
133
128
|
webCache = new Cache(new File(context.getCacheDir(), "fast-image-http-cache"), WEB_CACHE_SIZE);
|
|
134
129
|
webClient = client.newBuilder().cache(webCache).build();
|
|
135
|
-
registry.prepend(
|
|
130
|
+
registry.prepend(FastImageUrl.class, InputStream.class, new UrlLoaderFactory(client, webClient));
|
|
131
|
+
FastImageSvg.register(registry, glide.getBitmapPool());
|
|
132
|
+
FastImageAnimated.register(context, glide, registry);
|
|
133
|
+
FastImageApng.register(registry);
|
|
136
134
|
|
|
137
135
|
// writeToCache: local files stored under a source's key.
|
|
138
136
|
registry.prepend(FastImageCacheWrite.class, InputStream.class,
|
|
139
137
|
new FastImageCacheWrite.LoaderFactory(context.getApplicationContext()));
|
|
138
|
+
FastImageGlide.registered(glide);
|
|
140
139
|
}
|
|
141
140
|
|
|
142
|
-
// Loads
|
|
143
|
-
// (FastImageWebGlideUrls)
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
|
|
141
|
+
// Loads FastImage's remote images (FastImageUrls): `web` ones
|
|
142
|
+
// (FastImageWebGlideUrls) with the client with the HTTP cache, others with
|
|
143
|
+
// the other client, where a view loading an image that's being preloaded
|
|
144
|
+
// waits for the preload's download. FastImageUrl isn't a GlideUrl, so
|
|
145
|
+
// Glide doesn't also give these to other GlideUrl loaders, which it would
|
|
146
|
+
// try after a failed load (e.g. a 404, requested again).
|
|
147
|
+
private static class UrlLoaderFactory implements ModelLoaderFactory<FastImageUrl, InputStream> {
|
|
148
148
|
private final OkHttpClient client;
|
|
149
|
+
private final OkHttpClient webClient;
|
|
149
150
|
|
|
150
|
-
UrlLoaderFactory(OkHttpClient client) {
|
|
151
|
+
UrlLoaderFactory(OkHttpClient client, OkHttpClient webClient) {
|
|
151
152
|
this.client = client;
|
|
153
|
+
this.webClient = webClient;
|
|
152
154
|
}
|
|
153
155
|
|
|
154
156
|
@NonNull
|
|
155
157
|
@Override
|
|
156
|
-
public ModelLoader<
|
|
158
|
+
public ModelLoader<FastImageUrl, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
|
|
157
159
|
final OkHttpUrlLoader loader = new OkHttpUrlLoader(client);
|
|
158
|
-
|
|
160
|
+
final OkHttpUrlLoader webLoader = new OkHttpUrlLoader(webClient);
|
|
161
|
+
return new ModelLoader<FastImageUrl, InputStream>() {
|
|
159
162
|
@Override
|
|
160
|
-
public LoadData<InputStream> buildLoadData(@NonNull
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
@Override
|
|
168
|
-
public boolean handles(@NonNull GlideUrl model) {
|
|
169
|
-
return !(model instanceof FastImageWebGlideUrl);
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
@Override
|
|
175
|
-
public void teardown() {
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Loads FastImageWebGlideUrls with the given client.
|
|
180
|
-
private static class WebUrlLoaderFactory implements ModelLoaderFactory<FastImageWebGlideUrl, InputStream> {
|
|
181
|
-
private final OkHttpClient client;
|
|
182
|
-
|
|
183
|
-
WebUrlLoaderFactory(OkHttpClient client) {
|
|
184
|
-
this.client = client;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
@NonNull
|
|
188
|
-
@Override
|
|
189
|
-
public ModelLoader<FastImageWebGlideUrl, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
|
|
190
|
-
final OkHttpUrlLoader loader = new OkHttpUrlLoader(client);
|
|
191
|
-
return new ModelLoader<FastImageWebGlideUrl, InputStream>() {
|
|
192
|
-
@Override
|
|
193
|
-
public LoadData<InputStream> buildLoadData(@NonNull FastImageWebGlideUrl model, int width, int height, @NonNull Options options) {
|
|
194
|
-
return loader.buildLoadData(model, width, height, options);
|
|
163
|
+
public LoadData<InputStream> buildLoadData(@NonNull FastImageUrl model, int width, int height, @NonNull Options options) {
|
|
164
|
+
if (model.url instanceof FastImageWebGlideUrl) {
|
|
165
|
+
return webLoader.buildLoadData(model.url, width, height, options);
|
|
166
|
+
}
|
|
167
|
+
LoadData<InputStream> data = loader.buildLoadData(model.url, width, height, options);
|
|
168
|
+
return data == null ? null : FastImageSharedDownloads.share(data, model.url, options);
|
|
195
169
|
}
|
|
196
170
|
|
|
197
171
|
@Override
|
|
198
|
-
public boolean handles(@NonNull
|
|
172
|
+
public boolean handles(@NonNull FastImageUrl model) {
|
|
199
173
|
return true;
|
|
200
174
|
}
|
|
201
175
|
};
|
|
@@ -4,7 +4,6 @@ import android.graphics.drawable.Drawable;
|
|
|
4
4
|
|
|
5
5
|
import com.bumptech.glide.load.DataSource;
|
|
6
6
|
import com.bumptech.glide.load.engine.GlideException;
|
|
7
|
-
import com.bumptech.glide.load.model.GlideUrl;
|
|
8
7
|
import com.bumptech.glide.load.resource.gif.GifDrawable;
|
|
9
8
|
import com.bumptech.glide.request.Request;
|
|
10
9
|
import com.bumptech.glide.request.RequestListener;
|
|
@@ -83,7 +82,7 @@ public class FastImageRequestListener implements RequestListener<Drawable> {
|
|
|
83
82
|
view.applyLoopCount((GifDrawable) resource);
|
|
84
83
|
}
|
|
85
84
|
if (!events) return false;
|
|
86
|
-
boolean local = !(model instanceof
|
|
85
|
+
boolean local = !(model instanceof FastImageUrl);
|
|
87
86
|
int[] size = FastImageSourceSize.get(resource, model, local,
|
|
88
87
|
dataSource == DataSource.RESOURCE_DISK_CACHE);
|
|
89
88
|
if (size != null) {
|
|
@@ -218,7 +218,7 @@ final class FastImageSourceSize {
|
|
|
218
218
|
int orientation;
|
|
219
219
|
stream = open(context, source);
|
|
220
220
|
try {
|
|
221
|
-
Glide glide =
|
|
221
|
+
Glide glide = FastImageGlide.get(context);
|
|
222
222
|
orientation = ImageHeaderParserUtils.getOrientation(
|
|
223
223
|
glide.getRegistry().getImageHeaderParsers(), stream, glide.getArrayPool());
|
|
224
224
|
} finally {
|
|
@@ -118,6 +118,7 @@ final class FastImageSvg {
|
|
|
118
118
|
|
|
119
119
|
@Override
|
|
120
120
|
public boolean handles(@NonNull InputStream source, @NonNull Options options) throws IOException {
|
|
121
|
+
if (!FastImageGlide.isRequest(options)) return false;
|
|
121
122
|
// Glide rewinds the stream before decoding.
|
|
122
123
|
byte[] head = new byte[HEAD_LENGTH];
|
|
123
124
|
int length = 0;
|
|
@@ -145,6 +146,7 @@ final class FastImageSvg {
|
|
|
145
146
|
|
|
146
147
|
@Override
|
|
147
148
|
public boolean handles(@NonNull ByteBuffer source, @NonNull Options options) {
|
|
149
|
+
if (!FastImageGlide.isRequest(options)) return false;
|
|
148
150
|
ByteBuffer copy = source.duplicate();
|
|
149
151
|
byte[] head = new byte[Math.min(HEAD_LENGTH, copy.remaining())];
|
|
150
152
|
copy.get(head);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package com.dylanvann.fastimage;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
|
|
5
|
+
import com.bumptech.glide.load.model.GlideUrl;
|
|
6
|
+
|
|
7
|
+
// What FastImage loads a remote image with: its GlideUrl (url, headers, and
|
|
8
|
+
// cache key: the disk cache key stays the GlideUrl's), loaded by FastImage's
|
|
9
|
+
// own loader (FastImageOkHttpProgressGlideModule). Not a GlideUrl itself: the
|
|
10
|
+
// app's Glide may have other GlideUrl loaders (Glide's, another library's,
|
|
11
|
+
// e.g. expo-image's), which Glide would also try after a failed load, and
|
|
12
|
+
// FastImage leaves them as they are for the app's other loads.
|
|
13
|
+
final class FastImageUrl {
|
|
14
|
+
final GlideUrl url;
|
|
15
|
+
|
|
16
|
+
FastImageUrl(@NonNull GlideUrl url) {
|
|
17
|
+
this.url = url;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Override
|
|
21
|
+
public boolean equals(Object other) {
|
|
22
|
+
return other instanceof FastImageUrl && url.equals(((FastImageUrl) other).url);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Override
|
|
26
|
+
public int hashCode() {
|
|
27
|
+
return url.hashCode();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// The GlideUrl's (its cache key), which FastImageSourceSize keys sizes by.
|
|
31
|
+
@NonNull
|
|
32
|
+
@Override
|
|
33
|
+
public String toString() {
|
|
34
|
+
return url.toString();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -122,7 +122,8 @@ class FastImageViewConverter {
|
|
|
122
122
|
// memoryCache false: only kept on disk.
|
|
123
123
|
.skipMemoryCache(skipMemoryCache || (imageSource != null && !imageSource.isMemoryCache()))
|
|
124
124
|
.priority(priority)
|
|
125
|
-
.placeholder(TRANSPARENT_DRAWABLE)
|
|
125
|
+
.placeholder(TRANSPARENT_DRAWABLE)
|
|
126
|
+
.set(FastImageGlide.REQUEST, true);
|
|
126
127
|
|
|
127
128
|
// imageSource is null when only a defaultSource is shown.
|
|
128
129
|
if (imageSource != null && imageSource.isResource()) {
|
|
@@ -53,6 +53,7 @@ class FastImageViewManager extends SimpleViewManager<FastImageViewWithUrl> imple
|
|
|
53
53
|
// shared by all views kept the last view's Activity alive after it was
|
|
54
54
|
// destroyed, and gave views another Activity's manager (#492).
|
|
55
55
|
RequestManager requestManager = null;
|
|
56
|
+
FastImageGlide.get(reactContext);
|
|
56
57
|
if (isValidContextForGlide(reactContext)) {
|
|
57
58
|
requestManager = Glide.with(reactContext);
|
|
58
59
|
} else if (getActivityFromContext(reactContext) == null) {
|
|
@@ -87,7 +87,7 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
87
87
|
BitmapFactory.decodeFile(file.getPath(), bounds);
|
|
88
88
|
if (bounds.outWidth <= 0 || bounds.outHeight <= 0) return null;
|
|
89
89
|
int orientation = ImageHeaderParser.UNKNOWN_ORIENTATION;
|
|
90
|
-
Glide glide =
|
|
90
|
+
Glide glide = FastImageGlide.get(context);
|
|
91
91
|
try (InputStream stream = new FileInputStream(file)) {
|
|
92
92
|
orientation = ImageHeaderParserUtils.getOrientation(
|
|
93
93
|
glide.getRegistry().getImageHeaderParsers(), stream, glide.getArrayPool());
|
|
@@ -119,6 +119,7 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
119
119
|
UiThreadUtil.runOnUiThread(new Runnable() {
|
|
120
120
|
@Override
|
|
121
121
|
public void run() {
|
|
122
|
+
FastImageGlide.get(context);
|
|
122
123
|
final int count = sources.size();
|
|
123
124
|
final WritableMap[] results = new WritableMap[count];
|
|
124
125
|
// Sources of this call still to finish. It starts at the
|
|
@@ -270,7 +271,8 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
270
271
|
// thread. For a preload (`shared`), views that load the image meanwhile
|
|
271
272
|
// wait for the download and read its file (FastImageSharedDownloads).
|
|
272
273
|
private static void loadFile(Context context, Object model, RequestOptions options, boolean shared, final FileCallback callback) {
|
|
273
|
-
final String key = shared && model instanceof
|
|
274
|
+
final String key = shared && model instanceof FastImageUrl ? ((FastImageUrl) model).url.getCacheKey() : null;
|
|
275
|
+
FastImageGlide.get(context);
|
|
274
276
|
Glide.with(context)
|
|
275
277
|
.asFile()
|
|
276
278
|
.load(model)
|
|
@@ -298,6 +300,7 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
298
300
|
@Nullable
|
|
299
301
|
private static File cachedFile(Context context, Object model, RequestOptions options) {
|
|
300
302
|
try {
|
|
303
|
+
FastImageGlide.get(context);
|
|
301
304
|
return Glide.with(context)
|
|
302
305
|
.asFile()
|
|
303
306
|
.load(model)
|
|
@@ -348,7 +351,7 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
348
351
|
cachePathExecutor.execute(new Runnable() {
|
|
349
352
|
@Override
|
|
350
353
|
public void run() {
|
|
351
|
-
File file = cachedFile(context, FastImageKeyedGlideUrl.forKey(cacheKey), new RequestOptions());
|
|
354
|
+
File file = cachedFile(context, new FastImageUrl(FastImageKeyedGlideUrl.forKey(cacheKey)), new RequestOptions());
|
|
352
355
|
promise.resolve(file != null ? pathResult(file) : failure("Not in the disk cache"));
|
|
353
356
|
}
|
|
354
357
|
});
|
|
@@ -376,8 +379,8 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
376
379
|
public void run() {
|
|
377
380
|
// On disk already: in Glide's cache (not for `web` images,
|
|
378
381
|
// which it doesn't cache), or in the HTTP cache of `web`
|
|
379
|
-
// images (set up
|
|
380
|
-
|
|
382
|
+
// images (set up when FastImage's components are registered).
|
|
383
|
+
FastImageGlide.getRegistered(context);
|
|
381
384
|
File file = imageSource.isWebCache() ? null : cachedFile(context, imageSource.getSourceForLoad(), options);
|
|
382
385
|
if (file == null) file = FastImageOkHttpProgressGlideModule.webCacheFile(imageSource.getUri().toString());
|
|
383
386
|
if (file != null) {
|
|
@@ -486,7 +489,7 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
486
489
|
final GlideUrl key = imageSource != null && imageSource.isRemote()
|
|
487
490
|
? imageSource.getGlideUrl()
|
|
488
491
|
: FastImageKeyedGlideUrl.forKey(cacheKey);
|
|
489
|
-
final Object lookUp = imageSource != null && imageSource.isRemote() ? imageSource.getSourceForLoad() : key;
|
|
492
|
+
final Object lookUp = imageSource != null && imageSource.isRemote() ? imageSource.getSourceForLoad() : new FastImageUrl(key);
|
|
490
493
|
// A file:// or content:// uri, or a path.
|
|
491
494
|
Uri parsed = Uri.parse(file);
|
|
492
495
|
final Uri fileUri = parsed.getScheme() == null ? Uri.fromFile(new File(file)) : parsed;
|
|
@@ -551,7 +554,7 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
551
554
|
cachePathExecutor.execute(new Runnable() {
|
|
552
555
|
@Override
|
|
553
556
|
public void run() {
|
|
554
|
-
|
|
557
|
+
FastImageGlide.get(context);
|
|
555
558
|
WritableMap result = Arguments.createMap();
|
|
556
559
|
long maxDiskSize = FastImageCacheLimits.startedMaxDiskSize;
|
|
557
560
|
if (maxDiskSize >= 0) {
|
|
@@ -574,7 +577,7 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
574
577
|
activity.runOnUiThread(new Runnable() {
|
|
575
578
|
@Override
|
|
576
579
|
public void run() {
|
|
577
|
-
|
|
580
|
+
FastImageGlide.get(activity.getApplicationContext()).clearMemory();
|
|
578
581
|
promise.resolve(null);
|
|
579
582
|
}
|
|
580
583
|
});
|
|
@@ -588,9 +591,9 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
|
|
|
588
591
|
return;
|
|
589
592
|
}
|
|
590
593
|
|
|
591
|
-
|
|
594
|
+
FastImageGlide.getRegistered(activity.getApplicationContext()).clearDiskCache();
|
|
592
595
|
// And the HTTP cache of `cache: 'web'` images, which Glide doesn't
|
|
593
|
-
// cache.
|
|
596
|
+
// cache (set up when FastImage's components are registered).
|
|
594
597
|
try {
|
|
595
598
|
FastImageOkHttpProgressGlideModule.clearWebCache();
|
|
596
599
|
} catch (IOException e) {
|
|
@@ -6,6 +6,7 @@ import com.bumptech.glide.load.model.Headers;
|
|
|
6
6
|
// A url loaded with `cache: 'web'`. Glide doesn't cache these, so they load
|
|
7
7
|
// through an OkHttp client with an HTTP cache (see
|
|
8
8
|
// FastImageOkHttpProgressGlideModule) to follow the server's caching headers.
|
|
9
|
+
// Loaded as a FastImageUrl, like FastImage's other urls.
|
|
9
10
|
class FastImageWebGlideUrl extends GlideUrl {
|
|
10
11
|
FastImageWebGlideUrl(String url, Headers headers) {
|
|
11
12
|
super(url, headers);
|
package/dist/index.d.ts
CHANGED
|
@@ -187,7 +187,8 @@ export interface CacheLimits {
|
|
|
187
187
|
/**
|
|
188
188
|
* `configureCache`'s result: the limits in effect (0 for no limit), and the
|
|
189
189
|
* bytes the disk cache uses now. Android only has `maxDiskSize` and
|
|
190
|
-
* `diskSize`, and neither if the app has its own `AppGlideModule
|
|
190
|
+
* `diskSize`, and neither if the app has its own `AppGlideModule` (or
|
|
191
|
+
* expo-image, which has one).
|
|
191
192
|
*/
|
|
192
193
|
export interface CacheState {
|
|
193
194
|
maxDiskSize?: number;
|