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
package/README.md CHANGED
@@ -18,7 +18,7 @@ React Native's `Image` component handles image caching like browsers for the mos
18
18
 
19
19
  ## Features
20
20
 
21
- - **Performance**, with images [decoded at the size they're shown](#downsample): in [benchmarks](docs/benchmarks.md), FastImage shows images about as fast as other React Native image components and uses among the least memory for large photos.
21
+ - **Performance**: in [benchmarks](docs/benchmarks.md), FastImage shows images about as fast as other React Native image components on iOS and among the fastest on Android, [significantly faster in some scenarios](docs/benchmarks.md#opening-a-photo-while-others-load), and uses among the least memory for large photos.
22
22
  - **Aggressive caching**: an image downloads once, then shows from disk or memory until its url changes, without flickering ([freshness](#sourcecache), [cache keys](#sourcecachekey), [size limits](#configurecachelimits)).
23
23
  - **Preloading**, with a [result per image](#preloadsources) and the [cached file's path](#getcachepathsource).
24
24
  - **Headers**, e.g. for authentication ([`headers`](#sourceheaders)).
@@ -57,8 +57,6 @@ See [Formats](docs/formats.md) for the versions of iOS and Android each format n
57
57
 
58
58
  ## Installation
59
59
 
60
- Works with React Native 0.65 and later (iOS 13 and later, Android `minSdkVersion` 21 and later), with the New Architecture (through React Native's interop layer) and the legacy architecture, with Expo, and on tvOS with [React Native tvOS](https://github.com/react-native-tvos/react-native-tvos). It's tested on React Native 0.87 with the New Architecture, 0.73 with the legacy architecture, Expo SDK 57, and React Native tvOS 0.87. A native New Architecture component is planned for a future major version.
61
-
62
60
  ```bash
63
61
  npm install react-native-fast-image
64
62
  cd ios && pod install
@@ -72,11 +70,13 @@ npx expo install react-native-fast-image
72
70
 
73
71
  It has native code, so it needs a [development build](https://docs.expo.dev/develop/development-builds/introduction/) (e.g. `npx expo run:ios`), not Expo Go.
74
72
 
73
+ Needs React Native 0.83 or later with the New Architecture (Expo SDK 55 or later), iOS/tvOS 15.1 or later, and Android 7.0 (API 24) or later; on tvOS, it works with [React Native tvOS](https://github.com/react-native-tvos/react-native-tvos). Apps on the legacy architecture or older React Native can use FastImage 9 (`npm install react-native-fast-image@9`). Upgrading from FastImage 9: see [Upgrading from 9.x](docs/upgrading.md).
74
+
75
75
  To set the cache's size when the app starts, see [Native config](#native-config).
76
76
 
77
77
  If your Android app has its own Glide `AppGlideModule`, read [using FastImage with an AppGlideModule](docs/android-build-settings.md#if-your-app-has-its-own-appglidemodule) first, or FastImage may not work.
78
78
 
79
- On iOS, FastImage works with SDWebImage 5.11.1 and later, but apps that run on iOS 26 or later need 5.21.4 or later: earlier versions can crash there while loading images ([SDWebImage#3849](https://github.com/SDWebImage/SDWebImage/issues/3849)). A new install gets the latest version. If your `Podfile.lock` has an older one, update it with `cd ios && pod update SDWebImage`.
79
+ If `pod install` can't find a compatible SDWebImage (FastImage needs 5.21.4 or later), update it with `cd ios && pod update SDWebImage`.
80
80
 
81
81
  ## Usage
82
82
 
@@ -100,7 +100,7 @@ const YourImage = () => (
100
100
 
101
101
  ### `FastImage`
102
102
 
103
- It also takes React Native's View props, such as accessibility props, `testID`, `nativeID`, `onLayout` and `pointerEvents`.
103
+ It's a single native view, which also takes React Native's View props, such as accessibility props, `testID`, `nativeID`, `onLayout`, `pointerEvents` and `hitSlop`. A ref to it is that view (e.g. for `measure`). It doesn't take children: use [`FastImageBackground`](#fastimagebackground) for content over an image.
104
104
 
105
105
  <!-- api:props start (generated from src/ by website/scripts/generate.mts) -->
106
106
 
@@ -201,6 +201,16 @@ Whether the decoded image is kept in the memory cache. With `false` it's only ke
201
201
 
202
202
  ---
203
203
 
204
+ ##### `source.diskCache`
205
+
206
+ **Type:** `boolean` · **Default:** `true`
207
+
208
+ Whether the image is kept on disk. With `false` it isn't kept in the disk cache or an HTTP cache, or read from them. Use it for images the app shouldn't keep once they've been shown (e.g. disappearing messages, or where a security policy doesn't allow caching sensitive images), images that change every time they load, or large images shown once, which would push other images out of the disk cache. The image is downloaded again whenever it isn't in memory, e.g. for a view of another size (or on Android, a change of `blurRadius` or `objectFit`), so with `memoryCache: false` too it's downloaded each time it's shown. With `cache: 'web'` it isn't kept in memory either, so it's downloaded every time it loads. With `cache: 'cacheOnly'` it's only looked for in memory. On Android, a large download is held in a temporary file while it loads, as every download is, deleted as soon as it's opened.
209
+
210
+ `FastImage.preload`, `getCachePath` and `writeToCache` resolve not `ok` for it: there's no file, and a view decodes the image for its own size, so it may download a preloaded one again. A source for the same url (or `cacheKey`) without `diskCache: false` still stores the image.
211
+
212
+ ---
213
+
204
214
  ##### `source.width`
205
215
 
206
216
  **Type:** `number`
@@ -241,39 +251,32 @@ On Android, `defaultSource` doesn't show in debug builds: there the dev server s
241
251
 
242
252
  How the image fits the view, as CSS's `object-fit` does.
243
253
 
244
- - `'cover'`: scales it uniformly (keeping its aspect ratio) so it covers the view (minus padding), cropping what doesn't fit.
245
- - `'contain'`: scales it uniformly (keeping its aspect ratio) so all of it fits in the view (minus padding).
254
+ - `'cover'`: scales it uniformly (keeping its aspect ratio) so it covers the view (inside its borders), cropping what doesn't fit.
255
+ - `'contain'`: scales it uniformly (keeping its aspect ratio) so all of it fits in the view (inside its borders).
246
256
  - `'fill'`: scales its width and height separately to fill the view, which can change its aspect ratio.
247
257
  - `'none'`: shows it at its own size, centered, cropped if it's larger than the view.
248
258
  - `'scale-down'`: shows it at its own size, centered, or scaled down uniformly to fit if it's larger than the view (the smaller of `'none'` and `'contain'`).
249
259
 
250
260
  An image's own size is its size in pixels, as points (dp on Android), as CSS counts an image's pixels: a 300 × 200 image is 300 × 200 points. A bundled image (`require()`) is its size in points.
251
261
 
252
- It can also be set in `style`; the prop wins. Either one overrides `resizeMode`.
262
+ It can also be set in `style`; the prop wins.
253
263
 
254
264
  ---
255
265
 
256
- #### `resizeMode`
257
-
258
- **Type:** `ResizeMode` · **Default:** `'cover'`
266
+ #### `objectPosition`
259
267
 
260
- **Deprecated:** Use `objectFit` instead.
268
+ **Type:** `ObjectPosition` · **Default:** `'50% 50%'`
261
269
 
262
- How the image fills the view.
270
+ Where the image is in the view, as CSS's `object-position` places it: where its edges are when it doesn't fill the view exactly (`contain`, `cover`, `none` and `scale-down`; with `fill` it always fills it).
263
271
 
264
- - `'contain'`: as `objectFit="contain"`.
265
- - `'cover'`: as `objectFit="cover"`.
266
- - `'stretch'`: as `objectFit="fill"`.
267
- - `'center'`: as `objectFit="scale-down"`, except that on Android an image smaller than the view is shown at its size in pixels on the screen, so smaller than on iOS and the web.
268
- - `'repeat'`: repeats it to cover the view, from its top-left corner, at the image's own size in pixels (a bundled image at its size in points), scaled down to fit if it's larger than the view. An animated image repeats its first frame, and `defaultSource` repeats too.
269
-
270
- ---
272
+ - A string in CSS's syntax: one or two keywords (`'top'`, `'left bottom'`), lengths in points (`'10px 20px'`, with `px`) or percentages (`'25% 75%'`), or offsets from an edge (`'right 10px bottom 20%'`). A percentage puts that point of the image at that point of the view: `'0% 0%'` is the top-left corner, `'100% 100%'` the bottom-right.
273
+ - An object with one of `top` and `bottom` and one of `left` and `right`, each in points (a number) or a percentage (`'25%'`), e.g. `{ right: 10, bottom: '20%' }`. A missing axis is centered.
271
274
 
272
- #### `fallback`
275
+ Points are dp on Android. An invalid value is ignored (the image is centered), with a warning in development. `defaultSource` is placed the same way.
273
276
 
274
- **Type:** `boolean`
275
-
276
- If true, the image is shown with React Native's `Image` instead, styled and laid out the same way. FastImage's own features, such as its caching options, `priority` and `transition`, don't apply.
277
+ ```jsx
278
+ <FastImage source={{ uri }} objectFit="cover" objectPosition="top" />
279
+ ```
277
280
 
278
281
  ---
279
282
 
@@ -326,9 +329,11 @@ Pauses an animated image (GIF, animated WebP, APNG, or animated AVIF) on the fra
326
329
 
327
330
  #### `transition`
328
331
 
329
- **Type:** `number | boolean | Transition | null` · **Default:** `false`
332
+ **Type:** `number | boolean | Transition | null`
333
+
334
+ Fades the image in when it loads. `true` fades for the default's duration (see `FastImage.setDefaults`), or the platform's usual length if the default doesn't fade; a number is the duration in milliseconds, `false` (or 0) is no fade, or pass a `Transition`.
330
335
 
331
- Fades the image in when it loads. `true` uses the platform's usual fade, a number is the duration in milliseconds, or pass a `Transition`.
336
+ By default, images fade in on Android (300 ms), and not on iOS. `FastImage.setDefaults` changes that for every image; an image's own `transition` wins, and the settings it leaves out come from the default. `null` is the default.
332
337
 
333
338
  Downloads, local files (`file://`, `content://`) and bundled images (`require()`) fade in. In lists that reuse views (e.g. FlashList), set `recyclingKey`, so a reused view starts empty and its image fades in, instead of showing the previous item's image until it loads.
334
339
 
@@ -349,7 +354,7 @@ Decodes a large image at about the size it's shown at, instead of at full size,
349
354
  - `true`: an image at least twice the size its view needs is decoded at about the view's size (on Android, any image larger than its view). If the view grows, the image is decoded again for its new size (from the disk cache).
350
355
  - `false`: images are decoded at full size, e.g. for an image that's zoomed in on with a transform (a pinch-to-zoom viewer), which would otherwise show the smaller copy enlarged. **It uses more memory:** a 12-megapixel photo takes about 48 MB decoded, however small it's shown. On Android, an image over 16 megapixels (4096 × 4096) is decoded at the largest size under that, which Android can still draw.
351
356
 
352
- It doesn't change `onLoad`'s width and height (the image's own size) or the cached file. On iOS it needs SDWebImage 5.19.7 or later: before 5.19 images are decoded at full size, and 5.19.0 to 5.19.6 show photos stored sideways with an EXIF orientation (most phone photos) sideways. Photo library images are always decoded at about the view's size. Android 16 and later decode animated WebP at full size either way, and scale it as they draw it.
357
+ It doesn't change `onLoad`'s width and height (the image's own size) or the cached file. Photo library images are always decoded at about the view's size. Android 16 and later decode animated WebP at full size either way, and scale it as they draw it.
353
358
 
354
359
  If you control the images, serve them at the size they're shown (resized on your server or by an image CDN), which also saves bandwidth.
355
360
 
@@ -369,7 +374,7 @@ It's for still images, or a radius that changes now and then (e.g. blurring a ph
369
374
  - The image is blurred at about the size it's shown at, off the main thread. The cached file stays the original image, so `getCachePath` and other views of it aren't affected.
370
375
  - Changing it blurs the image that's showing again, without sending the load events again.
371
376
 
372
- To animate a blur, or to blur an animated image, use React Native's `filter` style instead, which the GPU draws: `style={{ filter: [{ blur: 6 }] }}`. It needs the New Architecture. React Native's docs list `blur` for Android 12+ only; on iOS it's behind an experimental React Native feature flag (`enableSwiftUIBasedFilters`, SwiftUI-based filters).
377
+ To animate a blur, or to blur an animated image, use React Native's `filter` style instead, which the GPU draws: `style={{ filter: [{ blur: 6 }] }}`. React Native's docs list `blur` for Android 12+ only; on iOS it's behind an experimental React Native feature flag (`enableSwiftUIBasedFilters`, SwiftUI-based filters).
373
378
 
374
379
  ---
375
380
 
@@ -439,7 +444,7 @@ Called when the image finishes loading, whether it was successful or an error, w
439
444
 
440
445
  **Type:** `StyleProp<ImageStyle>`
441
446
 
442
- The image's style: View's style props (`borderRadius` clips the image), and `tintColor`, as with React Native's `Image` (the `tintColor` prop wins).
447
+ The image's style: View's style props (`borderRadius` clips the image, and borders inset it, but padding doesn't), and `tintColor`, as with React Native's `Image` (the `tintColor` prop wins).
443
448
 
444
449
  ---
445
450
 
@@ -449,24 +454,12 @@ The image's style: View's style props (`borderRadius` clips the image), and `tin
449
454
 
450
455
  If supplied, changes the color of all the non-transparent pixels to the given color.
451
456
 
452
- ---
453
-
454
- #### `children`
455
-
456
- **Type:** `ReactNode`
457
-
458
- **Deprecated:** In the next major version, `FastImage` won't render children: use `FastImageBackground`.
459
-
460
- Render children within the image.
461
-
462
457
  <!-- api:props end -->
463
458
 
464
459
  ### `FastImageBackground`
465
460
 
466
461
  An image with content on top of it: a view that the image fills, with the children on top.
467
462
 
468
- Use it rather than giving `FastImage` children: in the next major version, `FastImage` won't render children, since the image will be a single native view ([#1220](https://github.com/DylanVann/react-native-fast-image/pull/1220)), which can't hold them. `FastImageBackground` works the same in both.
469
-
470
463
  ```jsx
471
464
  import { FastImageBackground } from 'react-native-fast-image'
472
465
 
@@ -628,11 +621,11 @@ const result = await FastImage.writeToCache(
628
621
 
629
622
  How much the image cache keeps. Set the limits your app starts with in its native config, so they're in effect from the first image, and change them while the app runs with `configureCache`, e.g. from a storage setting. Runtime changes are saved, and used on the next launches too.
630
623
 
631
- | Limit | iOS | Android |
632
- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
633
- | `maxDiskSize`: the most bytes of images kept on disk. When it's over, the least recently used images are removed. | Changes apply at once (the cache is trimmed to half the limit). Default: no limit. | Changes apply from the next launch (Glide's disk cache size is set when it starts). Default: 250 MB. |
634
- | `maxDiskAge`: seconds an image is kept on disk after it was last used. | Default: 1 week (counted from when it was stored before SDWebImage 5.21, unless it's set). | No age limit. |
635
- | `maxMemorySize`: the most bytes of decoded images kept in memory. | Default: no limit (they're removed when the system is low on memory). | About two screenfuls of images.[^glide-memory] |
624
+ | Limit | iOS | Android |
625
+ | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
626
+ | `maxDiskSize`: the most bytes of images kept on disk. When it's over, the least recently used images are removed. | Changes apply at once (the cache is trimmed to half the limit). Default: no limit. | Changes apply from the next launch (Glide's disk cache size is set when it starts). Default: 250 MB. |
627
+ | `maxDiskAge`: seconds an image is kept on disk after it was last used. | Default: 1 week. | No age limit. |
628
+ | `maxMemorySize`: the most bytes of decoded images kept in memory. | Default: no limit (they're removed when the system is low on memory). | About two screenfuls of images.[^glide-memory] |
636
629
 
637
630
  `0` means no limit.
638
631
 
@@ -649,6 +642,25 @@ On Android, if your app has its own `AppGlideModule` (see [using FastImage with
649
642
 
650
643
  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.
651
644
 
645
+ ### `setDefaults(defaults)`
646
+
647
+ **Parameters:** `defaults: FastImageDefaults` · **Returns:** `void`
648
+
649
+ Changes the defaults of every image, including `FastImageBackground`'s. Pass the settings to change; `null` goes back to the built-in default.
650
+
651
+ - `transition`: the [`transition`](#transition) of images that don't set one (its doc describes the built-in default). An image's own `transition` wins, and the settings it leaves out come from the default.
652
+
653
+ ```js
654
+ // In index.js, before images render.
655
+ FastImage.setDefaults({ transition: false }) // no fades
656
+ FastImage.setDefaults({ transition: true }) // fades on iOS too
657
+ FastImage.setDefaults({ transition: Platform.select({ ios: 200 }) }) // 200 ms on iOS; Android keeps its default
658
+ FastImage.setDefaults({ transition: { duration: 200, betweenImages: true } })
659
+ FastImage.setDefaults({ transition: null }) // the built-in default
660
+ ```
661
+
662
+ It isn't saved: call it when the app starts. An image already showing uses a change once one of its props changes, for its next load. It's ignored on the web, where images don't fade.
663
+
652
664
  ## Types
653
665
 
654
666
  <!-- api:types start (generated from src/ by website/scripts/generate.mts) -->
@@ -698,6 +710,14 @@ How fresh an image must be: see [`source.cache`](#sourcecache).
698
710
 
699
711
  ---
700
712
 
713
+ ### `FastImageDefaults`
714
+
715
+ `FastImage.setDefaults`'s settings.
716
+
717
+ - `transition?` (`number | boolean | Transition | null`): The `transition` of images that don't set one (an image's own settings win, and those it leaves out come from this). `null` goes back to the built-in default (see `transition`).
718
+
719
+ ---
720
+
701
721
  ### `LoadResult`
702
722
 
703
723
  **Type:** `{ ok: true; width: number; height: number } | { ok: false; error: string }`
@@ -714,6 +734,14 @@ How the image fits the view: see [`objectFit`](#objectfit).
714
734
 
715
735
  ---
716
736
 
737
+ ### `ObjectPosition`
738
+
739
+ **Type:** `string | ({ top?: PositionLength; bottom?: never } | { bottom: PositionLength; top?: never }) & ({ left?: PositionLength; right?: never } | { right: PositionLength; left?: never })`
740
+
741
+ Where the image is in the view: see [`objectPosition`](#objectposition).
742
+
743
+ ---
744
+
717
745
  ### `OnErrorEvent`
718
746
 
719
747
  `onError`'s event: `nativeEvent.error` says what went wrong, e.g. an HTTP status code or an image that can't be decoded.
@@ -724,7 +752,7 @@ How the image fits the view: see [`objectFit`](#objectfit).
724
752
 
725
753
  ### `OnLoadEvent`
726
754
 
727
- `onLoad`'s event: `nativeEvent` has the image's `width` and `height`, in pixels, and `target`, the view's React tag (missing on Android with the legacy architecture).
755
+ `onLoad`'s event: `nativeEvent` has the image's own `width` and `height` (see `onLoad`), and `target`, the view's React tag (on iOS and Android; not on the web).
728
756
 
729
757
  - `nativeEvent` (`{ width: number; height: number; target?: number }`)
730
758
 
@@ -738,6 +766,14 @@ How the image fits the view: see [`objectFit`](#objectfit).
738
766
 
739
767
  ---
740
768
 
769
+ ### `PositionLength`
770
+
771
+ **Type:** `` number | `${number}%` ``
772
+
773
+ A length in points (dp on Android), or a percentage: see [`objectPosition`](#objectposition).
774
+
775
+ ---
776
+
741
777
  ### `PreloadFailure`
742
778
 
743
779
  A preloaded source that failed to load.
@@ -775,19 +811,11 @@ An image's load priority: see [`source.priority`](#sourcepriority).
775
811
 
776
812
  ---
777
813
 
778
- ### `ResizeMode`
779
-
780
- **Type:** `'contain' | 'cover' | 'stretch' | 'center' | 'repeat'`
781
-
782
- How the image fits the view: see [`resizeMode`](#resizemode).
783
-
784
- ---
785
-
786
814
  ### `Transition`
787
815
 
788
816
  How the image fades in: see [`transition`](#transition).
789
817
 
790
- - `duration?` (`number`): How long the fade takes, in milliseconds; 0 means no fade. Defaults to the platform's usual length: 300 ms on Android, 250 ms on iOS.
818
+ - `duration?` (`number`): How long the fade takes, in milliseconds; 0 means no fade. Defaults to the default transition's (see `FastImage.setDefaults`) if it fades, otherwise the platform's usual length: 300 ms on Android, 250 ms on iOS.
791
819
  - `betweenImages?` (`boolean`, default `false`): Also fades between images: a new `source` replacing an image that's showing cross-dissolves from it. Otherwise only an image that appears over nothing (or over `defaultSource`) fades in, and a new source replaces the image showing at once, once it has loaded.
792
820
  - `skipOnCacheHit?` (`'none' | 'memory' | 'all' | null`, default `'memory'`): Skips the fade for an image from a cache, so images already loaded show at once, e.g. in a list scrolled back up or a reused row.
793
821
 
@@ -795,7 +823,7 @@ How the image fades in: see [`transition`](#transition).
795
823
  - `'all'`: skips it for images from the memory or disk cache too, so images that download fade in, and local files and bundled images usually only the first time (the disk cache usually keeps them too).
796
824
  - `'none'`: always fades.
797
825
 
798
- Downloads, local files and bundled images (`require()`) fade in. On Android, a `cache: 'web'` image from its HTTP cache, without a request, counts as one from the memory cache (these images aren't kept there).
826
+ On Android, a `cache: 'web'` image from its HTTP cache, without a request, counts as one from the memory cache (these images aren't kept there).
799
827
 
800
828
  <!-- api:types end -->
801
829
 
@@ -854,12 +882,20 @@ FastImage works on the web with [react-native-web](https://necolas.github.io/rea
854
882
 
855
883
  Support is minimal:
856
884
 
857
- - Props that work: `source` (a `uri`, a `require()`d image, or several sizes), `defaultSource`, `objectFit`, `resizeMode`, `tintColor`, `blurRadius`, `style`, children, `onLoadStart`, `onLoad`, `onError`, `onLoadEnd`, and View props such as `testID`, accessibility props, `onLayout` and `pointerEvents`.
858
- - Ignored: `source.headers` (a browser can't send them for an image), `source.priority`, `source.cache`, `source.cacheKey`, `source.memoryCache`, `recyclingKey`, `loop`, `imageRendering`, `paused`, `transition`, `downsample`, `fallback` and `onProgress`.
859
- - The image is an `<img>` element that fills the view inside its borders, with `objectFit` as its CSS `object-fit` (and `resizeMode`'s `stretch` as `fill`, `center` as `scale-down`). With `resizeMode="repeat"`, it's a repeated CSS background, with a transparent `<img>` over it. `tintColor` is an SVG filter and `blurRadius` a CSS `blur()`, and `defaultSource` is another `<img>`, under the image until it has loaded. A new `source` gets a new `<img>`, so the previous image doesn't stay while it loads (with several sizes, the browser shows it until the new one has loaded).
860
- - Several sizes are shown with a lazily loaded `<img>` whose `srcset` lists them, with `sizes="auto, 100vw"`: the browser loads the one for the width the image is shown at, in device pixels (usually the smallest that's at least as wide). Browsers that don't support `sizes="auto"` use the viewport's width. `resizeMode="repeat"` shows them as `cover`.
885
+ - Props that work: `source` (a `uri`, a `require()`d image, or several sizes), `defaultSource`, `objectFit`, `objectPosition`, `tintColor`, `blurRadius`, `style`, `onLoadStart`, `onLoad`, `onError`, `onLoadEnd`, and View props such as `testID`, accessibility props, `onLayout` and `pointerEvents`.
886
+ - Ignored: `source.headers` (a browser can't send them for an image), `source.priority`, `source.cache`, `source.cacheKey`, `source.memoryCache`, `source.diskCache`, `recyclingKey`, `loop`, `imageRendering`, `paused`, `transition`, `downsample` and `onProgress`.
887
+ - The image is an `<img>` element that fills the view inside its borders, with `objectFit` and `objectPosition` as its CSS `object-fit` and `object-position`. `tintColor` is an SVG filter and `blurRadius` a CSS `blur()`, and `defaultSource` is another `<img>`, under the image until it has loaded. A new `source` gets a new `<img>`, so the previous image doesn't stay while it loads (with several sizes, the browser shows it until the new one has loaded).
888
+ - Several sizes are shown with a lazily loaded `<img>` whose `srcset` lists them, with `sizes="auto, 100vw"`: the browser loads the one for the width the image is shown at, in device pixels (usually the smallest that's at least as wide). Browsers that don't support `sizes="auto"` use the viewport's width.
861
889
  - `FastImage.preload` loads the images into the browser's cache and resolves with a result per source. `clearMemoryCache`, `clearDiskCache` and `configureCache` resolve without doing anything (the browser manages its cache), and `getCachePath` and `writeToCache` resolve with `{ ok: false, error: 'Not supported on the web' }`.
862
890
 
891
+ ## Jest
892
+
893
+ With React Native's Jest preset, FastImage renders without any setup, as its native view (`FastImageView`, in snapshots). Its functions need the native module, which Jest doesn't have, so they throw: mock the ones a test calls, e.g.
894
+
895
+ ```js
896
+ jest.spyOn(FastImage, 'preload').mockResolvedValue([])
897
+ ```
898
+
863
899
  ## Troubleshooting
864
900
 
865
901
  If you have any problems using this library try the steps in [troubleshooting](docs/troubleshooting.md) and see if they fix it.
@@ -9,20 +9,25 @@ Pod::Spec.new do |s|
9
9
  s.authors = { "Dylan Vann" => "dylan@dylanvann.com" }
10
10
  s.homepage = "https://github.com/DylanVann/react-native-fast-image#readme"
11
11
  s.license = "MIT"
12
- s.platforms = { :ios => "13.0", :tvos => "13.0" }
12
+ # React Native 0.83's minimums.
13
+ s.platforms = { :ios => "15.1", :tvos => "15.1" }
13
14
  s.framework = 'UIKit'
14
15
  s.requires_arc = true
15
16
  s.source = { :git => "https://github.com/DylanVann/react-native-fast-image.git", :tag => "v#{s.version}" }
16
- s.source_files = "ios/**/*.{h,m}"
17
+ s.source_files = "ios/**/*.{h,m,mm}"
17
18
 
18
- s.dependency 'React-Core'
19
- # Any 5.x from 5.11.1, so apps can use newer versions (and share them with
20
- # other libraries) without having to update. 5.18.7+ has the privacy
21
- # manifest Apple requires.
22
- s.dependency 'SDWebImage', '>= 5.11.1', '< 6.0'
19
+ # React Native's dependencies for a New Architecture component and
20
+ # TurboModule (React-Core, Codegen's output for src/specs, ...).
21
+ install_modules_dependencies(s)
22
+
23
+ # Any 5.x from 5.21.4, so apps can use newer versions (and share them with
24
+ # other libraries, such as expo-image, which uses ~> 5.21.0 from Expo SDK 53)
25
+ # without having to update. downsample needs 5.19.7, tinted animated images
26
+ # and maxDiskAge counting from an image's last use 5.20, and 5.21.4 fixes a
27
+ # crash on iOS 26 (SDWebImage #3849).
28
+ s.dependency 'SDWebImage', '>= 5.21.4', '< 6.0'
23
29
  s.dependency 'SDWebImageWebPCoder', '>= 0.8.4', '< 1.0'
24
- # SVG images. Every 1.x needs iOS 13 (Apple's SVG renderer). From 1.7, as
25
- # expo-image's, so apps with it share one copy.
30
+ # SVG images. From 1.7, as expo-image's, so apps with it share one copy.
26
31
  s.dependency 'SDWebImageSVGCoder', '>= 1.7.0', '< 2.0'
27
32
  # Photo library images (ph://).
28
33
  s.dependency 'SDWebImagePhotosPlugin', '>= 1.2.0', '< 2.0'
@@ -2,22 +2,10 @@ def safeExtGet(prop, fallback) {
2
2
  rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
3
3
  }
4
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
5
  apply plugin: 'com.android.library'
6
+ // Codegen for the component and module specs (src/specs), from the app's
7
+ // React Native Gradle plugin.
8
+ apply plugin: 'com.facebook.react'
21
9
 
22
10
  // Whether the app has expo-image (in a node_modules folder above the app's
23
11
  // android folder, as Node finds it), which ships its own AppGlideModule.
@@ -32,10 +20,12 @@ def appHasExpoImage = {
32
20
  def excludeAppGlideModule = safeExtGet('excludeAppGlideModule', appHasExpoImage())
33
21
 
34
22
  // When changing the default, revisit the Glide rules in consumer-rules.pro.
35
- // 4.15+ animates animated WebP (Android 9+) and AVIF (Android 12+), which
23
+ // 5.0.7: Glide 5.0.9 needs apps to compile against API 37 (React Native
24
+ // 0.83's compileSdk is 36). An app can set another, 4.15 or later: 4.15+
25
+ // animates animated WebP (Android 9+) and AVIF (Android 12+), which
36
26
  // FastImageAnimated builds on. A version that isn't numbered (e.g. "4.+") is
37
27
  // taken to be recent.
38
- def glideVersion = safeExtGet('glideVersion', '4.16.0')
28
+ def glideVersion = safeExtGet('glideVersion', '5.0.7')
39
29
  def glideVersionParts = glideVersion.toString() =~ /^(\d+)\.(\d+)/
40
30
  if (glideVersionParts.find() &&
41
31
  (glideVersionParts.group(1).toInteger() < 4 ||
@@ -43,30 +33,18 @@ if (glideVersionParts.find() &&
43
33
  throw new GradleException("react-native-fast-image needs Glide 4.15 or later, but glideVersion is ${glideVersion}.")
44
34
  }
45
35
 
46
- // Newer versions of the Android Gradle plugin (7.3+) take the namespace from
47
- // build.gradle and warn about the package attribute in AndroidManifest.xml;
48
- // older versions need that attribute.
49
- def supportsNamespace = project.android.hasProperty("namespace")
50
-
51
36
  android {
52
- if (supportsNamespace) {
53
- namespace "com.dylanvann.fastimage"
54
- }
55
- compileSdkVersion safeExtGet('compileSdkVersion', 28)
56
- buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
37
+ namespace = "com.fastimage"
38
+ // React Native 0.83's.
39
+ compileSdkVersion safeExtGet('compileSdkVersion', 36)
57
40
  defaultConfig {
58
- minSdkVersion safeExtGet('minSdkVersion', 21)
59
- targetSdkVersion safeExtGet('targetSdkVersion', 28)
60
- versionCode 1
61
- versionName "1.0"
41
+ minSdkVersion safeExtGet('minSdkVersion', 24)
42
+ targetSdkVersion safeExtGet('targetSdkVersion', 36)
62
43
  // Applied to the app's release build, so apps don't need to add them.
63
44
  consumerProguardFiles 'consumer-rules.pro'
64
45
  }
65
46
  sourceSets {
66
47
  main {
67
- if (supportsNamespace) {
68
- manifest.srcFile "src/main/AndroidManifestNew.xml"
69
- }
70
48
  java {
71
49
  if (excludeAppGlideModule) {
72
50
  exclude "**/FastImageGlideModule.java"
@@ -74,28 +52,24 @@ android {
74
52
  }
75
53
  }
76
54
  }
77
- lintOptions {
78
- abortOnError false
55
+ lint {
56
+ abortOnError = false
79
57
  }
80
58
  }
81
59
 
60
+ react {
61
+ jsRootDir = file("../src/specs")
62
+ libraryName = "RNFastImageSpec"
63
+ codegenJavaPackageName = "com.fastimage"
64
+ }
65
+
82
66
  repositories {
83
- mavenLocal()
84
- maven {
85
- // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
86
- url "$rootDir/../node_modules/react-native/android"
87
- }
88
- maven {
89
- // Android JSC is installed from npm
90
- url "$rootDir/../node_modules/jsc-android/dist"
91
- }
92
67
  google()
93
68
  mavenCentral()
94
69
  }
95
70
 
96
71
  dependencies {
97
- //noinspection GradleDynamicVersion
98
- implementation 'com.facebook.react:react-native:+' // From node_modules
72
+ implementation 'com.facebook.react:react-android'
99
73
  implementation "com.github.bumptech.glide:glide:${glideVersion}"
100
74
  // FastImageGlideModule and FastImageOkHttpProgressGlideModule use @GlideModule.
101
75
  implementation "com.github.bumptech.glide:annotations:${glideVersion}"
@@ -4,16 +4,16 @@
4
4
 
5
5
  # FastImage's classes: its view manager, native module, Glide modules and
6
6
  # events.
7
- -keep public class com.dylanvann.fastimage.* {*;}
8
- -keep public class com.dylanvann.fastimage.** {*;}
7
+ -keep public class com.fastimage.* {*;}
8
+ -keep public class com.fastimage.** {*;}
9
9
 
10
10
  # The Glide rules below cover what Glide's own rules (its library's
11
11
  # proguard-rules.txt) didn't at the version FastImage uses by default
12
- # (glideVersion in build.gradle) and older ones apps may pick. When updating
13
- # Glide, revisit which are still needed: whether Glide's rules now keep
14
- # modules' constructors (4.16.0's still keep only the AppGlideModule's), and
15
- # whether its integrations still register old-style modules in their
16
- # manifests (the OkHttp integration's OkHttpGlideModule still did in 5.0.9).
12
+ # (glideVersion in build.gradle, 5.0.7) and older ones apps may pick. When
13
+ # updating Glide, revisit which are still needed: whether Glide's rules now
14
+ # keep modules' constructors, and whether its integrations still register
15
+ # old-style modules in their manifests (the OkHttp integration's
16
+ # OkHttpGlideModule still did in 5.0.9).
17
17
 
18
18
  # Glide's modules and their constructors: FastImage's, the one Glide
19
19
  # generates from them, and old-style modules Glide finds in the app's manifest
@@ -1,2 +1 @@
1
- <manifest package="com.dylanvann.fastimage">
2
- </manifest>
1
+ <manifest />
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  // An animated image that applies FastImage's loop and paused itself (an APNG,
4
4
  // FastImageApng). The view's target starts it when it's shown.
@@ -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;
@@ -46,7 +46,7 @@ import java.util.concurrent.Executors;
46
46
  // the image's data (which the drawable keeps anyway, to decode its frames
47
47
  // from), off the main thread.
48
48
  //
49
- // Not animated (dontAnimate: blurRadius, resizeMode repeat), they're decoded
49
+ // Not animated (dontAnimate: blurRadius), they're decoded
50
50
  // as their first frame, a bitmap, as GIFs are, and as Glide did before 4.15.
51
51
  // Glide's own decoder for them doesn't check that option.
52
52
  final class FastImageAnimated {
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  import android.graphics.Rect;
4
4
  import android.graphics.drawable.Drawable;
@@ -28,7 +28,7 @@ import java.nio.charset.StandardCharsets;
28
28
  //
29
29
  // The decoders come before Glide's own, and only take PNGs with an animation
30
30
  // control chunk (acTL), when the request animates (not with dontAnimate:
31
- // blurRadius, resizeMode repeat, which get the first frame from Glide's
31
+ // blurRadius, which gets the first frame from Glide's
32
32
  // decoder).
33
33
  final class FastImageApng {
34
34
  // As much of the start of the file as is read to find acTL, which comes
@@ -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;
@@ -26,15 +26,14 @@ import java.security.MessageDigest;
26
26
  // blurred and unblurred views of one image don't share a cached image; the
27
27
  // cached file stays the original.
28
28
  final class FastImageBlur extends BitmapTransformation {
29
- private static final String ID = "com.dylanvann.fastimage.FastImageBlur";
29
+ private static final String ID = "com.fastimage.FastImageBlur";
30
30
  private static final byte[] ID_BYTES = ID.getBytes(Charset.forName("UTF-8"));
31
31
 
32
32
  // In pixels on screen.
33
33
  private final float radius;
34
34
  private final ImageView.ScaleType scaleType;
35
35
  // Pixels on screen per pixel of the image at its own size (scale-down and
36
- // none show it at that size: see FastImageViewWithUrl.updateImageMatrix;
37
- // 1 for resizeMode center).
36
+ // none show it at that size: see FastImageViewWithUrl.updateImageMatrix).
38
37
  private final float density;
39
38
 
40
39
  FastImageBlur(float radius, ImageView.ScaleType scaleType, float density) {
@@ -76,7 +75,6 @@ final class FastImageBlur extends BitmapTransformation {
76
75
  if (width <= 0 || height <= 0 || outWidth <= 0 || outHeight <= 0) return 1;
77
76
  float x = outWidth / (float) width;
78
77
  float y = outHeight / (float) height;
79
- if (scaleType == null) return 1;
80
78
  switch (scaleType) {
81
79
  case CENTER_CROP:
82
80
  return Math.max(x, y);
@@ -212,7 +210,7 @@ final class FastImageBlur extends BitmapTransformation {
212
210
 
213
211
  @Override
214
212
  public int hashCode() {
215
- return (ID.hashCode() * 31 + Float.floatToIntBits(radius) * 31 + (scaleType == null ? 0 : scaleType.ordinal())) * 31
213
+ return (ID.hashCode() * 31 + Float.floatToIntBits(radius) * 31 + scaleType.ordinal()) * 31
216
214
  + Float.floatToIntBits(density);
217
215
  }
218
216
 
@@ -1,4 +1,4 @@
1
- package com.dylanvann.fastimage;
1
+ package com.fastimage;
2
2
 
3
3
  public enum FastImageCacheControl {
4
4
  IMMUTABLE,
@@ -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.SharedPreferences;
@@ -76,6 +76,9 @@ final class FastImageCacheLimits {
76
76
  ApplicationInfo info = context.getPackageManager()
77
77
  .getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
78
78
  Bundle metaData = info.metaData;
79
+ // Bundle.get (deprecated from API 33 for parcels of unknown types):
80
+ // the manifest's value is an Integer, a Float or a String.
81
+ @SuppressWarnings("deprecation")
79
82
  Object value = metaData == null ? null : metaData.get(MANIFEST_MAX_DISK_SIZE);
80
83
  if (value instanceof Number) return ((Number) value).longValue();
81
84
  if (value instanceof String) return Long.parseLong(((String) value).trim());
@@ -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.net.Uri;