@amazon-devices/expo-image 2.0.1758683737
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/.eslintrc.js +2 -0
- package/CHANGELOG.md +285 -0
- package/CMakeLists.txt +91 -0
- package/LICENSE +7 -0
- package/README.kepler.md +123 -0
- package/README.md +54 -0
- package/THIRD_PARTY_NOTICES.txt +24 -0
- package/android/build.gradle +124 -0
- package/android/proguard-rules.pro +28 -0
- package/android/src/main/AndroidManifest.xml +15 -0
- package/android/src/main/java/expo/modules/image/Exceptions.kt +9 -0
- package/android/src/main/java/expo/modules/image/ExpoImageAppGlideModule.kt +19 -0
- package/android/src/main/java/expo/modules/image/ExpoImageModule.kt +192 -0
- package/android/src/main/java/expo/modules/image/ExpoImageView.kt +220 -0
- package/android/src/main/java/expo/modules/image/ExpoImageViewWrapper.kt +652 -0
- package/android/src/main/java/expo/modules/image/GlideModel.kt +73 -0
- package/android/src/main/java/expo/modules/image/ImageUtils.kt +50 -0
- package/android/src/main/java/expo/modules/image/ImageViewWrapperTarget.kt +313 -0
- package/android/src/main/java/expo/modules/image/ResourceIdHelper.kt +47 -0
- package/android/src/main/java/expo/modules/image/ThumbnailRequestCoordinatorExtension.kt +21 -0
- package/android/src/main/java/expo/modules/image/YogaUtils.kt +20 -0
- package/android/src/main/java/expo/modules/image/blurhash/BlurHashFetcher.kt +32 -0
- package/android/src/main/java/expo/modules/image/blurhash/BlurhashDecoder.kt +189 -0
- package/android/src/main/java/expo/modules/image/blurhash/BlurhashModelLoader.kt +30 -0
- package/android/src/main/java/expo/modules/image/blurhash/BlurhashModelLoaderFactory.kt +14 -0
- package/android/src/main/java/expo/modules/image/blurhash/BlurhashModule.kt +17 -0
- package/android/src/main/java/expo/modules/image/dataurls/Base64DataFetcher.kt +27 -0
- package/android/src/main/java/expo/modules/image/dataurls/Base64ModelLoader.kt +24 -0
- package/android/src/main/java/expo/modules/image/dataurls/Base64ModelLoaderFactory.kt +12 -0
- package/android/src/main/java/expo/modules/image/dataurls/Base64Module.kt +16 -0
- package/android/src/main/java/expo/modules/image/drawing/OutlineProvider.kt +201 -0
- package/android/src/main/java/expo/modules/image/enums/ContentFit.kt +89 -0
- package/android/src/main/java/expo/modules/image/enums/ImageCacheType.kt +14 -0
- package/android/src/main/java/expo/modules/image/enums/Priority.kt +15 -0
- package/android/src/main/java/expo/modules/image/events/GlideRequestListener.kt +64 -0
- package/android/src/main/java/expo/modules/image/events/OkHttpProgressListener.kt +26 -0
- package/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt +80 -0
- package/android/src/main/java/expo/modules/image/okhttp/GlideUrlWrapperLoader.kt +55 -0
- package/android/src/main/java/expo/modules/image/records/CachePolicy.kt +10 -0
- package/android/src/main/java/expo/modules/image/records/ContentPosition.kt +89 -0
- package/android/src/main/java/expo/modules/image/records/ImageTransition.kt +8 -0
- package/android/src/main/java/expo/modules/image/records/SourceMap.kt +160 -0
- package/android/src/main/java/expo/modules/image/records/events.kt +25 -0
- package/android/src/main/java/expo/modules/image/svg/SVGDecoder.kt +33 -0
- package/android/src/main/java/expo/modules/image/svg/SVGDrawableTranscoder.kt +37 -0
- package/android/src/main/java/expo/modules/image/svg/SVGModule.kt +26 -0
- package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashDecoder.kt +365 -0
- package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashFetcher.kt +31 -0
- package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModelLoader.kt +26 -0
- package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModelLoaderFactory.kt +14 -0
- package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModule.kt +17 -0
- package/build/ExpoImage.d.ts +15 -0
- package/build/ExpoImage.d.ts.map +1 -0
- package/build/ExpoImage.js +75 -0
- package/build/ExpoImage.js.map +1 -0
- package/build/ExpoImage.kepler.d.ts +23 -0
- package/build/ExpoImage.kepler.d.ts.map +1 -0
- package/build/ExpoImage.kepler.js +71 -0
- package/build/ExpoImage.kepler.js.map +1 -0
- package/build/ExpoImage.web.d.ts +9 -0
- package/build/ExpoImage.web.d.ts.map +1 -0
- package/build/ExpoImage.web.js +90 -0
- package/build/ExpoImage.web.js.map +1 -0
- package/build/ExpoImageModules.d.ts +3 -0
- package/build/ExpoImageModules.d.ts.map +1 -0
- package/build/ExpoImageModules.js +4 -0
- package/build/ExpoImageModules.js.map +1 -0
- package/build/ExpoImageModules.kepler.d.ts +6 -0
- package/build/ExpoImageModules.kepler.d.ts.map +1 -0
- package/build/ExpoImageModules.kepler.js +5 -0
- package/build/ExpoImageModules.kepler.js.map +1 -0
- package/build/Image.d.ts +30 -0
- package/build/Image.d.ts.map +1 -0
- package/build/Image.js +49 -0
- package/build/Image.js.map +1 -0
- package/build/Image.types.d.ts +374 -0
- package/build/Image.types.d.ts.map +1 -0
- package/build/Image.types.js +2 -0
- package/build/Image.types.js.map +1 -0
- package/build/ImageBackground.d.ts +6 -0
- package/build/ImageBackground.d.ts.map +1 -0
- package/build/ImageBackground.js +13 -0
- package/build/ImageBackground.js.map +1 -0
- package/build/ImageViewNativeComponent.d.ts +20 -0
- package/build/ImageViewNativeComponent.d.ts.map +1 -0
- package/build/ImageViewNativeComponent.js +42 -0
- package/build/ImageViewNativeComponent.js.map +1 -0
- package/build/NativeImageLoaderKepler.d.ts +18 -0
- package/build/NativeImageLoaderKepler.d.ts.map +1 -0
- package/build/NativeImageLoaderKepler.js +3 -0
- package/build/NativeImageLoaderKepler.js.map +1 -0
- package/build/fabric/registerNativeComponent.d.ts +15 -0
- package/build/fabric/registerNativeComponent.d.ts.map +1 -0
- package/build/fabric/registerNativeComponent.js +47 -0
- package/build/fabric/registerNativeComponent.js.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +4 -0
- package/build/index.js.map +1 -0
- package/build/utils/AssetSourceResolver.web.d.ts +24 -0
- package/build/utils/AssetSourceResolver.web.d.ts.map +1 -0
- package/build/utils/AssetSourceResolver.web.js +67 -0
- package/build/utils/AssetSourceResolver.web.js.map +1 -0
- package/build/utils/blurhash/base83.d.ts +3 -0
- package/build/utils/blurhash/base83.d.ts.map +1 -0
- package/build/utils/blurhash/base83.js +103 -0
- package/build/utils/blurhash/base83.js.map +1 -0
- package/build/utils/blurhash/decode.d.ts +7 -0
- package/build/utils/blurhash/decode.d.ts.map +1 -0
- package/build/utils/blurhash/decode.js +92 -0
- package/build/utils/blurhash/decode.js.map +1 -0
- package/build/utils/blurhash/error.d.ts +4 -0
- package/build/utils/blurhash/error.d.ts.map +1 -0
- package/build/utils/blurhash/error.js +8 -0
- package/build/utils/blurhash/error.js.map +1 -0
- package/build/utils/blurhash/useBlurhash.d.ts +8 -0
- package/build/utils/blurhash/useBlurhash.d.ts.map +1 -0
- package/build/utils/blurhash/useBlurhash.js +64 -0
- package/build/utils/blurhash/useBlurhash.js.map +1 -0
- package/build/utils/blurhash/utils.d.ts +5 -0
- package/build/utils/blurhash/utils.d.ts.map +1 -0
- package/build/utils/blurhash/utils.js +21 -0
- package/build/utils/blurhash/utils.js.map +1 -0
- package/build/utils/resolveAssetSource.d.ts +3 -0
- package/build/utils/resolveAssetSource.d.ts.map +1 -0
- package/build/utils/resolveAssetSource.js +3 -0
- package/build/utils/resolveAssetSource.js.map +1 -0
- package/build/utils/resolveAssetSource.web.d.ts +9 -0
- package/build/utils/resolveAssetSource.web.d.ts.map +1 -0
- package/build/utils/resolveAssetSource.web.js +31 -0
- package/build/utils/resolveAssetSource.web.js.map +1 -0
- package/build/utils/resolveHashString.d.ts +14 -0
- package/build/utils/resolveHashString.d.ts.map +1 -0
- package/build/utils/resolveHashString.js +31 -0
- package/build/utils/resolveHashString.js.map +1 -0
- package/build/utils/resolveHashString.web.d.ts +20 -0
- package/build/utils/resolveHashString.web.d.ts.map +1 -0
- package/build/utils/resolveHashString.web.js +31 -0
- package/build/utils/resolveHashString.web.js.map +1 -0
- package/build/utils/resolveSources.d.ts +8 -0
- package/build/utils/resolveSources.d.ts.map +1 -0
- package/build/utils/resolveSources.js +45 -0
- package/build/utils/resolveSources.js.map +1 -0
- package/build/utils/thumbhash/thumbhash.d.ts +66 -0
- package/build/utils/thumbhash/thumbhash.d.ts.map +1 -0
- package/build/utils/thumbhash/thumbhash.js +338 -0
- package/build/utils/thumbhash/thumbhash.js.map +1 -0
- package/build/utils.d.ts +17 -0
- package/build/utils.d.ts.map +1 -0
- package/build/utils.js +85 -0
- package/build/utils.js.map +1 -0
- package/build/web/AnimationManager.d.ts +37 -0
- package/build/web/AnimationManager.d.ts.map +1 -0
- package/build/web/AnimationManager.js +155 -0
- package/build/web/AnimationManager.js.map +1 -0
- package/build/web/ColorTintFilter.d.ts +12 -0
- package/build/web/ColorTintFilter.d.ts.map +1 -0
- package/build/web/ColorTintFilter.js +30 -0
- package/build/web/ColorTintFilter.js.map +1 -0
- package/build/web/ImageWrapper.d.ts +5 -0
- package/build/web/ImageWrapper.d.ts.map +1 -0
- package/build/web/ImageWrapper.js +44 -0
- package/build/web/ImageWrapper.js.map +1 -0
- package/build/web/ImageWrapper.types.d.ts +29 -0
- package/build/web/ImageWrapper.types.d.ts.map +1 -0
- package/build/web/ImageWrapper.types.js +2 -0
- package/build/web/ImageWrapper.types.js.map +1 -0
- package/build/web/getImageWrapperEventHandler.d.ts +8 -0
- package/build/web/getImageWrapperEventHandler.d.ts.map +1 -0
- package/build/web/getImageWrapperEventHandler.js +25 -0
- package/build/web/getImageWrapperEventHandler.js.map +1 -0
- package/build/web/hooks.d.ts +13 -0
- package/build/web/hooks.d.ts.map +1 -0
- package/build/web/hooks.js +58 -0
- package/build/web/hooks.js.map +1 -0
- package/build/web/imageStyles.d.ts +2 -0
- package/build/web/imageStyles.d.ts.map +1 -0
- package/build/web/imageStyles.js +137 -0
- package/build/web/imageStyles.js.map +1 -0
- package/build/web/positioning.d.ts +11 -0
- package/build/web/positioning.d.ts.map +1 -0
- package/build/web/positioning.js +35 -0
- package/build/web/positioning.js.map +1 -0
- package/build/web/useSourceSelection.d.ts +14 -0
- package/build/web/useSourceSelection.d.ts.map +1 -0
- package/build/web/useSourceSelection.js +98 -0
- package/build/web/useSourceSelection.js.map +1 -0
- package/expo-module.config.json +9 -0
- package/ios/Blurhash.swift +326 -0
- package/ios/BlurhashLoader.swift +52 -0
- package/ios/ContentFit.swift +55 -0
- package/ios/ContentPosition.swift +108 -0
- package/ios/ExpoImage.podspec +30 -0
- package/ios/ImageCachePolicy.swift +24 -0
- package/ios/ImageCacheType.swift +21 -0
- package/ios/ImageModule.swift +127 -0
- package/ios/ImagePriority.swift +22 -0
- package/ios/ImageSource.swift +44 -0
- package/ios/ImageTransition.swift +67 -0
- package/ios/ImageUtils.swift +227 -0
- package/ios/ImageView.swift +469 -0
- package/ios/Loaders/PhotoLibraryAssetLoader.swift +146 -0
- package/ios/Thumbhash.swift +550 -0
- package/ios/ThumbhashLoader.swift +53 -0
- package/jest.config.js +3 -0
- package/kepler/ExpoImage.cpp +63 -0
- package/kepler/ExpoImage.h +29 -0
- package/kepler/ExpoImageCacheHandler.cpp +15 -0
- package/kepler/ExpoImageCacheHandler.h +28 -0
- package/kepler/ExpoImageComponent.cpp +579 -0
- package/kepler/ExpoImageComponent.h +199 -0
- package/kepler/ImageWrapper/BlurhashImageWrapper.cpp +37 -0
- package/kepler/ImageWrapper/BlurhashImageWrapper.h +23 -0
- package/kepler/ImageWrapper/CacheImageWrapper.cpp +80 -0
- package/kepler/ImageWrapper/CacheImageWrapper.h +41 -0
- package/kepler/ImageWrapper/HashImageWrapper.cpp +21 -0
- package/kepler/ImageWrapper/HashImageWrapper.h +22 -0
- package/kepler/ImageWrapper/ImageWrapper.cpp +24 -0
- package/kepler/ImageWrapper/ImageWrapper.h +33 -0
- package/kepler/ImageWrapper/LocalImageWrapper.cpp +61 -0
- package/kepler/ImageWrapper/LocalImageWrapper.h +30 -0
- package/kepler/ImageWrapper/ThumbhashImageWrapper.cpp +33 -0
- package/kepler/ImageWrapper/ThumbhashImageWrapper.h +20 -0
- package/kepler/KeplerImageViewComponent.h +64 -0
- package/kepler/KeplerInit.cpp +35 -0
- package/kepler/blurhash/common.h +32 -0
- package/kepler/blurhash/decode.cpp +187 -0
- package/kepler/blurhash/decode.h +58 -0
- package/kepler/contentposition/ImageContentPosition.cpp +86 -0
- package/kepler/contentposition/ImageContentPosition.h +48 -0
- package/kepler/enums/ImageContentFit.h +17 -0
- package/kepler/enums/ImagePriority.h +17 -0
- package/kepler/managers/ExpoImageManager.cpp +38 -0
- package/kepler/managers/ExpoImageManager.h +23 -0
- package/kepler/test/ExpoImage.cpp +73 -0
- package/kepler/test/ExpoImageComponent.cpp +290 -0
- package/kepler/test/blurhash/decode.cpp +39 -0
- package/kepler/test/contentposition/ImageContentPosition.cpp +100 -0
- package/kepler/test/managers/ExpoImageManager.cpp +39 -0
- package/kepler/test/thumbhash/decode.cpp +18 -0
- package/kepler/test/utils/LoaderDelegate.cpp +130 -0
- package/kepler/thumbhash/decode.cpp +166 -0
- package/kepler/thumbhash/decode.h +22 -0
- package/kepler/utils/PlaceholderImageLoaderDelegate.cpp +26 -0
- package/kepler/utils/PlaceholderImageLoaderDelegate.h +26 -0
- package/kepler/utils/PrefetchImageLoaderDelegate.cpp +55 -0
- package/kepler/utils/PrefetchImageLoaderDelegate.h +35 -0
- package/kepler/utils/SourceImageLoaderDelegate.cpp +47 -0
- package/kepler/utils/SourceImageLoaderDelegate.h +42 -0
- package/kepler/utils/SourceImageLoaderDelegateEmitter.cpp +15 -0
- package/kepler/utils/SourceImageLoaderDelegateEmitter.h +28 -0
- package/kepler-compatibility.json +8 -0
- package/package.json +1 -0
- package/react-native.config.js +22 -0
- package/src/ExpoImage.kepler.tsx +119 -0
- package/src/ExpoImage.tsx +119 -0
- package/src/ExpoImage.web.tsx +155 -0
- package/src/ExpoImageModules.kepler.ts +7 -0
- package/src/ExpoImageModules.ts +4 -0
- package/src/Image.tsx +82 -0
- package/src/Image.types.ts +450 -0
- package/src/ImageBackground.tsx +18 -0
- package/src/ImageViewNativeComponent.ts +59 -0
- package/src/NativeImageLoaderKepler.ts +22 -0
- package/src/fabric/registerNativeComponent.ts +70 -0
- package/src/index.ts +3 -0
- package/src/utils/AssetSourceResolver.web.ts +88 -0
- package/src/utils/blurhash/base83.ts +104 -0
- package/src/utils/blurhash/decode.ts +114 -0
- package/src/utils/blurhash/error.ts +7 -0
- package/src/utils/blurhash/useBlurhash.tsx +81 -0
- package/src/utils/blurhash/utils.ts +21 -0
- package/src/utils/resolveAssetSource.tsx +3 -0
- package/src/utils/resolveAssetSource.web.ts +40 -0
- package/src/utils/resolveHashString.tsx +36 -0
- package/src/utils/resolveHashString.web.tsx +33 -0
- package/src/utils/resolveSources.tsx +48 -0
- package/src/utils/thumbhash/thumbhash.ts +387 -0
- package/src/utils.ts +109 -0
- package/src/web/AnimationManager.tsx +224 -0
- package/src/web/ColorTintFilter.tsx +36 -0
- package/src/web/ImageWrapper.tsx +85 -0
- package/src/web/ImageWrapper.types.ts +36 -0
- package/src/web/getImageWrapperEventHandler.ts +29 -0
- package/src/web/hooks.ts +72 -0
- package/src/web/imageStyles.tsx +136 -0
- package/src/web/positioning.ts +48 -0
- package/src/web/useSourceSelection.ts +151 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
apply plugin: 'com.android.library'
|
|
2
|
+
apply plugin: 'kotlin-android'
|
|
3
|
+
apply plugin: 'maven-publish'
|
|
4
|
+
apply plugin: 'kotlin-kapt'
|
|
5
|
+
|
|
6
|
+
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
7
|
+
if (expoModulesCorePlugin.exists()) {
|
|
8
|
+
apply from: expoModulesCorePlugin
|
|
9
|
+
applyKotlinExpoModulesCorePlugin()
|
|
10
|
+
// Remove this check, but keep the contents after SDK49 support is dropped
|
|
11
|
+
if (safeExtGet("expoProvidesDefaultConfig", false)) {
|
|
12
|
+
useCoreDependencies()
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
buildscript {
|
|
17
|
+
// Simple helper that allows the root project to override versions declared by this library.
|
|
18
|
+
ext.safeExtGet = { prop, fallback ->
|
|
19
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Ensures backward compatibility
|
|
23
|
+
ext.getKotlinVersion = {
|
|
24
|
+
if (ext.has("kotlinVersion")) {
|
|
25
|
+
ext.kotlinVersion()
|
|
26
|
+
} else {
|
|
27
|
+
ext.safeExtGet("kotlinVersion", "1.8.10")
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
repositories {
|
|
32
|
+
mavenCentral()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
dependencies {
|
|
36
|
+
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
android {
|
|
41
|
+
// Remove this if and it's contents, when support for SDK49 is dropped
|
|
42
|
+
if (!safeExtGet("expoProvidesDefaultConfig", false)) {
|
|
43
|
+
compileSdkVersion safeExtGet("compileSdkVersion", 33)
|
|
44
|
+
|
|
45
|
+
defaultConfig {
|
|
46
|
+
minSdkVersion safeExtGet("minSdkVersion", 23)
|
|
47
|
+
targetSdkVersion safeExtGet("targetSdkVersion", 33)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
lintOptions {
|
|
51
|
+
abortOnError false
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
|
|
56
|
+
if (agpVersion.tokenize('.')[0].toInteger() < 8) {
|
|
57
|
+
compileOptions {
|
|
58
|
+
sourceCompatibility JavaVersion.VERSION_11
|
|
59
|
+
targetCompatibility JavaVersion.VERSION_11
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
kotlinOptions {
|
|
63
|
+
jvmTarget = JavaVersion.VERSION_11.majorVersion
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
namespace "expo.modules.image"
|
|
68
|
+
defaultConfig {
|
|
69
|
+
versionCode 1
|
|
70
|
+
versionName "1.6.0"
|
|
71
|
+
consumerProguardFiles("proguard-rules.pro")
|
|
72
|
+
}
|
|
73
|
+
publishing {
|
|
74
|
+
singleVariant("release") {
|
|
75
|
+
withSourcesJar()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (safeExtGet("excludeAppGlideModule", false)) {
|
|
81
|
+
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
|
|
82
|
+
exclude("**/ExpoImageAppGlideModule.kt")
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
repositories {
|
|
87
|
+
// ref: https://www.baeldung.com/maven-local-repository
|
|
88
|
+
mavenLocal()
|
|
89
|
+
maven {
|
|
90
|
+
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
|
91
|
+
url "$rootDir/../node_modules/react-native/android"
|
|
92
|
+
}
|
|
93
|
+
maven {
|
|
94
|
+
// Android JSC is installed from npm
|
|
95
|
+
url "$rootDir/../node_modules/jsc-android/dist"
|
|
96
|
+
}
|
|
97
|
+
google()
|
|
98
|
+
mavenCentral()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
dependencies {
|
|
102
|
+
def GLIDE_VERSION = "4.13.2"
|
|
103
|
+
|
|
104
|
+
if (!safeExtGet("expoProvidesDefaultConfig", false)) {
|
|
105
|
+
implementation project(':expo-modules-core')
|
|
106
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
//noinspection GradleDynamicVersion
|
|
110
|
+
implementation 'com.facebook.react:react-native:+' // From node_modules
|
|
111
|
+
|
|
112
|
+
api "com.github.bumptech.glide:glide:${GLIDE_VERSION}"
|
|
113
|
+
kapt "com.github.bumptech.glide:compiler:${GLIDE_VERSION}"
|
|
114
|
+
api 'com.caverock:androidsvg-aar:1.4'
|
|
115
|
+
|
|
116
|
+
implementation "com.github.penfeizhou.android.animation:glide-plugin:2.28.0"
|
|
117
|
+
implementation "com.github.bumptech.glide:avif-integration:${GLIDE_VERSION}"
|
|
118
|
+
|
|
119
|
+
api 'com.github.bumptech.glide:okhttp3-integration:4.11.0'
|
|
120
|
+
api "com.squareup.okhttp3:okhttp:${safeExtGet("okHttpVersion", '4.9.2')}"
|
|
121
|
+
|
|
122
|
+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1'
|
|
123
|
+
implementation "jp.wasabeef:glide-transformations:4.3.0"
|
|
124
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# https://bumptech.github.io/glide/doc/download-setup.html#proguard
|
|
2
|
+
|
|
3
|
+
-keep public class * extends com.bumptech.glide.module.LibraryGlideModule
|
|
4
|
+
-keep public class * implements com.bumptech.glide.module.GlideModule
|
|
5
|
+
-keep class * extends com.bumptech.glide.module.AppGlideModule {
|
|
6
|
+
<init>(...);
|
|
7
|
+
}
|
|
8
|
+
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
|
|
9
|
+
**[] $VALUES;
|
|
10
|
+
public *;
|
|
11
|
+
}
|
|
12
|
+
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
|
|
13
|
+
*** rewind();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
-keep public class com.bumptech.glide.request.ThumbnailRequestCoordinator {
|
|
17
|
+
*;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
-dontwarn com.bumptech.glide.load.resource.bitmap.VideoDecoder
|
|
21
|
+
|
|
22
|
+
# https://bumptech.github.io/glide/doc/configuration.html#applications
|
|
23
|
+
|
|
24
|
+
-keep class com.bumptech.glide.GeneratedAppGlideModuleImpl
|
|
25
|
+
|
|
26
|
+
-keep public class com.bumptech.glide.integration.webp.WebpImage { *; }
|
|
27
|
+
-keep public class com.bumptech.glide.integration.webp.WebpFrame { *; }
|
|
28
|
+
-keep public class com.bumptech.glide.integration.webp.WebpBitmapFactory { *; }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
2
|
+
<!-- Begin Glide configuration -->
|
|
3
|
+
<!-- Internet access (https://bumptech.github.io/glide/doc/download-setup.html#internet) -->
|
|
4
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
5
|
+
<!--
|
|
6
|
+
Allows Glide to monitor connectivity status and restart failed requests if users go from a
|
|
7
|
+
a disconnected to a connected network state.
|
|
8
|
+
-->
|
|
9
|
+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
10
|
+
|
|
11
|
+
<!-- Local storage (https://bumptech.github.io/glide/doc/download-setup.html#local-storage) -->
|
|
12
|
+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
|
13
|
+
|
|
14
|
+
<!-- End Glide configuration -->
|
|
15
|
+
</manifest>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
package expo.modules.image
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.exception.CodedException
|
|
4
|
+
|
|
5
|
+
class ImagePrefetchFailure(message: String) :
|
|
6
|
+
CodedException(message = "Failed to prefetch the image: $message")
|
|
7
|
+
|
|
8
|
+
class MissingActivity :
|
|
9
|
+
CodedException(message = "The current activity is no longer available")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package expo.modules.image
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import com.bumptech.glide.GlideBuilder
|
|
6
|
+
import com.bumptech.glide.annotation.GlideModule
|
|
7
|
+
import com.bumptech.glide.module.AppGlideModule
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* We need to include an [AppGlideModule] for [GlideModule] annotations
|
|
11
|
+
* to work.
|
|
12
|
+
*/
|
|
13
|
+
@GlideModule
|
|
14
|
+
class ExpoImageAppGlideModule : AppGlideModule() {
|
|
15
|
+
override fun applyOptions(context: Context, builder: GlideBuilder) {
|
|
16
|
+
super.applyOptions(context, builder)
|
|
17
|
+
builder.setLogLevel(Log.ERROR)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
package expo.modules.image
|
|
2
|
+
|
|
3
|
+
import android.view.View
|
|
4
|
+
import androidx.core.view.doOnDetach
|
|
5
|
+
import com.bumptech.glide.Glide
|
|
6
|
+
import com.bumptech.glide.load.model.GlideUrl
|
|
7
|
+
import com.facebook.react.uimanager.PixelUtil
|
|
8
|
+
import com.facebook.react.uimanager.Spacing
|
|
9
|
+
import com.facebook.react.uimanager.ViewProps
|
|
10
|
+
import com.facebook.yoga.YogaConstants
|
|
11
|
+
import expo.modules.image.enums.ContentFit
|
|
12
|
+
import expo.modules.image.enums.Priority
|
|
13
|
+
import expo.modules.image.records.CachePolicy
|
|
14
|
+
import expo.modules.image.records.ContentPosition
|
|
15
|
+
import expo.modules.image.records.ImageTransition
|
|
16
|
+
import expo.modules.image.records.SourceMap
|
|
17
|
+
import expo.modules.kotlin.functions.Queues
|
|
18
|
+
import expo.modules.kotlin.modules.Module
|
|
19
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
20
|
+
import expo.modules.kotlin.views.ViewDefinitionBuilder
|
|
21
|
+
|
|
22
|
+
class ExpoImageModule : Module() {
|
|
23
|
+
override fun definition() = ModuleDefinition {
|
|
24
|
+
Name("ExpoImage")
|
|
25
|
+
|
|
26
|
+
Function("prefetch") { urls: List<String> ->
|
|
27
|
+
val context = appContext.reactContext ?: return@Function
|
|
28
|
+
urls.forEach {
|
|
29
|
+
Glide
|
|
30
|
+
.with(context)
|
|
31
|
+
.download(GlideUrl(it))
|
|
32
|
+
.submit()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
AsyncFunction("clearMemoryCache") {
|
|
37
|
+
val activity = appContext.currentActivity ?: return@AsyncFunction false
|
|
38
|
+
Glide.get(activity).clearMemory()
|
|
39
|
+
return@AsyncFunction true
|
|
40
|
+
}.runOnQueue(Queues.MAIN)
|
|
41
|
+
|
|
42
|
+
AsyncFunction("clearDiskCache") {
|
|
43
|
+
val activity = appContext.currentActivity ?: return@AsyncFunction false
|
|
44
|
+
activity.let {
|
|
45
|
+
Glide.get(activity).clearDiskCache()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return@AsyncFunction true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
View(ExpoImageViewWrapper::class) {
|
|
52
|
+
Events(
|
|
53
|
+
"onLoadStart",
|
|
54
|
+
"onProgress",
|
|
55
|
+
"onError",
|
|
56
|
+
"onLoad"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
Prop("source") { view: ExpoImageViewWrapper, sources: List<SourceMap>? ->
|
|
60
|
+
view.sources = sources ?: emptyList()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
Prop("contentFit") { view: ExpoImageViewWrapper, contentFit: ContentFit? ->
|
|
64
|
+
view.contentFit = contentFit ?: ContentFit.Cover
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Prop("placeholderContentFit") { view: ExpoImageViewWrapper, placeholderContentFit: ContentFit? ->
|
|
68
|
+
view.placeholderContentFit = placeholderContentFit ?: ContentFit.ScaleDown
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
Prop("contentPosition") { view: ExpoImageViewWrapper, contentPosition: ContentPosition? ->
|
|
72
|
+
view.contentPosition = contentPosition ?: ContentPosition.center
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
Prop("blurRadius") { view: ExpoImageViewWrapper, blurRadius: Int? ->
|
|
76
|
+
view.blurRadius = blurRadius?.takeIf { it > 0 }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
Prop("transition") { view: ExpoImageViewWrapper, transition: ImageTransition? ->
|
|
80
|
+
view.transition = transition
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
PropGroup(
|
|
84
|
+
ViewProps.BORDER_RADIUS to 0,
|
|
85
|
+
ViewProps.BORDER_TOP_LEFT_RADIUS to 1,
|
|
86
|
+
ViewProps.BORDER_TOP_RIGHT_RADIUS to 2,
|
|
87
|
+
ViewProps.BORDER_BOTTOM_RIGHT_RADIUS to 3,
|
|
88
|
+
ViewProps.BORDER_BOTTOM_LEFT_RADIUS to 4,
|
|
89
|
+
ViewProps.BORDER_TOP_START_RADIUS to 5,
|
|
90
|
+
ViewProps.BORDER_TOP_END_RADIUS to 6,
|
|
91
|
+
ViewProps.BORDER_BOTTOM_START_RADIUS to 7,
|
|
92
|
+
ViewProps.BORDER_BOTTOM_END_RADIUS to 8
|
|
93
|
+
) { view: ExpoImageViewWrapper, index: Int, borderRadius: Float? ->
|
|
94
|
+
val radius = makeYogaUndefinedIfNegative(borderRadius ?: YogaConstants.UNDEFINED)
|
|
95
|
+
view.setBorderRadius(index, radius)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
PropGroup(
|
|
99
|
+
ViewProps.BORDER_WIDTH to Spacing.ALL,
|
|
100
|
+
ViewProps.BORDER_LEFT_WIDTH to Spacing.LEFT,
|
|
101
|
+
ViewProps.BORDER_RIGHT_WIDTH to Spacing.RIGHT,
|
|
102
|
+
ViewProps.BORDER_TOP_WIDTH to Spacing.TOP,
|
|
103
|
+
ViewProps.BORDER_BOTTOM_WIDTH to Spacing.BOTTOM,
|
|
104
|
+
ViewProps.BORDER_START_WIDTH to Spacing.START,
|
|
105
|
+
ViewProps.BORDER_END_WIDTH to Spacing.END
|
|
106
|
+
) { view: ExpoImageViewWrapper, index: Int, width: Float? ->
|
|
107
|
+
val pixelWidth = makeYogaUndefinedIfNegative(width ?: YogaConstants.UNDEFINED)
|
|
108
|
+
.ifYogaDefinedUse(PixelUtil::toPixelFromDIP)
|
|
109
|
+
view.setBorderWidth(index, pixelWidth)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
PropGroup(
|
|
113
|
+
ViewProps.BORDER_COLOR to Spacing.ALL,
|
|
114
|
+
ViewProps.BORDER_LEFT_COLOR to Spacing.LEFT,
|
|
115
|
+
ViewProps.BORDER_RIGHT_COLOR to Spacing.RIGHT,
|
|
116
|
+
ViewProps.BORDER_TOP_COLOR to Spacing.TOP,
|
|
117
|
+
ViewProps.BORDER_BOTTOM_COLOR to Spacing.BOTTOM,
|
|
118
|
+
ViewProps.BORDER_START_COLOR to Spacing.START,
|
|
119
|
+
ViewProps.BORDER_END_COLOR to Spacing.END
|
|
120
|
+
) { view: ExpoImageViewWrapper, index: Int, color: Int? ->
|
|
121
|
+
val rgbComponent = if (color == null) YogaConstants.UNDEFINED else (color and 0x00FFFFFF).toFloat()
|
|
122
|
+
val alphaComponent = if (color == null) YogaConstants.UNDEFINED else (color ushr 24).toFloat()
|
|
123
|
+
view.setBorderColor(index, rgbComponent, alphaComponent)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
Prop("borderStyle") { view: ExpoImageViewWrapper, borderStyle: String? ->
|
|
127
|
+
view.borderStyle = borderStyle
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
Prop("backgroundColor") { view: ExpoImageViewWrapper, color: Int? ->
|
|
131
|
+
view.backgroundColor = color
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
Prop("tintColor") { view: ExpoImageViewWrapper, color: Int? ->
|
|
135
|
+
view.tintColor = color
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
Prop("placeholder") { view: ExpoImageViewWrapper, placeholder: List<SourceMap>? ->
|
|
139
|
+
view.placeholders = placeholder ?: emptyList()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
Prop("accessible") { view: ExpoImageViewWrapper, accessible: Boolean? ->
|
|
143
|
+
view.accessible = accessible ?: false
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
Prop("accessibilityLabel") { view: ExpoImageViewWrapper, accessibilityLabel: String? ->
|
|
147
|
+
view.accessibilityLabel = accessibilityLabel
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
Prop("focusable") { view: ExpoImageViewWrapper, isFocusable: Boolean? ->
|
|
151
|
+
view.isFocusableProp = isFocusable ?: false
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
Prop("priority") { view: ExpoImageViewWrapper, priority: Priority? ->
|
|
155
|
+
view.priority = priority ?: Priority.NORMAL
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
Prop("cachePolicy") { view: ExpoImageViewWrapper, cachePolicy: CachePolicy? ->
|
|
159
|
+
view.cachePolicy = cachePolicy ?: CachePolicy.DISK
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
Prop("recyclingKey") { view: ExpoImageViewWrapper, recyclingKey: String? ->
|
|
163
|
+
view.recyclingKey = recyclingKey
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
Prop("allowDownscaling") { view: ExpoImageViewWrapper, allowDownscaling: Boolean? ->
|
|
167
|
+
view.allowDownscaling = allowDownscaling ?: true
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
OnViewDidUpdateProps { view: ExpoImageViewWrapper ->
|
|
171
|
+
view.rerenderIfNeeded()
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
OnViewDestroys { view: ExpoImageViewWrapper ->
|
|
175
|
+
view.doOnDetach {
|
|
176
|
+
view.onViewDestroys()
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// TODO(@lukmccall): Remove when the same functionality will be defined by the expo-modules-core in SDK 48
|
|
184
|
+
@Suppress("FunctionName")
|
|
185
|
+
private inline fun <reified T : View, reified PropType, reified CustomValueType> ViewDefinitionBuilder<T>.PropGroup(
|
|
186
|
+
vararg props: Pair<String, CustomValueType>,
|
|
187
|
+
noinline body: (view: T, value: CustomValueType, prop: PropType) -> Unit
|
|
188
|
+
) {
|
|
189
|
+
for ((name, value) in props) {
|
|
190
|
+
Prop<T, PropType>(name) { view, prop -> body(view, value, prop) }
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
package expo.modules.image
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.graphics.Canvas
|
|
6
|
+
import android.graphics.Color
|
|
7
|
+
import android.graphics.PorterDuff
|
|
8
|
+
import android.graphics.RectF
|
|
9
|
+
import android.graphics.drawable.BitmapDrawable
|
|
10
|
+
import android.graphics.drawable.Drawable
|
|
11
|
+
import android.util.Log
|
|
12
|
+
import androidx.appcompat.widget.AppCompatImageView
|
|
13
|
+
import androidx.core.graphics.transform
|
|
14
|
+
import androidx.core.view.isVisible
|
|
15
|
+
import com.facebook.react.modules.i18nmanager.I18nUtil
|
|
16
|
+
import com.facebook.react.uimanager.PixelUtil
|
|
17
|
+
import com.facebook.react.views.view.ReactViewBackgroundDrawable
|
|
18
|
+
import expo.modules.image.drawing.OutlineProvider
|
|
19
|
+
import expo.modules.image.enums.ContentFit
|
|
20
|
+
import expo.modules.image.records.ContentPosition
|
|
21
|
+
|
|
22
|
+
@SuppressLint("ViewConstructor")
|
|
23
|
+
class ExpoImageView(
|
|
24
|
+
context: Context
|
|
25
|
+
) : AppCompatImageView(context) {
|
|
26
|
+
var currentTarget: ImageViewWrapperTarget? = null
|
|
27
|
+
var isPlaceholder: Boolean = false
|
|
28
|
+
|
|
29
|
+
fun recycleView(): ImageViewWrapperTarget? {
|
|
30
|
+
setImageDrawable(null)
|
|
31
|
+
|
|
32
|
+
val target = currentTarget?.apply {
|
|
33
|
+
isUsed = false
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
currentTarget = null
|
|
37
|
+
isVisible = false
|
|
38
|
+
isPlaceholder = false
|
|
39
|
+
|
|
40
|
+
return target
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private val outlineProvider = OutlineProvider(context)
|
|
44
|
+
|
|
45
|
+
private var transformationMatrixChanged = false
|
|
46
|
+
|
|
47
|
+
private val borderDrawableLazyHolder = lazy {
|
|
48
|
+
ReactViewBackgroundDrawable(context).apply {
|
|
49
|
+
callback = this@ExpoImageView
|
|
50
|
+
|
|
51
|
+
outlineProvider.borderRadiiConfig
|
|
52
|
+
.map { it.ifYogaDefinedUse(PixelUtil::toPixelFromDIP) }
|
|
53
|
+
.withIndex()
|
|
54
|
+
.forEach { (i, radius) ->
|
|
55
|
+
if (i == 0) {
|
|
56
|
+
setRadius(radius)
|
|
57
|
+
} else {
|
|
58
|
+
setRadius(radius, i - 1)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
65
|
+
super.onLayout(changed, left, top, right, bottom)
|
|
66
|
+
applyTransformationMatrix()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fun applyTransformationMatrix() {
|
|
70
|
+
if (drawable == null) {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (isPlaceholder) {
|
|
75
|
+
applyTransformationMatrix(drawable, placeholderContentFit)
|
|
76
|
+
} else {
|
|
77
|
+
applyTransformationMatrix(drawable, contentFit, contentPosition)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private fun applyTransformationMatrix(
|
|
82
|
+
drawable: Drawable,
|
|
83
|
+
contentFit: ContentFit,
|
|
84
|
+
contentPosition: ContentPosition = ContentPosition.center
|
|
85
|
+
) {
|
|
86
|
+
val imageRect = RectF(0f, 0f, drawable.intrinsicWidth.toFloat(), drawable.intrinsicHeight.toFloat())
|
|
87
|
+
val viewRect = RectF(0f, 0f, width.toFloat(), height.toFloat())
|
|
88
|
+
|
|
89
|
+
val matrix = contentFit.toMatrix(
|
|
90
|
+
imageRect,
|
|
91
|
+
viewRect,
|
|
92
|
+
currentTarget?.sourceWidth ?: -1,
|
|
93
|
+
currentTarget?.sourceHeight ?: -1
|
|
94
|
+
)
|
|
95
|
+
val scaledImageRect = imageRect.transform(matrix)
|
|
96
|
+
|
|
97
|
+
imageMatrix = matrix.apply {
|
|
98
|
+
contentPosition.apply(this, scaledImageRect, viewRect)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private val borderDrawable
|
|
103
|
+
get() = borderDrawableLazyHolder.value
|
|
104
|
+
|
|
105
|
+
init {
|
|
106
|
+
clipToOutline = true
|
|
107
|
+
scaleType = ScaleType.MATRIX
|
|
108
|
+
super.setOutlineProvider(outlineProvider)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// region Component Props
|
|
112
|
+
internal var contentFit: ContentFit = ContentFit.Cover
|
|
113
|
+
set(value) {
|
|
114
|
+
field = value
|
|
115
|
+
transformationMatrixChanged = true
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
internal var placeholderContentFit: ContentFit = ContentFit.ScaleDown
|
|
119
|
+
set(value) {
|
|
120
|
+
field = value
|
|
121
|
+
transformationMatrixChanged = true
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
internal var contentPosition: ContentPosition = ContentPosition.center
|
|
125
|
+
set(value) {
|
|
126
|
+
field = value
|
|
127
|
+
transformationMatrixChanged = true
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
internal fun setBorderRadius(position: Int, borderRadius: Float) {
|
|
131
|
+
val isInvalidated = outlineProvider.setBorderRadius(borderRadius, position)
|
|
132
|
+
if (isInvalidated) {
|
|
133
|
+
invalidateOutline()
|
|
134
|
+
if (!outlineProvider.hasEqualCorners()) {
|
|
135
|
+
invalidate()
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Setting the border-radius doesn't necessarily mean that a border
|
|
140
|
+
// should to be drawn. Only update the border-drawable when needed.
|
|
141
|
+
if (borderDrawableLazyHolder.isInitialized()) {
|
|
142
|
+
val radius = borderRadius.ifYogaDefinedUse(PixelUtil::toPixelFromDIP)
|
|
143
|
+
borderDrawableLazyHolder.value.apply {
|
|
144
|
+
if (position == 0) {
|
|
145
|
+
setRadius(radius)
|
|
146
|
+
} else {
|
|
147
|
+
setRadius(radius, position - 1)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
internal fun setBorderWidth(position: Int, width: Float) {
|
|
154
|
+
borderDrawable.setBorderWidth(position, width)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
internal fun setBorderColor(position: Int, rgb: Float, alpha: Float) {
|
|
158
|
+
borderDrawable.setBorderColor(position, rgb, alpha)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
internal fun setBorderStyle(style: String?) {
|
|
162
|
+
borderDrawable.setBorderStyle(style)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
internal fun setBackgroundColor(color: Int?) {
|
|
166
|
+
if (color == null) {
|
|
167
|
+
setBackgroundColor(Color.TRANSPARENT)
|
|
168
|
+
} else {
|
|
169
|
+
setBackgroundColor(color)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
internal fun setTintColor(color: Int?) {
|
|
174
|
+
color?.let { setColorFilter(it, PorterDuff.Mode.SRC_IN) } ?: clearColorFilter()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
override fun invalidateDrawable(drawable: Drawable) {
|
|
178
|
+
super.invalidateDrawable(drawable)
|
|
179
|
+
if (borderDrawableLazyHolder.isInitialized() && drawable === borderDrawable) {
|
|
180
|
+
invalidate()
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
override fun draw(canvas: Canvas) {
|
|
185
|
+
// When the border-radii are not all the same, a convex-path
|
|
186
|
+
// is used for the Outline. Unfortunately clipping is not supported
|
|
187
|
+
// for convex-paths and we fallback to Canvas clipping.
|
|
188
|
+
outlineProvider.clipCanvasIfNeeded(canvas, this)
|
|
189
|
+
// If we encounter a recycled bitmap here, it suggests an issue where we may have failed to
|
|
190
|
+
// finish clearing the image bitmap before the UI attempts to display it.
|
|
191
|
+
// One solution could be to suppress the error and assume that the second image view is currently responsible for displaying the correct view.
|
|
192
|
+
if ((drawable as? BitmapDrawable)?.bitmap?.isRecycled == true) {
|
|
193
|
+
Log.e("ExpoImage", "Trying to use a recycled bitmap")
|
|
194
|
+
recycleView()?.let { target ->
|
|
195
|
+
(parent as? ExpoImageViewWrapper)?.requestManager?.let { requestManager ->
|
|
196
|
+
target.clear(requestManager)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
super.draw(canvas)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
public override fun onDraw(canvas: Canvas) {
|
|
204
|
+
super.onDraw(canvas)
|
|
205
|
+
// Draw borders on top of the background and image
|
|
206
|
+
if (borderDrawableLazyHolder.isInitialized()) {
|
|
207
|
+
val layoutDirection = if (I18nUtil.getInstance().isRTL(context)) {
|
|
208
|
+
LAYOUT_DIRECTION_RTL
|
|
209
|
+
} else {
|
|
210
|
+
LAYOUT_DIRECTION_LTR
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
borderDrawable.apply {
|
|
214
|
+
resolvedLayoutDirection = layoutDirection
|
|
215
|
+
setBounds(0, 0, width, height)
|
|
216
|
+
draw(canvas)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|