expo-image 1.7.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/expo/modules/image/ExpoImageModule.kt +48 -3
- package/android/src/main/java/expo/modules/image/events/GlideRequestListener.kt +5 -2
- package/android/src/main/java/expo/modules/image/records/SourceMap.kt +17 -4
- package/android/src/main/java/expo/modules/image/svg/SVGDrawableTranscoder.kt +29 -7
- package/build/ExpoImage.web.d.ts +1 -1
- package/build/ExpoImage.web.d.ts.map +1 -1
- package/build/ExpoImage.web.js +14 -4
- package/build/ExpoImage.web.js.map +1 -1
- package/build/Image.d.ts +10 -4
- package/build/Image.d.ts.map +1 -1
- package/build/Image.js +11 -5
- package/build/Image.js.map +1 -1
- package/ios/ImageModule.swift +20 -2
- package/ios/ImageView.swift +2 -2
- package/package.json +2 -2
- package/src/ExpoImage.web.tsx +17 -4
- package/src/Image.tsx +14 -5
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,28 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 1.8.1 — 2023-11-14
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- Reverted ["[image][Android] Add tracing (#25251)"](https://github.com/expo/expo/pull/25251)
|
|
18
|
+
|
|
19
|
+
## 1.8.0 — 2023-11-13
|
|
20
|
+
|
|
21
|
+
### 🎉 New features
|
|
22
|
+
|
|
23
|
+
- Return a promise in the `prefetch` method. ([#25196](https://github.com/expo/expo/pull/25196) by [@gkasdorf](https://github.com/gkasdorf))
|
|
24
|
+
- [Android] Added `autoplay` prop and `startAnimating()` and `stopAnimating()` functions to reflect changes made to iOS in [#25008](https://github.com/expo/expo/pull/25008). ([#25124](https://github.com/expo/expo/pull/25124) by [@gkasdorf](https://github.com/gkasdorf))
|
|
25
|
+
|
|
26
|
+
### 🐛 Bug fixes
|
|
27
|
+
|
|
28
|
+
- [Android] Fix `contentFit` not working for `SVG` images. ([#25187](https://github.com/expo/expo/pull/25187) by [@behenate](https://github.com/behenate))
|
|
29
|
+
- [iOS] Start loading the image before the view mounts to fix issues with the PagerView. ([#25343](https://github.com/expo/expo/pull/25343) by [@tsapeta](https://github.com/tsapeta))
|
|
30
|
+
- [Android] Fix `SVG` not scaling correctly in the release mode. ([#25326](https://github.com/expo/expo/pull/25326) by [@lukmccall](https://github.com/lukmccall))
|
|
31
|
+
- [Android] Fix incorrect `intrinsicSize` returned for SVGs. ([#25048](https://github.com/expo/expo/pull/25048) by [@behenate](https://github.com/behenate))
|
|
32
|
+
|
|
33
|
+
### 💡 Others
|
|
34
|
+
|
|
13
35
|
## 1.7.0 — 2023-11-01
|
|
14
36
|
|
|
15
37
|
### 🎉 New features
|
package/android/build.gradle
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
package expo.modules.image
|
|
2
2
|
|
|
3
|
+
import android.graphics.drawable.Drawable
|
|
3
4
|
import android.view.View
|
|
4
5
|
import androidx.core.view.doOnDetach
|
|
5
6
|
import com.bumptech.glide.Glide
|
|
7
|
+
import com.bumptech.glide.load.DataSource
|
|
8
|
+
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
|
9
|
+
import com.bumptech.glide.load.engine.GlideException
|
|
6
10
|
import com.bumptech.glide.load.model.GlideUrl
|
|
11
|
+
import com.bumptech.glide.request.RequestListener
|
|
12
|
+
import com.bumptech.glide.request.target.Target
|
|
7
13
|
import com.facebook.react.uimanager.PixelUtil
|
|
8
14
|
import com.facebook.react.uimanager.Spacing
|
|
9
15
|
import com.facebook.react.uimanager.ViewProps
|
|
@@ -14,6 +20,7 @@ import expo.modules.image.records.CachePolicy
|
|
|
14
20
|
import expo.modules.image.records.ContentPosition
|
|
15
21
|
import expo.modules.image.records.ImageTransition
|
|
16
22
|
import expo.modules.image.records.SourceMap
|
|
23
|
+
import expo.modules.kotlin.Promise
|
|
17
24
|
import expo.modules.kotlin.functions.Queues
|
|
18
25
|
import expo.modules.kotlin.modules.Module
|
|
19
26
|
import expo.modules.kotlin.modules.ModuleDefinition
|
|
@@ -23,12 +30,50 @@ class ExpoImageModule : Module() {
|
|
|
23
30
|
override fun definition() = ModuleDefinition {
|
|
24
31
|
Name("ExpoImage")
|
|
25
32
|
|
|
26
|
-
|
|
27
|
-
val context = appContext.reactContext ?: return@
|
|
33
|
+
AsyncFunction("prefetch") { urls: List<String>, cachePolicy: CachePolicy, promise: Promise ->
|
|
34
|
+
val context = appContext.reactContext ?: return@AsyncFunction false
|
|
35
|
+
|
|
36
|
+
var imagesLoaded = 0
|
|
37
|
+
var failed = false
|
|
38
|
+
|
|
28
39
|
urls.forEach {
|
|
29
40
|
Glide
|
|
30
41
|
.with(context)
|
|
31
|
-
.
|
|
42
|
+
.load(GlideUrl(it)) // Use `load` instead of `download` to store the asset in the memory cache
|
|
43
|
+
.apply {
|
|
44
|
+
if (cachePolicy == CachePolicy.MEMORY) {
|
|
45
|
+
diskCacheStrategy(DiskCacheStrategy.NONE)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
.listener(object : RequestListener<Drawable> {
|
|
49
|
+
override fun onLoadFailed(
|
|
50
|
+
e: GlideException?,
|
|
51
|
+
model: Any?,
|
|
52
|
+
target: Target<Drawable>?,
|
|
53
|
+
isFirstResource: Boolean
|
|
54
|
+
): Boolean {
|
|
55
|
+
if (!failed) {
|
|
56
|
+
failed = true
|
|
57
|
+
promise.resolve(false)
|
|
58
|
+
}
|
|
59
|
+
return true
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
override fun onResourceReady(
|
|
63
|
+
resource: Drawable?,
|
|
64
|
+
model: Any?,
|
|
65
|
+
target: Target<Drawable>?,
|
|
66
|
+
dataSource: DataSource?,
|
|
67
|
+
isFirstResource: Boolean
|
|
68
|
+
): Boolean {
|
|
69
|
+
imagesLoaded++
|
|
70
|
+
|
|
71
|
+
if (imagesLoaded == urls.size) {
|
|
72
|
+
promise.resolve(true)
|
|
73
|
+
}
|
|
74
|
+
return true
|
|
75
|
+
}
|
|
76
|
+
})
|
|
32
77
|
.submit()
|
|
33
78
|
}
|
|
34
79
|
}
|
|
@@ -11,6 +11,7 @@ import expo.modules.image.enums.ImageCacheType
|
|
|
11
11
|
import expo.modules.image.records.ImageErrorEvent
|
|
12
12
|
import expo.modules.image.records.ImageLoadEvent
|
|
13
13
|
import expo.modules.image.records.ImageSource
|
|
14
|
+
import expo.modules.image.svg.SVGBitmapDrawable
|
|
14
15
|
import java.lang.ref.WeakReference
|
|
15
16
|
import java.util.*
|
|
16
17
|
|
|
@@ -47,13 +48,15 @@ class GlideRequestListener(
|
|
|
47
48
|
dataSource: DataSource,
|
|
48
49
|
isFirstResource: Boolean
|
|
49
50
|
): Boolean {
|
|
51
|
+
val intrinsicWidth = (resource as? SVGBitmapDrawable)?.svgIntrinsicWidth ?: resource.intrinsicWidth
|
|
52
|
+
val intrinsicHeight = (resource as? SVGBitmapDrawable)?.svgIntrinsicHeight ?: resource.intrinsicHeight
|
|
50
53
|
expoImageViewWrapper.get()?.onLoad?.invoke(
|
|
51
54
|
ImageLoadEvent(
|
|
52
55
|
cacheType = ImageCacheType.fromNativeValue(dataSource).name.lowercase(Locale.getDefault()),
|
|
53
56
|
source = ImageSource(
|
|
54
57
|
url = model.toString(),
|
|
55
|
-
width =
|
|
56
|
-
height =
|
|
58
|
+
width = intrinsicWidth,
|
|
59
|
+
height = intrinsicHeight,
|
|
57
60
|
mediaType = null // TODO(@lukmccall): add mediaType
|
|
58
61
|
)
|
|
59
62
|
)
|
|
@@ -2,6 +2,7 @@ package expo.modules.image.records
|
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.net.Uri
|
|
5
|
+
import android.util.TypedValue
|
|
5
6
|
import com.bumptech.glide.load.model.GlideUrl
|
|
6
7
|
import com.bumptech.glide.load.model.Headers
|
|
7
8
|
import com.bumptech.glide.load.model.LazyHeaders
|
|
@@ -38,13 +39,25 @@ data class SourceMap(
|
|
|
38
39
|
|
|
39
40
|
private fun isLocalFileUri() = parsedUri?.scheme?.startsWith("file") ?: false
|
|
40
41
|
|
|
41
|
-
private fun isSvg(): Boolean {
|
|
42
|
-
var
|
|
42
|
+
private fun isSvg(context: Context): Boolean {
|
|
43
|
+
var uri = parsedUri?.toString()
|
|
44
|
+
if (uri?.startsWith("res:/") == true) {
|
|
45
|
+
val id = uri.removePrefix("res:/")
|
|
46
|
+
try {
|
|
47
|
+
val typedValue = TypedValue()
|
|
48
|
+
context.resources.getValue(id, typedValue, true)
|
|
49
|
+
uri = typedValue.string.toString()
|
|
50
|
+
} catch (e: Throwable) {
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
var lastDotIndex = uri?.lastIndexOf('.')
|
|
43
56
|
// if the path has no file extension and no . at all (e.g. file://path/to/file) return false
|
|
44
57
|
if (lastDotIndex == -1 || lastDotIndex == null) {
|
|
45
58
|
return false
|
|
46
59
|
}
|
|
47
|
-
return
|
|
60
|
+
return uri?.substring(lastDotIndex)?.startsWith(".svg") ?: false
|
|
48
61
|
}
|
|
49
62
|
|
|
50
63
|
fun isBlurhash() = parsedUri?.scheme?.startsWith("blurhash") ?: false
|
|
@@ -111,7 +124,7 @@ data class SourceMap(
|
|
|
111
124
|
|
|
112
125
|
// Override the size for local assets (apart from SVGs). This ensures that
|
|
113
126
|
// resizeMode "center" displays the image in the correct size.
|
|
114
|
-
if (width != 0 && height != 0 && !isSvg()) {
|
|
127
|
+
if (width != 0 && height != 0 && !isSvg(context)) {
|
|
115
128
|
override((width * scale).toInt(), (height * scale).toInt())
|
|
116
129
|
}
|
|
117
130
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package expo.modules.image.svg
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import android.content.res.Resources
|
|
4
5
|
import android.graphics.Bitmap
|
|
5
6
|
import android.graphics.Canvas
|
|
6
7
|
import android.graphics.Picture
|
|
@@ -11,8 +12,16 @@ import com.bumptech.glide.load.Options
|
|
|
11
12
|
import com.bumptech.glide.load.engine.Resource
|
|
12
13
|
import com.bumptech.glide.load.resource.SimpleResource
|
|
13
14
|
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder
|
|
15
|
+
import com.caverock.androidsvg.PreserveAspectRatio
|
|
16
|
+
import com.caverock.androidsvg.RenderOptions
|
|
14
17
|
import com.caverock.androidsvg.SVG
|
|
15
18
|
|
|
19
|
+
/**
|
|
20
|
+
* We have to use the intrinsicWidth/Height from the bitmap to render the image at a high enough resolution, but at the same time we want to return the actual
|
|
21
|
+
* preferred width and height of the SVG to JS. This class allows us to do that.
|
|
22
|
+
*/
|
|
23
|
+
class SVGBitmapDrawable(res: Resources?, bitmap: Bitmap?, val svgIntrinsicWidth: Int, val svgIntrinsicHeight: Int) : BitmapDrawable(res, bitmap)
|
|
24
|
+
|
|
16
25
|
/**
|
|
17
26
|
* Convert the [SVG]'s internal representation to an Android-compatible one ([Picture]).
|
|
18
27
|
*
|
|
@@ -21,17 +30,30 @@ import com.caverock.androidsvg.SVG
|
|
|
21
30
|
*/
|
|
22
31
|
class SVGDrawableTranscoder(val context: Context) : ResourceTranscoder<SVG?, Drawable> {
|
|
23
32
|
override fun transcode(toTranscode: Resource<SVG?>, options: Options): Resource<Drawable> {
|
|
24
|
-
val
|
|
25
|
-
val
|
|
26
|
-
val
|
|
27
|
-
val
|
|
33
|
+
val svgData = toTranscode.get()
|
|
34
|
+
val svgIntrinsicWidth = svgData.documentViewBox.width()
|
|
35
|
+
val svgIntrinsicHeight = svgData.documentViewBox.height()
|
|
36
|
+
val documentWidth = svgData.documentWidth
|
|
37
|
+
val documentHeight = svgData.documentHeight
|
|
38
|
+
val aspectRatio = svgIntrinsicWidth / svgIntrinsicHeight
|
|
28
39
|
|
|
29
|
-
|
|
40
|
+
// We have no information on what content fit the user wants, so when choosing render resolution we assume
|
|
41
|
+
// "cover" in order to prevent loss of quality after the bitmap is transformed to appropriate `contentFit` later.
|
|
42
|
+
val shouldUseHeightReference = documentWidth / aspectRatio > documentHeight
|
|
43
|
+
val renderWidth = if (shouldUseHeightReference) documentWidth else documentHeight * aspectRatio
|
|
44
|
+
val renderHeight = if (shouldUseHeightReference) documentWidth / aspectRatio else documentHeight
|
|
45
|
+
val renderOptions = RenderOptions().apply {
|
|
46
|
+
viewPort(0f, 0f, renderWidth, renderHeight)
|
|
47
|
+
preserveAspectRatio(PreserveAspectRatio.FULLSCREEN_START)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
val picture = svgData.renderToPicture(renderWidth.toInt(), renderHeight.toInt(), renderOptions)
|
|
51
|
+
val drawable = PictureDrawable(picture)
|
|
52
|
+
val bitmap = Bitmap.createBitmap(renderWidth.toInt(), renderHeight.toInt(), Bitmap.Config.ARGB_8888)
|
|
30
53
|
val canvas = Canvas(bitmap)
|
|
31
54
|
drawable.setBounds(0, 0, canvas.width, canvas.height)
|
|
32
55
|
drawable.draw(canvas)
|
|
33
56
|
|
|
34
|
-
|
|
35
|
-
return SimpleResource(newDrawable)
|
|
57
|
+
return SimpleResource(SVGBitmapDrawable(context.resources, bitmap, svgIntrinsicWidth.toInt(), svgIntrinsicHeight.toInt()))
|
|
36
58
|
}
|
|
37
59
|
}
|
package/build/ExpoImage.web.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ImageNativeProps } from './Image.types';
|
|
2
2
|
export declare const ExpoImageModule: {
|
|
3
|
-
prefetch(urls: string | string[]):
|
|
3
|
+
prefetch(urls: string | string[], _: any): Promise<boolean>;
|
|
4
4
|
clearMemoryCache(): Promise<boolean>;
|
|
5
5
|
clearDiskCache(): Promise<boolean>;
|
|
6
6
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoImage.web.d.ts","sourceRoot":"","sources":["../src/ExpoImage.web.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAmC,MAAM,eAAe,CAAC;AAQlF,eAAO,MAAM,eAAe;
|
|
1
|
+
{"version":3,"file":"ExpoImage.web.d.ts","sourceRoot":"","sources":["../src/ExpoImage.web.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAmC,MAAM,eAAe,CAAC;AAQlF,eAAO,MAAM,eAAe;mBACL,MAAM,GAAG,MAAM,EAAE,WAAM,QAAQ,OAAO,CAAC;wBAqBlC,QAAQ,OAAO,CAAC;sBAIlB,QAAQ,OAAO,CAAC;CAGzC,CAAC;AA+BF,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAChC,MAAM,EACN,WAAW,EACX,UAAU,EACV,eAAe,EACf,qBAAqB,EACrB,WAAW,EACX,MAAM,EACN,UAAU,EACV,OAAO,EACP,gBAAgB,EAChB,SAAS,EACT,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,KAAK,EACL,GAAG,KAAK,EACT,EAAE,gBAAgB,eA+ElB"}
|
package/build/ExpoImage.web.js
CHANGED
|
@@ -6,11 +6,21 @@ import loadStyle from './web/imageStyles';
|
|
|
6
6
|
import useSourceSelection from './web/useSourceSelection';
|
|
7
7
|
loadStyle();
|
|
8
8
|
export const ExpoImageModule = {
|
|
9
|
-
prefetch(urls) {
|
|
9
|
+
async prefetch(urls, _) {
|
|
10
10
|
const urlsArray = Array.isArray(urls) ? urls : [urls];
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
return new Promise((resolve) => {
|
|
12
|
+
let imagesLoaded = 0;
|
|
13
|
+
urlsArray.forEach((url) => {
|
|
14
|
+
const img = new Image();
|
|
15
|
+
img.src = url;
|
|
16
|
+
img.onload = () => {
|
|
17
|
+
imagesLoaded++;
|
|
18
|
+
if (imagesLoaded === urlsArray.length) {
|
|
19
|
+
resolve(true);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
img.onerror = () => resolve(false);
|
|
23
|
+
});
|
|
14
24
|
});
|
|
15
25
|
},
|
|
16
26
|
async clearMemoryCache() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoImage.web.js","sourceRoot":"","sources":["../src/ExpoImage.web.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { View } from 'react-native-web';\n\nimport { ImageNativeProps, ImageSource, ImageLoadEventData } from './Image.types';\nimport AnimationManager, { AnimationManagerNode } from './web/AnimationManager';\nimport ImageWrapper from './web/ImageWrapper';\nimport loadStyle from './web/imageStyles';\nimport useSourceSelection from './web/useSourceSelection';\n\nloadStyle();\n\nexport const ExpoImageModule = {\n prefetch(urls: string | string[]): void {\n const urlsArray = Array.isArray(urls) ? urls : [urls];\n urlsArray.forEach((url) => {\n const img = new Image();\n img.src = url;\n });\n },\n\n async clearMemoryCache(): Promise<boolean> {\n return false;\n },\n\n async clearDiskCache(): Promise<boolean> {\n return false;\n },\n};\n\nfunction onLoadAdapter(onLoad?: (event: ImageLoadEventData) => void) {\n return (event: React.SyntheticEvent<HTMLImageElement, Event>) => {\n const target = event.target as HTMLImageElement;\n onLoad?.({\n source: {\n url: target.currentSrc,\n width: target.naturalWidth,\n height: target.naturalHeight,\n mediaType: null,\n },\n cacheType: 'none',\n });\n };\n}\n\nfunction onErrorAdapter(onError?: { (event: { error: string }): void }) {\n return ({ source }: { source?: ImageSource | null }) => {\n onError?.({\n error: `Failed to load image from url: ${source?.uri}`,\n });\n };\n}\n\n// Used for some transitions to mimic native animations\nconst setCssVariables = (element: HTMLElement, size: DOMRect) => {\n element?.style.setProperty('--expo-image-width', `${size.width}px`);\n element?.style.setProperty('--expo-image-height', `${size.height}px`);\n};\n\nexport default function ExpoImage({\n source,\n placeholder,\n contentFit,\n contentPosition,\n placeholderContentFit,\n cachePolicy,\n onLoad,\n transition,\n onError,\n responsivePolicy,\n onLoadEnd,\n priority,\n blurRadius,\n recyclingKey,\n style,\n ...props\n}: ImageNativeProps) {\n const imagePlaceholderContentFit = placeholderContentFit || 'scale-down';\n const imageHashStyle = {\n objectFit: placeholderContentFit || contentFit,\n };\n const { containerRef, source: selectedSource } = useSourceSelection(\n source,\n responsivePolicy,\n setCssVariables\n );\n\n const initialNodeAnimationKey =\n (recyclingKey ? `${recyclingKey}-${placeholder?.[0]?.uri}` : placeholder?.[0]?.uri) ?? '';\n\n const initialNode: AnimationManagerNode | null = placeholder?.[0]?.uri\n ? [\n initialNodeAnimationKey,\n ({ onAnimationFinished }) =>\n (className, style) => (\n <ImageWrapper\n {...props}\n source={placeholder?.[0]}\n style={{\n objectFit: imagePlaceholderContentFit,\n ...(blurRadius ? { filter: `blur(${blurRadius}px)` } : {}),\n ...style,\n }}\n className={className}\n events={{\n onTransitionEnd: [onAnimationFinished],\n }}\n contentPosition={{ left: '50%', top: '50%' }}\n hashPlaceholderContentPosition={contentPosition}\n hashPlaceholderStyle={imageHashStyle}\n />\n ),\n ]\n : null;\n\n const currentNodeAnimationKey =\n (recyclingKey\n ? `${recyclingKey}-${selectedSource?.uri ?? placeholder?.[0]?.uri}`\n : selectedSource?.uri ?? placeholder?.[0]?.uri) ?? '';\n\n const currentNode: AnimationManagerNode = [\n currentNodeAnimationKey,\n ({ onAnimationFinished, onReady, onMount, onError: onErrorInner }) =>\n (className, style) => (\n <ImageWrapper\n {...props}\n source={selectedSource || placeholder?.[0]}\n events={{\n onError: [onErrorAdapter(onError), onLoadEnd, onErrorInner],\n onLoad: [onLoadAdapter(onLoad), onLoadEnd, onReady],\n onMount: [onMount],\n onTransitionEnd: [onAnimationFinished],\n }}\n style={{\n objectFit: selectedSource ? contentFit : imagePlaceholderContentFit,\n ...(blurRadius ? { filter: `blur(${blurRadius}px)` } : {}),\n ...style,\n }}\n className={className}\n cachePolicy={cachePolicy}\n priority={priority}\n contentPosition={selectedSource ? contentPosition : { top: '50%', left: '50%' }}\n hashPlaceholderContentPosition={contentPosition}\n hashPlaceholderStyle={imageHashStyle}\n accessibilityLabel={props.accessibilityLabel}\n />\n ),\n ];\n return (\n <View ref={containerRef} dataSet={{ expoimage: true }} style={[{ overflow: 'hidden' }, style]}>\n <AnimationManager transition={transition} recyclingKey={recyclingKey} initial={initialNode}>\n {currentNode}\n </AnimationManager>\n </View>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ExpoImage.web.js","sourceRoot":"","sources":["../src/ExpoImage.web.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { View } from 'react-native-web';\n\nimport { ImageNativeProps, ImageSource, ImageLoadEventData } from './Image.types';\nimport AnimationManager, { AnimationManagerNode } from './web/AnimationManager';\nimport ImageWrapper from './web/ImageWrapper';\nimport loadStyle from './web/imageStyles';\nimport useSourceSelection from './web/useSourceSelection';\n\nloadStyle();\n\nexport const ExpoImageModule = {\n async prefetch(urls: string | string[], _): Promise<boolean> {\n const urlsArray = Array.isArray(urls) ? urls : [urls];\n\n return new Promise<boolean>((resolve) => {\n let imagesLoaded = 0;\n\n urlsArray.forEach((url) => {\n const img = new Image();\n img.src = url;\n img.onload = () => {\n imagesLoaded++;\n\n if (imagesLoaded === urlsArray.length) {\n resolve(true);\n }\n };\n img.onerror = () => resolve(false);\n });\n });\n },\n\n async clearMemoryCache(): Promise<boolean> {\n return false;\n },\n\n async clearDiskCache(): Promise<boolean> {\n return false;\n },\n};\n\nfunction onLoadAdapter(onLoad?: (event: ImageLoadEventData) => void) {\n return (event: React.SyntheticEvent<HTMLImageElement, Event>) => {\n const target = event.target as HTMLImageElement;\n onLoad?.({\n source: {\n url: target.currentSrc,\n width: target.naturalWidth,\n height: target.naturalHeight,\n mediaType: null,\n },\n cacheType: 'none',\n });\n };\n}\n\nfunction onErrorAdapter(onError?: { (event: { error: string }): void }) {\n return ({ source }: { source?: ImageSource | null }) => {\n onError?.({\n error: `Failed to load image from url: ${source?.uri}`,\n });\n };\n}\n\n// Used for some transitions to mimic native animations\nconst setCssVariables = (element: HTMLElement, size: DOMRect) => {\n element?.style.setProperty('--expo-image-width', `${size.width}px`);\n element?.style.setProperty('--expo-image-height', `${size.height}px`);\n};\n\nexport default function ExpoImage({\n source,\n placeholder,\n contentFit,\n contentPosition,\n placeholderContentFit,\n cachePolicy,\n onLoad,\n transition,\n onError,\n responsivePolicy,\n onLoadEnd,\n priority,\n blurRadius,\n recyclingKey,\n style,\n ...props\n}: ImageNativeProps) {\n const imagePlaceholderContentFit = placeholderContentFit || 'scale-down';\n const imageHashStyle = {\n objectFit: placeholderContentFit || contentFit,\n };\n const { containerRef, source: selectedSource } = useSourceSelection(\n source,\n responsivePolicy,\n setCssVariables\n );\n\n const initialNodeAnimationKey =\n (recyclingKey ? `${recyclingKey}-${placeholder?.[0]?.uri}` : placeholder?.[0]?.uri) ?? '';\n\n const initialNode: AnimationManagerNode | null = placeholder?.[0]?.uri\n ? [\n initialNodeAnimationKey,\n ({ onAnimationFinished }) =>\n (className, style) => (\n <ImageWrapper\n {...props}\n source={placeholder?.[0]}\n style={{\n objectFit: imagePlaceholderContentFit,\n ...(blurRadius ? { filter: `blur(${blurRadius}px)` } : {}),\n ...style,\n }}\n className={className}\n events={{\n onTransitionEnd: [onAnimationFinished],\n }}\n contentPosition={{ left: '50%', top: '50%' }}\n hashPlaceholderContentPosition={contentPosition}\n hashPlaceholderStyle={imageHashStyle}\n />\n ),\n ]\n : null;\n\n const currentNodeAnimationKey =\n (recyclingKey\n ? `${recyclingKey}-${selectedSource?.uri ?? placeholder?.[0]?.uri}`\n : selectedSource?.uri ?? placeholder?.[0]?.uri) ?? '';\n\n const currentNode: AnimationManagerNode = [\n currentNodeAnimationKey,\n ({ onAnimationFinished, onReady, onMount, onError: onErrorInner }) =>\n (className, style) => (\n <ImageWrapper\n {...props}\n source={selectedSource || placeholder?.[0]}\n events={{\n onError: [onErrorAdapter(onError), onLoadEnd, onErrorInner],\n onLoad: [onLoadAdapter(onLoad), onLoadEnd, onReady],\n onMount: [onMount],\n onTransitionEnd: [onAnimationFinished],\n }}\n style={{\n objectFit: selectedSource ? contentFit : imagePlaceholderContentFit,\n ...(blurRadius ? { filter: `blur(${blurRadius}px)` } : {}),\n ...style,\n }}\n className={className}\n cachePolicy={cachePolicy}\n priority={priority}\n contentPosition={selectedSource ? contentPosition : { top: '50%', left: '50%' }}\n hashPlaceholderContentPosition={contentPosition}\n hashPlaceholderStyle={imageHashStyle}\n accessibilityLabel={props.accessibilityLabel}\n />\n ),\n ];\n return (\n <View ref={containerRef} dataSet={{ expoimage: true }} style={[{ overflow: 'hidden' }, style]}>\n <AnimationManager transition={transition} recyclingKey={recyclingKey} initial={initialNode}>\n {currentNode}\n </AnimationManager>\n </View>\n );\n}\n"]}
|
package/build/Image.d.ts
CHANGED
|
@@ -4,11 +4,17 @@ export declare class Image extends React.PureComponent<ImageProps> {
|
|
|
4
4
|
nativeViewRef: any;
|
|
5
5
|
constructor(props: any);
|
|
6
6
|
/**
|
|
7
|
-
* Preloads images at the given
|
|
8
|
-
* Preloaded images are
|
|
9
|
-
* `disk` (default) or `memory-disk` cache policy.
|
|
7
|
+
* Preloads images at the given URLs that can be later used in the image view.
|
|
8
|
+
* Preloaded images are cached to the memory and disk by default, so make sure
|
|
9
|
+
* to use `disk` (default) or `memory-disk` [cache policy](#cachepolicy).
|
|
10
|
+
* @param urls - A URL string or an array of URLs of images to prefetch.
|
|
11
|
+
* @param cachePolicy - The cache policy for prefetched images.
|
|
12
|
+
* @return A promise resolving to `true` as soon as all images have been
|
|
13
|
+
* successfully prefetched. If an image fails to be prefetched, the promise
|
|
14
|
+
* will immediately resolve to `false` regardless of whether other images have
|
|
15
|
+
* finished prefetching.
|
|
10
16
|
*/
|
|
11
|
-
static prefetch(urls: string | string[]):
|
|
17
|
+
static prefetch(urls: string | string[], cachePolicy?: 'memory-disk' | 'memory'): Promise<boolean>;
|
|
12
18
|
/**
|
|
13
19
|
* Asynchronously clears all images stored in memory.
|
|
14
20
|
* @platform android
|
package/build/Image.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../src/Image.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAM3C,qBAAa,KAAM,SAAQ,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC;IACxD,aAAa,MAAC;gBAEF,KAAK,KAAA;IAKjB
|
|
1
|
+
{"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../src/Image.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAM3C,qBAAa,KAAM,SAAQ,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC;IACxD,aAAa,MAAC;gBAEF,KAAK,KAAA;IAKjB;;;;;;;;;;OAUG;WACU,QAAQ,CACnB,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EACvB,WAAW,GAAE,aAAa,GAAG,QAAwB,GACpD,OAAO,CAAC,OAAO,CAAC;IAInB;;;;;;;OAOG;WACU,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjD;;;;;;;OAOG;WACU,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/C;;;;;;;;;OASG;WACU,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIxE;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrC;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC,MAAM;CAqCP"}
|
package/build/Image.js
CHANGED
|
@@ -11,12 +11,18 @@ export class Image extends React.PureComponent {
|
|
|
11
11
|
this.nativeViewRef = React.createRef();
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
* Preloads images at the given
|
|
15
|
-
* Preloaded images are
|
|
16
|
-
* `disk` (default) or `memory-disk` cache policy.
|
|
14
|
+
* Preloads images at the given URLs that can be later used in the image view.
|
|
15
|
+
* Preloaded images are cached to the memory and disk by default, so make sure
|
|
16
|
+
* to use `disk` (default) or `memory-disk` [cache policy](#cachepolicy).
|
|
17
|
+
* @param urls - A URL string or an array of URLs of images to prefetch.
|
|
18
|
+
* @param cachePolicy - The cache policy for prefetched images.
|
|
19
|
+
* @return A promise resolving to `true` as soon as all images have been
|
|
20
|
+
* successfully prefetched. If an image fails to be prefetched, the promise
|
|
21
|
+
* will immediately resolve to `false` regardless of whether other images have
|
|
22
|
+
* finished prefetching.
|
|
17
23
|
*/
|
|
18
|
-
static prefetch(urls) {
|
|
19
|
-
return ExpoImageModule.prefetch(Array.isArray(urls) ? urls : [urls]);
|
|
24
|
+
static async prefetch(urls, cachePolicy = 'memory-disk') {
|
|
25
|
+
return ExpoImageModule.prefetch(Array.isArray(urls) ? urls : [urls], cachePolicy);
|
|
20
26
|
}
|
|
21
27
|
/**
|
|
22
28
|
* Asynchronously clears all images stored in memory.
|
package/build/Image.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Image.js","sourceRoot":"","sources":["../src/Image.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,SAAS,EAAE,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,IAAI,qCAAqC,GAAG,KAAK,CAAC;AAElD,MAAM,OAAO,KAAM,SAAQ,KAAK,CAAC,aAAyB;IACxD,aAAa,CAAC;IAEd,YAAY,KAAK;QACf,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;IACzC,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"Image.js","sourceRoot":"","sources":["../src/Image.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,SAAS,EAAE,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,IAAI,qCAAqC,GAAG,KAAK,CAAC;AAElD,MAAM,OAAO,KAAM,SAAQ,KAAK,CAAC,aAAyB;IACxD,aAAa,CAAC;IAEd,YAAY,KAAK;QACf,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;IACzC,CAAC;IAED;;;;;;;;;;OAUG;IACH,MAAM,CAAC,KAAK,CAAC,QAAQ,CACnB,IAAuB,EACvB,cAAwC,aAAa;QAErD,OAAO,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC;IACpF,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,CAAC,gBAAgB;QAC3B,OAAO,MAAM,eAAe,CAAC,gBAAgB,EAAE,CAAC;IAClD,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,CAAC,cAAc;QACzB,OAAO,MAAM,eAAe,CAAC,cAAc,EAAE,CAAC;IAChD,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,QAAgB;QAC7C,OAAO,MAAM,eAAe,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,cAAc;QAClB,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;IACpD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;IACnD,CAAC;IAED,MAAM;QACJ,MAAM,EACJ,KAAK,EACL,MAAM,EACN,WAAW,EACX,UAAU,EACV,eAAe,EACf,UAAU,EACV,YAAY,EACZ,UAAU,EAAE,cAAc,EAC1B,aAAa,EACb,sBAAsB,EACtB,GAAG,SAAS,EACb,GAAG,IAAI,CAAC,KAAK,CAAC;QAEf,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,SAAS,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtF,MAAM,UAAU,GAAG,cAAc,IAAI,eAAe,CAAC;QAErD,IAAI,CAAC,aAAa,IAAI,sBAAsB,CAAC,IAAI,CAAC,qCAAqC,EAAE;YACvF,OAAO,CAAC,IAAI,CACV,4GAA4G,CAC7G,CAAC;YACF,qCAAqC,GAAG,IAAI,CAAC;SAC9C;QAED,OAAO,CACL,CAAC,SAAS,CACR,IAAI,SAAS,CAAC,CACd,KAAK,CAAC,CAAC,SAAS,CAAC,CACjB,MAAM,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAC/B,WAAW,CAAC,CAAC,cAAc,CAAC,WAAW,IAAI,aAAa,IAAI,sBAAsB,CAAC,CAAC,CACpF,UAAU,CAAC,CAAC,iBAAiB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CACtD,eAAe,CAAC,CAAC,sBAAsB,CAAC,eAAe,CAAC,CAAC,CACzD,UAAU,CAAC,CAAC,iBAAiB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,EACxD,CACH,CAAC;IACJ,CAAC;CACF","sourcesContent":["import React from 'react';\nimport { StyleSheet } from 'react-native';\n\nimport ExpoImage, { ExpoImageModule } from './ExpoImage';\nimport { ImageProps } from './Image.types';\nimport { resolveContentFit, resolveContentPosition, resolveTransition } from './utils';\nimport { resolveSources } from './utils/resolveSources';\n\nlet loggedDefaultSourceDeprecationWarning = false;\n\nexport class Image extends React.PureComponent<ImageProps> {\n nativeViewRef;\n\n constructor(props) {\n super(props);\n this.nativeViewRef = React.createRef();\n }\n\n /**\n * Preloads images at the given URLs that can be later used in the image view.\n * Preloaded images are cached to the memory and disk by default, so make sure\n * to use `disk` (default) or `memory-disk` [cache policy](#cachepolicy).\n * @param urls - A URL string or an array of URLs of images to prefetch.\n * @param cachePolicy - The cache policy for prefetched images.\n * @return A promise resolving to `true` as soon as all images have been\n * successfully prefetched. If an image fails to be prefetched, the promise\n * will immediately resolve to `false` regardless of whether other images have\n * finished prefetching.\n */\n static async prefetch(\n urls: string | string[],\n cachePolicy: 'memory-disk' | 'memory' = 'memory-disk'\n ): Promise<boolean> {\n return ExpoImageModule.prefetch(Array.isArray(urls) ? urls : [urls], cachePolicy);\n }\n\n /**\n * Asynchronously clears all images stored in memory.\n * @platform android\n * @platform ios\n * @return A promise resolving to `true` when the operation succeeds.\n * It may resolve to `false` on Android when the activity is no longer available.\n * Resolves to `false` on Web.\n */\n static async clearMemoryCache(): Promise<boolean> {\n return await ExpoImageModule.clearMemoryCache();\n }\n\n /**\n * Asynchronously clears all images from the disk cache.\n * @platform android\n * @platform ios\n * @return A promise resolving to `true` when the operation succeeds.\n * It may resolve to `false` on Android when the activity is no longer available.\n * Resolves to `false` on Web.\n */\n static async clearDiskCache(): Promise<boolean> {\n return await ExpoImageModule.clearDiskCache();\n }\n\n /**\n * Asynchronously checks if an image exists in the disk cache and resolves to\n * the path of the cached image if it does.\n * @param cacheKey - The cache key for the requested image. Unless you have set\n * a custom cache key, this will be the source URL of the image.\n * @platform android\n * @platform ios\n * @return A promise resolving to the path of the cached image. It will resolve\n * to `null` if the image does not exist in the cache.\n */\n static async getCachePathAsync(cacheKey: string): Promise<string | null> {\n return await ExpoImageModule.getCachePathAsync(cacheKey);\n }\n\n /**\n * Asynchronously starts playback of the view's image if it is animated.\n * @platform ios\n */\n async startAnimating(): Promise<void> {\n await this.nativeViewRef.current.startAnimating();\n }\n\n /**\n * Asynchronously stops the playback of the view's image if it is animated.\n * @platform ios\n */\n async stopAnimating(): Promise<void> {\n await this.nativeViewRef.current.stopAnimating();\n }\n\n render() {\n const {\n style,\n source,\n placeholder,\n contentFit,\n contentPosition,\n transition,\n fadeDuration,\n resizeMode: resizeModeProp,\n defaultSource,\n loadingIndicatorSource,\n ...restProps\n } = this.props;\n\n const { resizeMode: resizeModeStyle, ...restStyle } = StyleSheet.flatten(style) || {};\n const resizeMode = resizeModeProp ?? resizeModeStyle;\n\n if ((defaultSource || loadingIndicatorSource) && !loggedDefaultSourceDeprecationWarning) {\n console.warn(\n '[expo-image]: `defaultSource` and `loadingIndicatorSource` props are deprecated, use `placeholder` instead'\n );\n loggedDefaultSourceDeprecationWarning = true;\n }\n\n return (\n <ExpoImage\n {...restProps}\n style={restStyle}\n source={resolveSources(source)}\n placeholder={resolveSources(placeholder ?? defaultSource ?? loadingIndicatorSource)}\n contentFit={resolveContentFit(contentFit, resizeMode)}\n contentPosition={resolveContentPosition(contentPosition)}\n transition={resolveTransition(transition, fadeDuration)}\n />\n );\n }\n}\n"]}
|
package/ios/ImageModule.swift
CHANGED
|
@@ -108,8 +108,26 @@ public final class ImageModule: Module {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
AsyncFunction("prefetch") { (urls: [URL], cachePolicy: ImageCachePolicy, promise: Promise) in
|
|
112
|
+
var context = SDWebImageContext()
|
|
113
|
+
context[.storeCacheType] = cachePolicy.toSdCacheType().rawValue
|
|
114
|
+
|
|
115
|
+
var imagesLoaded = 0
|
|
116
|
+
var failed = false
|
|
117
|
+
|
|
118
|
+
urls.forEach { url in
|
|
119
|
+
SDWebImagePrefetcher.shared.prefetchURLs([url], context: context, progress: nil, completed: { loaded, skipped in
|
|
120
|
+
if skipped > 0 && !failed {
|
|
121
|
+
failed = true
|
|
122
|
+
promise.resolve(false)
|
|
123
|
+
} else {
|
|
124
|
+
imagesLoaded = imagesLoaded + 1
|
|
125
|
+
if imagesLoaded == urls.count {
|
|
126
|
+
promise.resolve(true)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
}
|
|
113
131
|
}
|
|
114
132
|
|
|
115
133
|
AsyncFunction("clearMemoryCache") { () -> Bool in
|
package/ios/ImageView.swift
CHANGED
|
@@ -67,8 +67,8 @@ public final class ImageView: ExpoView {
|
|
|
67
67
|
|
|
68
68
|
public override var bounds: CGRect {
|
|
69
69
|
didSet {
|
|
70
|
-
// Reload the image when the bounds size has changed and
|
|
71
|
-
if oldValue.size != bounds.size &&
|
|
70
|
+
// Reload the image when the bounds size has changed and is not empty.
|
|
71
|
+
if oldValue.size != bounds.size && bounds.size != .zero {
|
|
72
72
|
reload()
|
|
73
73
|
}
|
|
74
74
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-image",
|
|
3
3
|
"title": "Expo Image",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.8.1",
|
|
5
5
|
"description": "A cross-platform, performant image component for React Native and Expo with Web support",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"types": "build/index.d.ts",
|
|
@@ -33,5 +33,5 @@
|
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"expo": "*"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "8951e9a6edc691f350c8e894863b6cf14720317a"
|
|
37
37
|
}
|
package/src/ExpoImage.web.tsx
CHANGED
|
@@ -10,11 +10,24 @@ import useSourceSelection from './web/useSourceSelection';
|
|
|
10
10
|
loadStyle();
|
|
11
11
|
|
|
12
12
|
export const ExpoImageModule = {
|
|
13
|
-
prefetch(urls: string | string[]):
|
|
13
|
+
async prefetch(urls: string | string[], _): Promise<boolean> {
|
|
14
14
|
const urlsArray = Array.isArray(urls) ? urls : [urls];
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
|
|
16
|
+
return new Promise<boolean>((resolve) => {
|
|
17
|
+
let imagesLoaded = 0;
|
|
18
|
+
|
|
19
|
+
urlsArray.forEach((url) => {
|
|
20
|
+
const img = new Image();
|
|
21
|
+
img.src = url;
|
|
22
|
+
img.onload = () => {
|
|
23
|
+
imagesLoaded++;
|
|
24
|
+
|
|
25
|
+
if (imagesLoaded === urlsArray.length) {
|
|
26
|
+
resolve(true);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
img.onerror = () => resolve(false);
|
|
30
|
+
});
|
|
18
31
|
});
|
|
19
32
|
},
|
|
20
33
|
|
package/src/Image.tsx
CHANGED
|
@@ -17,12 +17,21 @@ export class Image extends React.PureComponent<ImageProps> {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Preloads images at the given
|
|
21
|
-
* Preloaded images are
|
|
22
|
-
* `disk` (default) or `memory-disk` cache policy.
|
|
20
|
+
* Preloads images at the given URLs that can be later used in the image view.
|
|
21
|
+
* Preloaded images are cached to the memory and disk by default, so make sure
|
|
22
|
+
* to use `disk` (default) or `memory-disk` [cache policy](#cachepolicy).
|
|
23
|
+
* @param urls - A URL string or an array of URLs of images to prefetch.
|
|
24
|
+
* @param cachePolicy - The cache policy for prefetched images.
|
|
25
|
+
* @return A promise resolving to `true` as soon as all images have been
|
|
26
|
+
* successfully prefetched. If an image fails to be prefetched, the promise
|
|
27
|
+
* will immediately resolve to `false` regardless of whether other images have
|
|
28
|
+
* finished prefetching.
|
|
23
29
|
*/
|
|
24
|
-
static prefetch(
|
|
25
|
-
|
|
30
|
+
static async prefetch(
|
|
31
|
+
urls: string | string[],
|
|
32
|
+
cachePolicy: 'memory-disk' | 'memory' = 'memory-disk'
|
|
33
|
+
): Promise<boolean> {
|
|
34
|
+
return ExpoImageModule.prefetch(Array.isArray(urls) ? urls : [urls], cachePolicy);
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
/**
|