react-native-fast-image 9.3.7 → 10.0.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 (76) hide show
  1. package/README.md +87 -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 +3 -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 +36 -9
  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 +1 -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 +7 -8
  29. package/android/src/main/java/com/fastimage/FastImageViewManager.java +591 -0
  30. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageViewModule.java +31 -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 +33 -17
  37. package/dist/index.cjs.web.js +211 -61
  38. package/dist/index.cjs.web.js.flow +33 -17
  39. package/dist/index.d.ts +83 -58
  40. package/dist/index.js +278 -159
  41. package/dist/index.js.flow +33 -17
  42. package/dist/index.web.js +212 -62
  43. package/dist/index.web.js.flow +33 -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} +70 -59
  53. package/ios/FastImage/FFFastImageView.h +36 -7
  54. package/ios/FastImage/FFFastImageView.m +201 -164
  55. package/ios/FastImage/FFFastImageViewComponentView.h +11 -0
  56. package/ios/FastImage/FFFastImageViewComponentView.mm +325 -0
  57. package/ios/FastImage/RCTConvert+FFFastImage.h +1 -1
  58. package/ios/FastImage/RCTConvert+FFFastImage.m +7 -10
  59. package/package.json +28 -9
  60. package/src/constants.ts +28 -0
  61. package/src/index.js.flow +179 -0
  62. package/src/index.tsx +1103 -0
  63. package/src/index.web.tsx +548 -0
  64. package/src/objectFit.ts +48 -0
  65. package/src/objectPosition.ts +243 -0
  66. package/src/specs/FastImageViewNativeComponent.ts +83 -0
  67. package/src/specs/NativeFastImageModule.ts +35 -0
  68. package/src/warnings.ts +37 -0
  69. package/android/src/main/AndroidManifestNew.xml +0 -3
  70. package/android/src/main/java/com/dylanvann/fastimage/FastImageCookieHandler.java +0 -63
  71. package/android/src/main/java/com/dylanvann/fastimage/FastImageEvents.java +0 -49
  72. package/android/src/main/java/com/dylanvann/fastimage/FastImageProgressListener.java +0 -18
  73. package/android/src/main/java/com/dylanvann/fastimage/FastImageShadowNode.java +0 -21
  74. package/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java +0 -379
  75. package/android/src/main/java/com/dylanvann/fastimage/FastImageViewPackage.java +0 -27
  76. 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
 
@@ -241,39 +241,32 @@ On Android, `defaultSource` doesn't show in debug builds: there the dev server s
241
241
 
242
242
  How the image fits the view, as CSS's `object-fit` does.
243
243
 
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).
244
+ - `'cover'`: scales it uniformly (keeping its aspect ratio) so it covers the view (inside its borders), cropping what doesn't fit.
245
+ - `'contain'`: scales it uniformly (keeping its aspect ratio) so all of it fits in the view (inside its borders).
246
246
  - `'fill'`: scales its width and height separately to fill the view, which can change its aspect ratio.
247
247
  - `'none'`: shows it at its own size, centered, cropped if it's larger than the view.
248
248
  - `'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
249
 
250
250
  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
251
 
252
- It can also be set in `style`; the prop wins. Either one overrides `resizeMode`.
252
+ It can also be set in `style`; the prop wins.
253
253
 
254
254
  ---
255
255
 
256
- #### `resizeMode`
256
+ #### `objectPosition`
257
257
 
258
- **Type:** `ResizeMode` · **Default:** `'cover'`
258
+ **Type:** `ObjectPosition` · **Default:** `'50% 50%'`
259
259
 
260
- **Deprecated:** Use `objectFit` instead.
260
+ 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).
261
261
 
262
- How the image fills the view.
262
+ - 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.
263
+ - 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.
263
264
 
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
- ---
271
-
272
- #### `fallback`
273
-
274
- **Type:** `boolean`
265
+ 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.
275
266
 
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.
267
+ ```jsx
268
+ <FastImage source={{ uri }} objectFit="cover" objectPosition="top" />
269
+ ```
277
270
 
278
271
  ---
279
272
 
@@ -326,9 +319,11 @@ Pauses an animated image (GIF, animated WebP, APNG, or animated AVIF) on the fra
326
319
 
327
320
  #### `transition`
328
321
 
329
- **Type:** `number | boolean | Transition | null` · **Default:** `false`
322
+ **Type:** `number | boolean | Transition | null`
323
+
324
+ 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
325
 
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`.
326
+ 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
327
 
333
328
  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
329
 
@@ -349,7 +344,7 @@ Decodes a large image at about the size it's shown at, instead of at full size,
349
344
  - `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
345
  - `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
346
 
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.
347
+ 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
348
 
354
349
  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
350
 
@@ -369,7 +364,7 @@ It's for still images, or a radius that changes now and then (e.g. blurring a ph
369
364
  - 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
365
  - Changing it blurs the image that's showing again, without sending the load events again.
371
366
 
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).
367
+ 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
368
 
374
369
  ---
375
370
 
@@ -439,7 +434,7 @@ Called when the image finishes loading, whether it was successful or an error, w
439
434
 
440
435
  **Type:** `StyleProp<ImageStyle>`
441
436
 
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).
437
+ 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
438
 
444
439
  ---
445
440
 
@@ -449,24 +444,12 @@ The image's style: View's style props (`borderRadius` clips the image), and `tin
449
444
 
450
445
  If supplied, changes the color of all the non-transparent pixels to the given color.
451
446
 
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
447
  <!-- api:props end -->
463
448
 
464
449
  ### `FastImageBackground`
465
450
 
466
451
  An image with content on top of it: a view that the image fills, with the children on top.
467
452
 
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
453
  ```jsx
471
454
  import { FastImageBackground } from 'react-native-fast-image'
472
455
 
@@ -628,11 +611,11 @@ const result = await FastImage.writeToCache(
628
611
 
629
612
  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
613
 
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] |
614
+ | Limit | iOS | Android |
615
+ | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
616
+ | `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. |
617
+ | `maxDiskAge`: seconds an image is kept on disk after it was last used. | Default: 1 week. | No age limit. |
618
+ | `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
619
 
637
620
  `0` means no limit.
638
621
 
@@ -649,6 +632,25 @@ On Android, if your app has its own `AppGlideModule` (see [using FastImage with
649
632
 
650
633
  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
634
 
635
+ ### `setDefaults(defaults)`
636
+
637
+ **Parameters:** `defaults: FastImageDefaults` · **Returns:** `void`
638
+
639
+ Changes the defaults of every image, including `FastImageBackground`'s. Pass the settings to change; `null` goes back to the built-in default.
640
+
641
+ - `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.
642
+
643
+ ```js
644
+ // In index.js, before images render.
645
+ FastImage.setDefaults({ transition: false }) // no fades
646
+ FastImage.setDefaults({ transition: true }) // fades on iOS too
647
+ FastImage.setDefaults({ transition: Platform.select({ ios: 200 }) }) // 200 ms on iOS; Android keeps its default
648
+ FastImage.setDefaults({ transition: { duration: 200, betweenImages: true } })
649
+ FastImage.setDefaults({ transition: null }) // the built-in default
650
+ ```
651
+
652
+ 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.
653
+
652
654
  ## Types
653
655
 
654
656
  <!-- api:types start (generated from src/ by website/scripts/generate.mts) -->
@@ -698,6 +700,14 @@ How fresh an image must be: see [`source.cache`](#sourcecache).
698
700
 
699
701
  ---
700
702
 
703
+ ### `FastImageDefaults`
704
+
705
+ `FastImage.setDefaults`'s settings.
706
+
707
+ - `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`).
708
+
709
+ ---
710
+
701
711
  ### `LoadResult`
702
712
 
703
713
  **Type:** `{ ok: true; width: number; height: number } | { ok: false; error: string }`
@@ -714,6 +724,14 @@ How the image fits the view: see [`objectFit`](#objectfit).
714
724
 
715
725
  ---
716
726
 
727
+ ### `ObjectPosition`
728
+
729
+ **Type:** `string | ({ top?: PositionLength; bottom?: never } | { bottom: PositionLength; top?: never }) & ({ left?: PositionLength; right?: never } | { right: PositionLength; left?: never })`
730
+
731
+ Where the image is in the view: see [`objectPosition`](#objectposition).
732
+
733
+ ---
734
+
717
735
  ### `OnErrorEvent`
718
736
 
719
737
  `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 +742,7 @@ How the image fits the view: see [`objectFit`](#objectfit).
724
742
 
725
743
  ### `OnLoadEvent`
726
744
 
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).
745
+ `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
746
 
729
747
  - `nativeEvent` (`{ width: number; height: number; target?: number }`)
730
748
 
@@ -738,6 +756,14 @@ How the image fits the view: see [`objectFit`](#objectfit).
738
756
 
739
757
  ---
740
758
 
759
+ ### `PositionLength`
760
+
761
+ **Type:** `` number | `${number}%` ``
762
+
763
+ A length in points (dp on Android), or a percentage: see [`objectPosition`](#objectposition).
764
+
765
+ ---
766
+
741
767
  ### `PreloadFailure`
742
768
 
743
769
  A preloaded source that failed to load.
@@ -775,19 +801,11 @@ An image's load priority: see [`source.priority`](#sourcepriority).
775
801
 
776
802
  ---
777
803
 
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
804
  ### `Transition`
787
805
 
788
806
  How the image fades in: see [`transition`](#transition).
789
807
 
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.
808
+ - `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
809
  - `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
810
  - `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
811
 
@@ -795,7 +813,7 @@ How the image fades in: see [`transition`](#transition).
795
813
  - `'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
814
  - `'none'`: always fades.
797
815
 
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).
816
+ 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
817
 
800
818
  <!-- api:types end -->
801
819
 
@@ -854,12 +872,20 @@ FastImage works on the web with [react-native-web](https://necolas.github.io/rea
854
872
 
855
873
  Support is minimal:
856
874
 
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`.
875
+ - 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`.
876
+ - 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` and `onProgress`.
877
+ - 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).
878
+ - 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
879
  - `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
880
 
881
+ ## Jest
882
+
883
+ 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.
884
+
885
+ ```js
886
+ jest.spyOn(FastImage, 'preload').mockResolvedValue([])
887
+ ```
888
+
863
889
  ## Troubleshooting
864
890
 
865
891
  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;