react-native-fast-image 9.3.7 → 10.1.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.
Files changed (78) hide show
  1. package/README.md +97 -61
  2. package/RNFastImage.podspec +14 -9
  3. package/android/build.gradle +21 -47
  4. package/android/consumer-rules.pro +7 -7
  5. package/android/src/main/AndroidManifest.xml +1 -2
  6. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageAnimatable.java +1 -1
  7. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageAnimated.java +2 -2
  8. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageApng.java +2 -2
  9. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageBlur.java +4 -6
  10. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageCacheControl.java +1 -1
  11. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageCacheLimits.java +4 -1
  12. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageCacheWrite.java +1 -1
  13. package/android/src/main/java/com/fastimage/FastImageCrop.java +92 -0
  14. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageEvent.java +2 -3
  15. package/android/src/main/java/com/fastimage/FastImageEvents.java +74 -0
  16. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageGif.java +1 -1
  17. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageGlide.java +13 -3
  18. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageGlideModule.java +1 -1
  19. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageKeyedGlideUrl.java +1 -1
  20. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageOkHttpProgressGlideModule.java +49 -14
  21. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageRequestListener.java +6 -1
  22. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSharedDownloads.java +1 -1
  23. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSource.java +12 -1
  24. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSourceSize.java +12 -2
  25. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSvg.java +3 -3
  26. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSvgRenderer.java +1 -1
  27. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageUrl.java +1 -1
  28. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageViewConverter.java +24 -9
  29. package/android/src/main/java/com/fastimage/FastImageViewManager.java +591 -0
  30. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageViewModule.java +50 -28
  31. package/android/src/main/java/com/fastimage/FastImageViewPackage.java +51 -0
  32. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageViewWithUrl.java +352 -126
  33. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageWebGlideUrl.java +1 -1
  34. package/app.plugin.js +2 -7
  35. package/dist/index.cjs.js +276 -157
  36. package/dist/index.cjs.js.flow +34 -17
  37. package/dist/index.cjs.web.js +211 -61
  38. package/dist/index.cjs.web.js.flow +34 -17
  39. package/dist/index.d.ts +108 -58
  40. package/dist/index.js +278 -159
  41. package/dist/index.js.flow +34 -17
  42. package/dist/index.web.js +212 -62
  43. package/dist/index.web.js.flow +34 -17
  44. package/dist/objectFit.d.ts +2 -2
  45. package/dist/objectPosition.d.ts +42 -0
  46. package/dist/specs/FastImageViewNativeComponent.d.ts +48 -0
  47. package/dist/specs/NativeFastImageModule.d.ts +11 -0
  48. package/dist/warnings.d.ts +3 -0
  49. package/ios/FastImage/FFFDownsampledImage.h +4 -8
  50. package/ios/FastImage/FFFDownsampledImage.m +0 -34
  51. package/ios/FastImage/FFFastImageModule.h +8 -0
  52. package/ios/FastImage/{FFFastImageViewManager.m → FFFastImageModule.mm} +89 -59
  53. package/ios/FastImage/FFFastImageSource.h +4 -0
  54. package/ios/FastImage/FFFastImageSource.m +5 -1
  55. package/ios/FastImage/FFFastImageView.h +36 -7
  56. package/ios/FastImage/FFFastImageView.m +229 -172
  57. package/ios/FastImage/FFFastImageViewComponentView.h +11 -0
  58. package/ios/FastImage/FFFastImageViewComponentView.mm +325 -0
  59. package/ios/FastImage/RCTConvert+FFFastImage.h +1 -1
  60. package/ios/FastImage/RCTConvert+FFFastImage.m +9 -10
  61. package/package.json +28 -9
  62. package/src/constants.ts +28 -0
  63. package/src/index.js.flow +180 -0
  64. package/src/index.tsx +1128 -0
  65. package/src/index.web.tsx +548 -0
  66. package/src/objectFit.ts +48 -0
  67. package/src/objectPosition.ts +243 -0
  68. package/src/specs/FastImageViewNativeComponent.ts +83 -0
  69. package/src/specs/NativeFastImageModule.ts +35 -0
  70. package/src/warnings.ts +37 -0
  71. package/android/src/main/AndroidManifestNew.xml +0 -3
  72. package/android/src/main/java/com/dylanvann/fastimage/FastImageCookieHandler.java +0 -63
  73. package/android/src/main/java/com/dylanvann/fastimage/FastImageEvents.java +0 -49
  74. package/android/src/main/java/com/dylanvann/fastimage/FastImageProgressListener.java +0 -18
  75. package/android/src/main/java/com/dylanvann/fastimage/FastImageShadowNode.java +0 -21
  76. package/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java +0 -379
  77. package/android/src/main/java/com/dylanvann/fastimage/FastImageViewPackage.java +0 -27
  78. package/ios/FastImage/FFFastImageViewManager.h +0 -5
@@ -0,0 +1,92 @@
1
+ package com.fastimage;
2
+
3
+ import android.graphics.Bitmap;
4
+ import android.graphics.Canvas;
5
+ import android.graphics.Matrix;
6
+ import android.graphics.Paint;
7
+
8
+ import androidx.annotation.NonNull;
9
+
10
+ import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
11
+ import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
12
+ import com.bumptech.glide.load.resource.bitmap.TransformationUtils;
13
+
14
+ import java.nio.ByteBuffer;
15
+ import java.nio.charset.Charset;
16
+ import java.security.MessageDigest;
17
+
18
+ // objectFit cover with an objectPosition other than the center: Glide's
19
+ // CenterCrop at that position. The image is scaled to cover the view's size
20
+ // and the part the view shows is kept, so the bitmap is the view's size, as
21
+ // with CenterCrop. On each axis the image's left or top edge is at
22
+ // (view - image) * fraction + offset (CSS's object-position); an offset that
23
+ // moves it past an edge leaves that part transparent.
24
+ final class FastImageCrop extends BitmapTransformation {
25
+ private static final String ID = "com.fastimage.FastImageCrop";
26
+ private static final byte[] ID_BYTES = ID.getBytes(Charset.forName("UTF-8"));
27
+ private static final Paint PAINT = new Paint(Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG);
28
+
29
+ private final float x;
30
+ private final float xOffset;
31
+ private final float y;
32
+ private final float yOffset;
33
+
34
+ // Offsets in pixels.
35
+ FastImageCrop(float x, float xOffset, float y, float yOffset) {
36
+ this.x = x;
37
+ this.xOffset = xOffset;
38
+ this.y = y;
39
+ this.yOffset = yOffset;
40
+ }
41
+
42
+ @Override
43
+ protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
44
+ int width = toTransform.getWidth();
45
+ int height = toTransform.getHeight();
46
+ if (width <= 0 || height <= 0 || outWidth <= 0 || outHeight <= 0) return toTransform;
47
+ float scale = Math.max(outWidth / (float) width, outHeight / (float) height);
48
+ float shownWidth = width * scale;
49
+ float shownHeight = height * scale;
50
+ float left = Math.round((outWidth - shownWidth) * x + xOffset);
51
+ float top = Math.round((outHeight - shownHeight) * y + yOffset);
52
+ Bitmap.Config config = toTransform.getConfig() != null ? toTransform.getConfig() : Bitmap.Config.ARGB_8888;
53
+ // Past an edge, the view shows nothing there.
54
+ boolean uncovered = left > 0 || top > 0 || left + shownWidth < outWidth || top + shownHeight < outHeight;
55
+ if (uncovered && config == Bitmap.Config.RGB_565) config = Bitmap.Config.ARGB_8888;
56
+ Bitmap result = pool.get(outWidth, outHeight, config);
57
+ TransformationUtils.setAlpha(toTransform, result);
58
+ if (uncovered) {
59
+ result.setHasAlpha(true);
60
+ result.eraseColor(0);
61
+ }
62
+ Matrix matrix = new Matrix();
63
+ matrix.setScale(scale, scale);
64
+ matrix.postTranslate(left, top);
65
+ Canvas canvas = new Canvas(result);
66
+ canvas.drawBitmap(toTransform, matrix, PAINT);
67
+ canvas.setBitmap(null);
68
+ return result;
69
+ }
70
+
71
+ @Override
72
+ public boolean equals(Object o) {
73
+ if (!(o instanceof FastImageCrop)) return false;
74
+ FastImageCrop other = (FastImageCrop) o;
75
+ return other.x == x && other.xOffset == xOffset && other.y == y && other.yOffset == yOffset;
76
+ }
77
+
78
+ @Override
79
+ public int hashCode() {
80
+ int hash = ID.hashCode();
81
+ hash = hash * 31 + Float.floatToIntBits(x);
82
+ hash = hash * 31 + Float.floatToIntBits(xOffset);
83
+ hash = hash * 31 + Float.floatToIntBits(y);
84
+ return hash * 31 + Float.floatToIntBits(yOffset);
85
+ }
86
+
87
+ @Override
88
+ public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
89
+ messageDigest.update(ID_BYTES);
90
+ messageDigest.update(ByteBuffer.allocate(16).putFloat(x).putFloat(xOffset).putFloat(y).putFloat(yOffset).array());
91
+ }
92
+ }
@@ -1,11 +1,10 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import com.facebook.react.bridge.WritableMap;
4
4
  import com.facebook.react.uimanager.events.Event;
5
5
 
6
6
  // An event for a FastImage view, sent with the EventDispatcher (see
7
- // FastImageEvents) instead of the RCTEventEmitter JS module, which the New
8
- // Architecture warns about on every event.
7
+ // FastImageEvents).
9
8
  class FastImageEvent extends Event<FastImageEvent> {
10
9
  private final String name;
11
10
  private final WritableMap data;
@@ -0,0 +1,74 @@
1
+ package com.fastimage;
2
+
3
+ import com.facebook.react.bridge.Arguments;
4
+ import com.facebook.react.bridge.ReactContext;
5
+ import com.facebook.react.bridge.WritableMap;
6
+ import com.facebook.react.uimanager.UIManagerHelper;
7
+ import com.facebook.react.uimanager.events.EventDispatcher;
8
+
9
+ // Sends FastImage view events through React Native's EventDispatcher.
10
+ final class FastImageEvents {
11
+ // The handledEvents prop's bits (see src/specs/FastImageViewNativeComponent.ts).
12
+ static final int LOAD_START = 1;
13
+ static final int PROGRESS = 1 << 1;
14
+ static final int LOAD = 1 << 2;
15
+ static final int ERROR = 1 << 3;
16
+ static final int LOAD_END = 1 << 4;
17
+
18
+ private FastImageEvents() {
19
+ }
20
+
21
+ private static int bit(String name) {
22
+ switch (name) {
23
+ case FastImageViewManager.REACT_ON_LOAD_START_EVENT:
24
+ return LOAD_START;
25
+ case FastImageViewManager.REACT_ON_PROGRESS_EVENT:
26
+ return PROGRESS;
27
+ case FastImageRequestListener.REACT_ON_LOAD_EVENT:
28
+ return LOAD;
29
+ case FastImageRequestListener.REACT_ON_ERROR_EVENT:
30
+ return ERROR;
31
+ case FastImageRequestListener.REACT_ON_LOAD_END_EVENT:
32
+ return LOAD_END;
33
+ default:
34
+ return 0;
35
+ }
36
+ }
37
+
38
+ static void send(FastImageViewWithUrl view, String name) {
39
+ send(view, name, Arguments.createMap());
40
+ }
41
+
42
+ // onLoadEnd with the load's result: ok with the image's size, as onLoad
43
+ // sent it.
44
+ static void sendLoadEnd(FastImageViewWithUrl view, int width, int height) {
45
+ WritableMap event = Arguments.createMap();
46
+ event.putBoolean("ok", true);
47
+ event.putInt("width", width);
48
+ event.putInt("height", height);
49
+ send(view, FastImageRequestListener.REACT_ON_LOAD_END_EVENT, event);
50
+ }
51
+
52
+ // onLoadEnd with the load's result: not ok, with the error onError sent.
53
+ static void sendLoadEnd(FastImageViewWithUrl view, String error) {
54
+ WritableMap event = Arguments.createMap();
55
+ event.putBoolean("ok", false);
56
+ event.putString("error", error);
57
+ send(view, FastImageRequestListener.REACT_ON_LOAD_END_EVENT, event);
58
+ }
59
+
60
+ // Only the events JS has a handler for: most images have none.
61
+ static void send(FastImageViewWithUrl view, String name, WritableMap data) {
62
+ if (!view.handles(bit(name))) return;
63
+ ReactContext context = FastImageViewManager.getReactContext(view.getContext());
64
+ if (context == null) return;
65
+ // The view's event dispatcher (Fabric, bridgeless). Deprecated from React
66
+ // Native 0.85; its replacement, getEventDispatcher(context), isn't in 0.83.
67
+ @SuppressWarnings("deprecation")
68
+ EventDispatcher dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.getId());
69
+ if (dispatcher != null) {
70
+ dispatcher.dispatchEvent(new FastImageEvent(
71
+ UIManagerHelper.getSurfaceId(view), view.getId(), name, data));
72
+ }
73
+ }
74
+ }
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import android.content.Context;
4
4
  import android.graphics.Bitmap;
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import android.content.Context;
4
4
 
@@ -16,12 +16,22 @@ final class FastImageGlide {
16
16
  // Set on FastImage's requests, so its decoders (animated WebP and AVIF,
17
17
  // APNG, SVG) only take its own images: another library's images (e.g.
18
18
  // expo-image's) keep that library's decoders.
19
- static final Option<Boolean> REQUEST = Option.memory("com.dylanvann.fastimage.Request", false);
19
+ static final Option<Boolean> REQUEST = Option.memory("com.fastimage.Request", false);
20
20
 
21
21
  static boolean isRequest(@NonNull Options options) {
22
22
  return Boolean.TRUE.equals(options.get(REQUEST));
23
23
  }
24
24
 
25
+ // Set for a source with diskCache false: its download goes through a
26
+ // client without an HTTP cache (FastImageOkHttpProgressGlideModule), so
27
+ // neither the `web` images' HTTP cache nor one the app gave its client
28
+ // keeps it.
29
+ static final Option<Boolean> NO_STORE = Option.memory("com.fastimage.NoStore", false);
30
+
31
+ static boolean isNoStore(@NonNull Options options) {
32
+ return Boolean.TRUE.equals(options.get(NO_STORE));
33
+ }
34
+
25
35
  // The Glide instance FastImage's components (FastImageOkHttpProgressGlideModule)
26
36
  // were registered with.
27
37
  private static volatile Glide registered;
@@ -62,7 +72,7 @@ final class FastImageGlide {
62
72
  synchronized (FastImageGlide.class) {
63
73
  if (registered != glide) {
64
74
  new FastImageOkHttpProgressGlideModule()
65
- .registerComponents(context.getApplicationContext(), glide, registry);
75
+ .register(context.getApplicationContext(), glide, registry, false);
66
76
  }
67
77
  }
68
78
  }
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import android.content.Context;
4
4
 
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import androidx.annotation.NonNull;
4
4
  import androidx.annotation.Nullable;
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import android.content.Context;
4
4
  import androidx.annotation.NonNull;
@@ -11,12 +11,14 @@ import com.bumptech.glide.load.ImageHeaderParser;
11
11
  import com.bumptech.glide.load.ImageHeaderParserUtils;
12
12
  import com.bumptech.glide.load.engine.bitmap_recycle.ArrayPool;
13
13
  import com.bumptech.glide.load.Options;
14
+ import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
14
15
  import com.bumptech.glide.load.model.GlideUrl;
15
16
  import com.bumptech.glide.load.model.ModelLoader;
16
17
  import com.bumptech.glide.load.model.ModelLoaderFactory;
17
18
  import com.bumptech.glide.load.model.MultiModelLoaderFactory;
18
19
  import com.bumptech.glide.module.LibraryGlideModule;
19
20
  import com.facebook.react.modules.network.CookieJarContainer;
21
+ import com.facebook.react.modules.network.ForwardingCookieHandler;
20
22
  import com.facebook.react.modules.network.OkHttpClientProvider;
21
23
 
22
24
  import java.io.File;
@@ -26,6 +28,7 @@ import java.util.Locale;
26
28
  import java.util.concurrent.TimeUnit;
27
29
 
28
30
  import okhttp3.Cache;
31
+ import okhttp3.Dispatcher;
29
32
  import okhttp3.HttpUrl;
30
33
  import okhttp3.Interceptor;
31
34
  import okhttp3.JavaNetCookieJar;
@@ -95,18 +98,23 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
95
98
  @NonNull Glide glide,
96
99
  @NonNull Registry registry
97
100
  ) {
101
+ register(context, glide, registry, true);
102
+ }
103
+
104
+ // `otherLoads`: as part of Glide's setup, where an app's own AppGlideModule
105
+ // runs after. Not when FastImageGlide.get registers FastImage's components
106
+ // itself, after the app's setup, which keeps what it registered for the
107
+ // app's other loads.
108
+ void register(Context context, Glide glide, Registry registry, boolean otherLoads) {
98
109
  OkHttpClient sharedClient = OkHttpClientProvider.getOkHttpClient();
99
- OkHttpClient.Builder builder = sharedClient
100
- .newBuilder()
101
- // A network interceptor, so it runs before the HTTP cache of
102
- // `web` images stores the response (checking it reads it).
103
- .addNetworkInterceptor(createNonImageInterceptor(registry, glide.getArrayPool()));
110
+ OkHttpClient.Builder builder = sharedClient.newBuilder();
104
111
  // React Native's shared client comes with an empty cookie jar (React
105
112
  // Native only fills it in for its networking and Image clients), so
106
113
  // images were loaded without the app's cookies, unlike on iOS. Use the
107
- // same cookie store. A cookie jar the app set up itself is kept.
114
+ // same cookie store (Android's CookieManager, through React Native's
115
+ // ForwardingCookieHandler). A cookie jar the app set up itself is kept.
108
116
  if (sharedClient.cookieJar() instanceof CookieJarContainer) {
109
- builder.cookieJar(new JavaNetCookieJar(new FastImageCookieHandler()));
117
+ builder.cookieJar(new JavaNetCookieJar(new ForwardingCookieHandler()));
110
118
  }
111
119
  // React Native's shared client has no timeouts, so a download that
112
120
  // stopped (e.g. on a connection that died) never ended, and every
@@ -117,7 +125,26 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
117
125
  // longer than any.
118
126
  if (sharedClient.connectTimeoutMillis() == 0) builder.connectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
119
127
  if (sharedClient.readTimeoutMillis() == 0) builder.readTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
120
- OkHttpClient client = builder.build();
128
+ OkHttpClient appClient = builder.build();
129
+ // Images the app loads with Glide itself (a GlideUrl, from its own
130
+ // native code or another library) go through the same client, as
131
+ // expo-image does, instead of the default one Glide's OkHttp
132
+ // integration registers: the app's interceptors and cookies, these
133
+ // timeouts, and one connection pool. Not FastImage's check that a
134
+ // response is an image (below), which other loads, like a video's
135
+ // frame, can't pass. An app's own AppGlideModule runs after, and can
136
+ // register another.
137
+ // With a dispatcher of their own: FastImage's downloads count on
138
+ // having the client's requests per host to themselves
139
+ // (FastImageSharedDownloads), so the app's loads mustn't take them.
140
+ if (otherLoads) registry.replace(GlideUrl.class, InputStream.class,
141
+ new OkHttpUrlLoader.Factory(appClient.newBuilder().dispatcher(new Dispatcher()).build()));
142
+ OkHttpClient client = appClient
143
+ .newBuilder()
144
+ // A network interceptor, so it runs before the HTTP cache of
145
+ // `web` images stores the response (checking it reads it).
146
+ .addNetworkInterceptor(createNonImageInterceptor(registry, glide.getArrayPool()))
147
+ .build();
121
148
  // `cache: 'web'` skips Glide's caches and relies on HTTP caching, so
122
149
  // those urls get a client with an HTTP cache (#280): one of their own,
123
150
  // not the app's (if it gave React Native's shared client one), so
@@ -127,7 +154,10 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
127
154
  webCache = new Cache(new File(context.getCacheDir(), "fast-image-http-cache"), WEB_CACHE_SIZE);
128
155
  webClient = client.newBuilder().cache(webCache).build();
129
156
  FastImageSharedDownloads.setDirectory(new File(context.getCacheDir(), "fast-image-downloads"));
130
- registry.prepend(FastImageUrl.class, InputStream.class, new UrlLoaderFactory(client, webClient));
157
+ // diskCache false: no HTTP cache at all, also when the app's client has
158
+ // one.
159
+ OkHttpClient noStoreClient = client.newBuilder().cache(null).build();
160
+ registry.prepend(FastImageUrl.class, InputStream.class, new UrlLoaderFactory(client, webClient, noStoreClient));
131
161
  FastImageSvg.register(registry, glide.getBitmapPool());
132
162
  FastImageAnimated.register(context, glide, registry);
133
163
  FastImageApng.register(registry);
@@ -141,16 +171,19 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
141
171
  // Loads FastImage's remote images (FastImageUrls), with one download of an
142
172
  // image at a time, shared by its requests (FastImageSharedDownloads):
143
173
  // `web` ones (FastImageWebGlideUrls) with the client with the HTTP cache,
144
- // others with the other client. FastImageUrl isn't a GlideUrl, so Glide
174
+ // others with the other client, and those with diskCache false
175
+ // (FastImageGlide.NO_STORE) with a client without any. FastImageUrl isn't a GlideUrl, so Glide
145
176
  // doesn't also give these to other GlideUrl loaders, which it would try
146
177
  // after a failed load (e.g. a 404, requested again).
147
178
  private static class UrlLoaderFactory implements ModelLoaderFactory<FastImageUrl, InputStream> {
148
179
  private final OkHttpClient client;
149
180
  private final OkHttpClient webClient;
181
+ private final OkHttpClient noStoreClient;
150
182
 
151
- UrlLoaderFactory(OkHttpClient client, OkHttpClient webClient) {
183
+ UrlLoaderFactory(OkHttpClient client, OkHttpClient webClient, OkHttpClient noStoreClient) {
152
184
  this.client = client;
153
185
  this.webClient = webClient;
186
+ this.noStoreClient = noStoreClient;
154
187
  }
155
188
 
156
189
  @NonNull
@@ -159,8 +192,10 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
159
192
  return new ModelLoader<FastImageUrl, InputStream>() {
160
193
  @Override
161
194
  public LoadData<InputStream> buildLoadData(@NonNull FastImageUrl model, int width, int height, @NonNull Options options) {
162
- return FastImageSharedDownloads.loadData(
163
- model.url, model.url instanceof FastImageWebGlideUrl ? webClient : client);
195
+ OkHttpClient urlClient = FastImageGlide.isNoStore(options) ? noStoreClient
196
+ : model.url instanceof FastImageWebGlideUrl ? webClient
197
+ : client;
198
+ return FastImageSharedDownloads.loadData(model.url, urlClient);
164
199
  }
165
200
 
166
201
  @Override
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import android.graphics.drawable.Drawable;
4
4
 
@@ -84,6 +84,11 @@ public class FastImageRequestListener implements RequestListener<Drawable> {
84
84
  dataSource == DataSource.RESOURCE_DISK_CACHE);
85
85
  // Before the view shows it (the target does once this returns).
86
86
  view.onImageSize(size);
87
+ // Only onLoad and onLoadEnd need a local image's size read from it:
88
+ // without them, don't (scale-down and none lay it out from the decoded
89
+ // image meanwhile). (After get, which also forgets a size that mustn't
90
+ // be reused.)
91
+ if (!view.handles(FastImageEvents.LOAD | FastImageEvents.LOAD_END)) return false;
87
92
  if (size != null) {
88
93
  sendLoad(view, size);
89
94
  return false;
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import android.os.Process;
4
4
 
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import android.content.Context;
4
4
  import android.content.res.Resources;
@@ -156,6 +156,17 @@ public class FastImageSource extends ImageSource {
156
156
  return mMemoryCache;
157
157
  }
158
158
 
159
+ // `diskCache`: whether the image is kept in the disk cache.
160
+ private boolean mDiskCache = true;
161
+
162
+ void setDiskCache(boolean diskCache) {
163
+ mDiskCache = diskCache;
164
+ }
165
+
166
+ boolean isDiskCache() {
167
+ return mDiskCache;
168
+ }
169
+
159
170
  // An http(s) url.
160
171
  boolean isRemote() {
161
172
  String scheme = mUri == null ? null : mUri.getScheme();
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import android.content.Context;
4
4
  import android.graphics.BitmapFactory;
@@ -110,13 +110,23 @@ final class FastImageSourceSize {
110
110
  // downsample strategy it implies wrapped by capture, and then blur if it
111
111
  // isn't null. Not downsampled (downsample false), the image isn't cropped
112
112
  // or fitted to the view's size either: the view scales it as it draws it.
113
- static RequestOptions scaleTypeOptions(@Nullable ImageView.ScaleType scaleType, Capture capture, @Nullable FastImageBlur blur,
113
+ static RequestOptions scaleTypeOptions(
114
+ @Nullable ImageView.ScaleType scaleType,
115
+ Capture capture,
116
+ @Nullable FastImageCrop crop,
117
+ @Nullable FastImageBlur blur,
114
118
  boolean downsample) {
115
119
  RequestOptions options = new RequestOptions();
116
120
  BitmapTransformation transformation = null;
117
121
  if (scaleType != null && downsample) {
118
122
  switch (scaleType) {
119
123
  case CENTER_CROP:
124
+ if (crop != null) {
125
+ // At objectPosition, rather than the center.
126
+ options = options.optionalTransform(crop);
127
+ transformation = crop;
128
+ break;
129
+ }
120
130
  options = options.optionalCenterCrop();
121
131
  transformation = new CenterCrop();
122
132
  break;
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import android.graphics.Bitmap;
4
4
 
@@ -45,7 +45,7 @@ final class FastImageSvg {
45
45
  // the view. Part of the disk cache key, since the bitmap's size depends on
46
46
  // them. Unset (0) for the other fits, which draw it for the view's size.
47
47
  static final Option<Float> DENSITY = Option.disk(
48
- "com.dylanvann.fastimage.FastImageSvg.Density", 0f,
48
+ "com.fastimage.FastImageSvg.Density", 0f,
49
49
  new Option.CacheKeyUpdater<Float>() {
50
50
  @Override
51
51
  public void update(@NonNull byte[] keyBytes, @NonNull Float value, @NonNull MessageDigest messageDigest) {
@@ -54,7 +54,7 @@ final class FastImageSvg {
54
54
  }
55
55
  });
56
56
  static final Option<Boolean> FITS = Option.disk(
57
- "com.dylanvann.fastimage.FastImageSvg.Fits", false,
57
+ "com.fastimage.FastImageSvg.Fits", false,
58
58
  new Option.CacheKeyUpdater<Boolean>() {
59
59
  @Override
60
60
  public void update(@NonNull byte[] keyBytes, @NonNull Boolean value, @NonNull MessageDigest messageDigest) {
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import android.graphics.Bitmap;
4
4
  import android.graphics.Canvas;
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import androidx.annotation.NonNull;
4
4
 
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import static com.bumptech.glide.request.RequestOptions.signatureOf;
4
4
 
@@ -43,16 +43,15 @@ class FastImageViewConverter {
43
43
  put("high", Priority.HIGH);
44
44
  }};
45
45
 
46
- private static final Map<String, ImageView.ScaleType> FAST_IMAGE_RESIZE_MODE_MAP =
46
+ // objectFit's scale types. scale-down and none are laid out by the view
47
+ // itself, at the image's own size in dp (see
48
+ // FastImageViewWithUrl.updateImageMatrix).
49
+ private static final Map<String, ImageView.ScaleType> FAST_IMAGE_OBJECT_FIT_MAP =
47
50
  new HashMap<String, ImageView.ScaleType>() {{
48
51
  put("contain", ScaleType.FIT_CENTER);
49
52
  put("cover", ScaleType.CENTER_CROP);
50
- put("stretch", ScaleType.FIT_XY);
51
- put("center", ScaleType.CENTER_INSIDE);
52
- // objectFit="scale-down": as center, laid out in dp (see
53
- // FastImageViewWithUrl.setResizeMode).
53
+ put("fill", ScaleType.FIT_XY);
54
54
  put("scale-down", ScaleType.CENTER_INSIDE);
55
- // objectFit="none": the image at its own size, centered.
56
55
  put("none", ScaleType.CENTER);
57
56
  }};
58
57
 
@@ -63,6 +62,13 @@ class FastImageViewConverter {
63
62
  return uri != null && !uri.trim().isEmpty();
64
63
  }
65
64
 
65
+ // `diskCache`: whether the image is kept in the disk cache (true unless
66
+ // the source sets false).
67
+ static boolean isDiskCache(@Nullable ReadableMap source) {
68
+ return source == null || !source.hasKey("diskCache") || source.getType("diskCache") != ReadableType.Boolean
69
+ || source.getBoolean("diskCache");
70
+ }
71
+
66
72
  // Resolve the source uri to a file path that android understands.
67
73
  static @Nullable
68
74
  FastImageSource getImageSource(Context context, @Nullable ReadableMap source) {
@@ -72,6 +78,7 @@ class FastImageViewConverter {
72
78
  if (source.hasKey("memoryCache") && source.getType("memoryCache") == ReadableType.Boolean) {
73
79
  imageSource.setMemoryCache(source.getBoolean("memoryCache"));
74
80
  }
81
+ imageSource.setDiskCache(isDiskCache(source));
75
82
  if (source.hasKey("cacheKey") && source.getType("cacheKey") == ReadableType.String) {
76
83
  imageSource.setCacheKey(source.getString("cacheKey"));
77
84
  }
@@ -121,6 +128,13 @@ class FastImageViewConverter {
121
128
  break;
122
129
  }
123
130
 
131
+ // diskCache false: neither written to Glide's disk cache nor read from
132
+ // it, nor to an HTTP cache (NO_STORE).
133
+ final boolean noStore = imageSource != null && !imageSource.isDiskCache();
134
+ if (noStore) {
135
+ diskCacheStrategy = DiskCacheStrategy.NONE;
136
+ }
137
+
124
138
  RequestOptions options = new RequestOptions()
125
139
  .diskCacheStrategy(diskCacheStrategy)
126
140
  .onlyRetrieveFromCache(onlyFromCache)
@@ -128,7 +142,8 @@ class FastImageViewConverter {
128
142
  .skipMemoryCache(skipMemoryCache || (imageSource != null && !imageSource.isMemoryCache()))
129
143
  .priority(priority)
130
144
  .placeholder(TRANSPARENT_DRAWABLE)
131
- .set(FastImageGlide.REQUEST, true);
145
+ .set(FastImageGlide.REQUEST, true)
146
+ .set(FastImageGlide.NO_STORE, noStore);
132
147
 
133
148
  // imageSource is null when only a defaultSource is shown.
134
149
  if (imageSource != null && imageSource.isResource()) {
@@ -163,7 +178,7 @@ class FastImageViewConverter {
163
178
  }
164
179
 
165
180
  static ScaleType getScaleType(String propValue) {
166
- return getValue("resizeMode", "cover", FAST_IMAGE_RESIZE_MODE_MAP, propValue);
181
+ return getValue("objectFit", "cover", FAST_IMAGE_OBJECT_FIT_MAP, propValue);
167
182
  }
168
183
 
169
184
  private static <T> T getValue(String propName, String defaultPropValue, Map<String, T> map, String propValue) {