expo-image 1.2.0 → 1.2.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 +10 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/expo/modules/image/ExpoImageModule.kt +4 -1
- package/android/src/main/java/expo/modules/image/ExpoImageViewWrapper.kt +9 -9
- package/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt +4 -0
- package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModelLoader.kt +5 -2
- package/build/utils/resolveHashString.d.ts.map +1 -1
- package/build/utils/resolveHashString.js +3 -1
- package/build/utils/resolveHashString.js.map +1 -1
- package/ios/ThumbhashLoader.swift +5 -4
- package/package.json +2 -2
- package/src/utils/resolveHashString.tsx +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 1.2.1 — 2023-04-17
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- [Android] Fix `url` property returned by the `onLoad` event. ([#22161](https://github.com/expo/expo/pull/22161) by [@lukmccall](https://github.com/lukmccall))
|
|
18
|
+
- [Android] Fix images not loading after the app was foregrounded. ([#22159](https://github.com/expo/expo/pull/22159) by [@lukmccall](https://github.com/lukmccall))
|
|
19
|
+
- [Android] Fixed image was loaded event if the view dimensions were 0. ([#22157](https://github.com/expo/expo/pull/22157) by [@lukmccall](https://github.com/lukmccall))
|
|
20
|
+
- Fix generating the image from ThumbHash that starts with a slash character. ([#22160](https://github.com/expo/expo/pull/22160) by [@tsapeta](https://github.com/tsapeta))
|
|
21
|
+
|
|
13
22
|
## 1.2.0 — 2023-04-14
|
|
14
23
|
|
|
15
24
|
### 🎉 New features
|
|
@@ -22,6 +31,7 @@
|
|
|
22
31
|
### 🐛 Bug fixes
|
|
23
32
|
|
|
24
33
|
- [Web] Prevent breaking in static rendering environments. ([#21883](https://github.com/expo/expo/pull/21883) by [@EvanBacon](https://github.com/EvanBacon))
|
|
34
|
+
- [Android] Fixed image disappearing before navigation animation is complete. ([#22066](https://github.com/expo/expo/pull/22066) by [@sallen450](https://github.com/sallen450))
|
|
25
35
|
- [Web] Fixed monorepo asset resolution in production for Metro web. ([#22094](https://github.com/expo/expo/pull/22094) by [@EvanBacon](https://github.com/EvanBacon))
|
|
26
36
|
|
|
27
37
|
## 1.1.0 — 2023-03-25
|
package/android/build.gradle
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package expo.modules.image
|
|
2
2
|
|
|
3
3
|
import android.view.View
|
|
4
|
+
import androidx.core.view.doOnDetach
|
|
4
5
|
import com.bumptech.glide.Glide
|
|
5
6
|
import com.bumptech.glide.load.model.GlideUrl
|
|
6
7
|
import com.facebook.react.uimanager.PixelUtil
|
|
@@ -171,7 +172,9 @@ class ExpoImageModule : Module() {
|
|
|
171
172
|
}
|
|
172
173
|
|
|
173
174
|
OnViewDestroys { view: ExpoImageViewWrapper ->
|
|
174
|
-
view.
|
|
175
|
+
view.doOnDetach {
|
|
176
|
+
view.onViewDestroys()
|
|
177
|
+
}
|
|
175
178
|
}
|
|
176
179
|
}
|
|
177
180
|
}
|
|
@@ -3,7 +3,6 @@ package expo.modules.image
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.app.Activity
|
|
5
5
|
import android.content.Context
|
|
6
|
-
import android.graphics.Rect
|
|
7
6
|
import android.graphics.drawable.Animatable
|
|
8
7
|
import android.graphics.drawable.Drawable
|
|
9
8
|
import android.os.Build
|
|
@@ -371,13 +370,11 @@ class ExpoImageViewWrapper(context: Context, appContext: AppContext) : ExpoView(
|
|
|
371
370
|
return sources.first()
|
|
372
371
|
}
|
|
373
372
|
|
|
374
|
-
val
|
|
375
|
-
if (
|
|
373
|
+
val targetPixelCount = width * height
|
|
374
|
+
if (targetPixelCount == 0) {
|
|
376
375
|
return null
|
|
377
376
|
}
|
|
378
377
|
|
|
379
|
-
val targetPixelCount = selfRect.width() * selfRect.height()
|
|
380
|
-
|
|
381
378
|
var bestSource: SourceMap? = null
|
|
382
379
|
var bestFit = Double.MAX_VALUE
|
|
383
380
|
|
|
@@ -433,8 +430,8 @@ class ExpoImageViewWrapper(context: Context, appContext: AppContext) : ExpoView(
|
|
|
433
430
|
|
|
434
431
|
val sourceToLoad = bestSource?.createGlideModel(context)
|
|
435
432
|
val placeholder = bestPlaceholder?.createGlideModel(context)
|
|
436
|
-
// We only clean the image when the source is set to null and we don't have a placeholder.
|
|
437
|
-
if ((bestSource == null || sourceToLoad == null) && placeholder == null) {
|
|
433
|
+
// We only clean the image when the source is set to null and we don't have a placeholder or the view is empty.
|
|
434
|
+
if (width == 0 || height == 0 || (bestSource == null || sourceToLoad == null) && placeholder == null) {
|
|
438
435
|
firstView.recycleView()
|
|
439
436
|
secondView.recycleView()
|
|
440
437
|
|
|
@@ -621,6 +618,7 @@ class ExpoImageViewWrapper(context: Context, appContext: AppContext) : ExpoView(
|
|
|
621
618
|
companion object {
|
|
622
619
|
private var requestManager: RequestManager? = null
|
|
623
620
|
private var appContextRef: WeakReference<AppContext?> = WeakReference(null)
|
|
621
|
+
private var activityRef: WeakReference<Activity?> = WeakReference(null)
|
|
624
622
|
|
|
625
623
|
fun getOrCreateRequestManager(
|
|
626
624
|
appContext: AppContext,
|
|
@@ -630,13 +628,15 @@ class ExpoImageViewWrapper(context: Context, appContext: AppContext) : ExpoView(
|
|
|
630
628
|
?: return createNewRequestManager(activity).also {
|
|
631
629
|
requestManager = it
|
|
632
630
|
appContextRef = WeakReference(appContext)
|
|
631
|
+
activityRef = WeakReference(activity)
|
|
633
632
|
}
|
|
634
633
|
|
|
635
|
-
// Request manager was created using different activity
|
|
636
|
-
if (appContextRef.get() != appContext) {
|
|
634
|
+
// Request manager was created using different activity or app context
|
|
635
|
+
if (appContextRef.get() != appContext || activityRef.get() != activity) {
|
|
637
636
|
return createNewRequestManager(activity).also {
|
|
638
637
|
requestManager = it
|
|
639
638
|
appContextRef = WeakReference(appContext)
|
|
639
|
+
activityRef = WeakReference(activity)
|
|
640
640
|
}
|
|
641
641
|
}
|
|
642
642
|
|
|
@@ -13,8 +13,11 @@ class ThumbhashModelLoader : ModelLoader<GlideThumbhashModel, Bitmap> {
|
|
|
13
13
|
override fun handles(model: GlideThumbhashModel): Boolean = true
|
|
14
14
|
|
|
15
15
|
override fun buildLoadData(model: GlideThumbhashModel, width: Int, height: Int, options: Options): ModelLoader.LoadData<Bitmap> {
|
|
16
|
-
//
|
|
17
|
-
|
|
16
|
+
// The URI looks like this: thumbhash:/3OcRJYB4d3h\iIeHeEh3eIhw+j2w
|
|
17
|
+
// ThumbHash may include slashes which could break the structure of the URL, so we replace them
|
|
18
|
+
// with backslashes on the JS side and revert them back to slashes here, before generating the image.
|
|
19
|
+
val thumbhash = model.uri.pathSegments.joinToString(separator = "/").replace("\\", "/")
|
|
20
|
+
|
|
18
21
|
return ModelLoader.LoadData(
|
|
19
22
|
ObjectKey(model),
|
|
20
23
|
ThumbhashFetcher(thumbhash)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveHashString.d.ts","sourceRoot":"","sources":["../../src/utils/resolveHashString.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAS7C;;;;KAIK;AACL,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAO9D;AAED;;;;KAIK;AACL,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"resolveHashString.d.ts","sourceRoot":"","sources":["../../src/utils/resolveHashString.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAS7C;;;;KAIK;AACL,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAO9D;AAED;;;;KAIK;AACL,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAO/D"}
|
|
@@ -21,7 +21,9 @@ export function resolveBlurhashString(str) {
|
|
|
21
21
|
* @return An ImageSource representing the provided thumbhash.
|
|
22
22
|
* */
|
|
23
23
|
export function resolveThumbhashString(str) {
|
|
24
|
-
|
|
24
|
+
// ThumbHash may contain slashes that could break the url when the slash is at the beginning.
|
|
25
|
+
// We replace slashes with backslashes to make sure we don't break the url's path.
|
|
26
|
+
const thumbhash = str.replace(/^thumbhash:\//, '').replace(/\//g, '\\');
|
|
25
27
|
return {
|
|
26
28
|
uri: hashToUri('thumbhash', thumbhash),
|
|
27
29
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveHashString.js","sourceRoot":"","sources":["../../src/utils/resolveHashString.tsx"],"names":[],"mappings":"AAIA,SAAS,SAAS,CAAC,IAAmB,EAAE,IAAY;IAClD,MAAM,eAAe,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACnF,OAAO,GAAG,IAAI,KAAK,eAAe,EAAE,CAAC;AACvC,CAAC;AAED;;;;KAIK;AACL,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7E,OAAO;QACL,GAAG,EAAE,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC;QACpC,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE;QAChC,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,EAAE;KACnC,CAAC;AACJ,CAAC;AAED;;;;KAIK;AACL,MAAM,UAAU,sBAAsB,CAAC,GAAW;IAChD,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"resolveHashString.js","sourceRoot":"","sources":["../../src/utils/resolveHashString.tsx"],"names":[],"mappings":"AAIA,SAAS,SAAS,CAAC,IAAmB,EAAE,IAAY;IAClD,MAAM,eAAe,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACnF,OAAO,GAAG,IAAI,KAAK,eAAe,EAAE,CAAC;AACvC,CAAC;AAED;;;;KAIK;AACL,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7E,OAAO;QACL,GAAG,EAAE,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC;QACpC,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE;QAChC,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,EAAE;KACnC,CAAC;AACJ,CAAC;AAED;;;;KAIK;AACL,MAAM,UAAU,sBAAsB,CAAC,GAAW;IAChD,6FAA6F;IAC7F,kFAAkF;IAClF,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACxE,OAAO;QACL,GAAG,EAAE,SAAS,CAAC,WAAW,EAAE,SAAS,CAAC;KACvC,CAAC;AACJ,CAAC","sourcesContent":["import { ImageSource } from '../Image.types';\n\ntype ImageHashType = 'blurhash' | 'thumbhash';\n\nfunction hashToUri(type: ImageHashType, hash: string): string {\n const encodedBlurhash = encodeURI(hash).replace(/#/g, '%23').replace(/\\?/g, '%3F');\n return `${type}:/${encodedBlurhash}`;\n}\n\n/**\n * Converts a blurhash string (`blurhash:/<hash>/<width>/<height>` or <hash>/<width>/<height>) into an `ImageSource`.\n *\n * @return An ImageSource representing the provided blurhash.\n * */\nexport function resolveBlurhashString(str: string): ImageSource {\n const [blurhash, width, height] = str.replace(/^blurhash:\\//, '').split('/');\n return {\n uri: hashToUri('blurhash', blurhash),\n width: parseInt(width, 10) || 16,\n height: parseInt(height, 10) || 16,\n };\n}\n\n/**\n * Converts a thumbhash string (`thumbhash:/<hash>` or `<hash>`) into an `ImageSource`.\n *\n * @return An ImageSource representing the provided thumbhash.\n * */\nexport function resolveThumbhashString(str: string): ImageSource {\n // ThumbHash may contain slashes that could break the url when the slash is at the beginning.\n // We replace slashes with backslashes to make sure we don't break the url's path.\n const thumbhash = str.replace(/^thumbhash:\\//, '').replace(/\\//g, '\\\\');\n return {\n uri: hashToUri('thumbhash', thumbhash),\n };\n}\n"]}
|
|
@@ -21,9 +21,10 @@ class ThumbhashLoader: NSObject, SDImageLoader {
|
|
|
21
21
|
return nil
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
// The URI looks like this: thumbhash:/3OcRJYB4d3h
|
|
25
|
-
//
|
|
26
|
-
|
|
24
|
+
// The URI looks like this: thumbhash:/3OcRJYB4d3h\iIeHeEh3eIhw+j2w
|
|
25
|
+
// ThumbHash may include slashes which could break the structure of the URL, so we replace them
|
|
26
|
+
// with backslashes on the JS side and revert them back to slashes here, before generating the image.
|
|
27
|
+
var thumbhash = (url.pathComponents[1] ?? "").replacingOccurrences(of: "\\", with: "/")
|
|
27
28
|
|
|
28
29
|
// Thumbhashes with transparency cause the conversion to data to fail, padding the thumbhash string to correct length fixes that
|
|
29
30
|
let remainder = thumbhash.count % 4
|
|
@@ -31,7 +32,7 @@ class ThumbhashLoader: NSObject, SDImageLoader {
|
|
|
31
32
|
thumbhash = thumbhash.padding(toLength: thumbhash.count + 4 - remainder, withPad: "=", startingAt: 0)
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
guard let thumbhashData = Data(base64Encoded: thumbhash, options: .ignoreUnknownCharacters) else {
|
|
35
|
+
guard !thumbhash.isEmpty, let thumbhashData = Data(base64Encoded: thumbhash, options: .ignoreUnknownCharacters) else {
|
|
35
36
|
let error = makeNSError(description: "URL provided to ThumbhashLoader is invalid")
|
|
36
37
|
completedBlock?(nil, nil, error, false)
|
|
37
38
|
return nil
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-image",
|
|
3
3
|
"title": "Expo Image",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.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": "836bea54c7c2ba747df428d8217d85703a9701fb"
|
|
37
37
|
}
|
|
@@ -27,7 +27,9 @@ export function resolveBlurhashString(str: string): ImageSource {
|
|
|
27
27
|
* @return An ImageSource representing the provided thumbhash.
|
|
28
28
|
* */
|
|
29
29
|
export function resolveThumbhashString(str: string): ImageSource {
|
|
30
|
-
|
|
30
|
+
// ThumbHash may contain slashes that could break the url when the slash is at the beginning.
|
|
31
|
+
// We replace slashes with backslashes to make sure we don't break the url's path.
|
|
32
|
+
const thumbhash = str.replace(/^thumbhash:\//, '').replace(/\//g, '\\');
|
|
31
33
|
return {
|
|
32
34
|
uri: hashToUri('thumbhash', thumbhash),
|
|
33
35
|
};
|