@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.
Files changed (289) hide show
  1. package/.eslintrc.js +2 -0
  2. package/CHANGELOG.md +285 -0
  3. package/CMakeLists.txt +91 -0
  4. package/LICENSE +7 -0
  5. package/README.kepler.md +123 -0
  6. package/README.md +54 -0
  7. package/THIRD_PARTY_NOTICES.txt +24 -0
  8. package/android/build.gradle +124 -0
  9. package/android/proguard-rules.pro +28 -0
  10. package/android/src/main/AndroidManifest.xml +15 -0
  11. package/android/src/main/java/expo/modules/image/Exceptions.kt +9 -0
  12. package/android/src/main/java/expo/modules/image/ExpoImageAppGlideModule.kt +19 -0
  13. package/android/src/main/java/expo/modules/image/ExpoImageModule.kt +192 -0
  14. package/android/src/main/java/expo/modules/image/ExpoImageView.kt +220 -0
  15. package/android/src/main/java/expo/modules/image/ExpoImageViewWrapper.kt +652 -0
  16. package/android/src/main/java/expo/modules/image/GlideModel.kt +73 -0
  17. package/android/src/main/java/expo/modules/image/ImageUtils.kt +50 -0
  18. package/android/src/main/java/expo/modules/image/ImageViewWrapperTarget.kt +313 -0
  19. package/android/src/main/java/expo/modules/image/ResourceIdHelper.kt +47 -0
  20. package/android/src/main/java/expo/modules/image/ThumbnailRequestCoordinatorExtension.kt +21 -0
  21. package/android/src/main/java/expo/modules/image/YogaUtils.kt +20 -0
  22. package/android/src/main/java/expo/modules/image/blurhash/BlurHashFetcher.kt +32 -0
  23. package/android/src/main/java/expo/modules/image/blurhash/BlurhashDecoder.kt +189 -0
  24. package/android/src/main/java/expo/modules/image/blurhash/BlurhashModelLoader.kt +30 -0
  25. package/android/src/main/java/expo/modules/image/blurhash/BlurhashModelLoaderFactory.kt +14 -0
  26. package/android/src/main/java/expo/modules/image/blurhash/BlurhashModule.kt +17 -0
  27. package/android/src/main/java/expo/modules/image/dataurls/Base64DataFetcher.kt +27 -0
  28. package/android/src/main/java/expo/modules/image/dataurls/Base64ModelLoader.kt +24 -0
  29. package/android/src/main/java/expo/modules/image/dataurls/Base64ModelLoaderFactory.kt +12 -0
  30. package/android/src/main/java/expo/modules/image/dataurls/Base64Module.kt +16 -0
  31. package/android/src/main/java/expo/modules/image/drawing/OutlineProvider.kt +201 -0
  32. package/android/src/main/java/expo/modules/image/enums/ContentFit.kt +89 -0
  33. package/android/src/main/java/expo/modules/image/enums/ImageCacheType.kt +14 -0
  34. package/android/src/main/java/expo/modules/image/enums/Priority.kt +15 -0
  35. package/android/src/main/java/expo/modules/image/events/GlideRequestListener.kt +64 -0
  36. package/android/src/main/java/expo/modules/image/events/OkHttpProgressListener.kt +26 -0
  37. package/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt +80 -0
  38. package/android/src/main/java/expo/modules/image/okhttp/GlideUrlWrapperLoader.kt +55 -0
  39. package/android/src/main/java/expo/modules/image/records/CachePolicy.kt +10 -0
  40. package/android/src/main/java/expo/modules/image/records/ContentPosition.kt +89 -0
  41. package/android/src/main/java/expo/modules/image/records/ImageTransition.kt +8 -0
  42. package/android/src/main/java/expo/modules/image/records/SourceMap.kt +160 -0
  43. package/android/src/main/java/expo/modules/image/records/events.kt +25 -0
  44. package/android/src/main/java/expo/modules/image/svg/SVGDecoder.kt +33 -0
  45. package/android/src/main/java/expo/modules/image/svg/SVGDrawableTranscoder.kt +37 -0
  46. package/android/src/main/java/expo/modules/image/svg/SVGModule.kt +26 -0
  47. package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashDecoder.kt +365 -0
  48. package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashFetcher.kt +31 -0
  49. package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModelLoader.kt +26 -0
  50. package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModelLoaderFactory.kt +14 -0
  51. package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModule.kt +17 -0
  52. package/build/ExpoImage.d.ts +15 -0
  53. package/build/ExpoImage.d.ts.map +1 -0
  54. package/build/ExpoImage.js +75 -0
  55. package/build/ExpoImage.js.map +1 -0
  56. package/build/ExpoImage.kepler.d.ts +23 -0
  57. package/build/ExpoImage.kepler.d.ts.map +1 -0
  58. package/build/ExpoImage.kepler.js +71 -0
  59. package/build/ExpoImage.kepler.js.map +1 -0
  60. package/build/ExpoImage.web.d.ts +9 -0
  61. package/build/ExpoImage.web.d.ts.map +1 -0
  62. package/build/ExpoImage.web.js +90 -0
  63. package/build/ExpoImage.web.js.map +1 -0
  64. package/build/ExpoImageModules.d.ts +3 -0
  65. package/build/ExpoImageModules.d.ts.map +1 -0
  66. package/build/ExpoImageModules.js +4 -0
  67. package/build/ExpoImageModules.js.map +1 -0
  68. package/build/ExpoImageModules.kepler.d.ts +6 -0
  69. package/build/ExpoImageModules.kepler.d.ts.map +1 -0
  70. package/build/ExpoImageModules.kepler.js +5 -0
  71. package/build/ExpoImageModules.kepler.js.map +1 -0
  72. package/build/Image.d.ts +30 -0
  73. package/build/Image.d.ts.map +1 -0
  74. package/build/Image.js +49 -0
  75. package/build/Image.js.map +1 -0
  76. package/build/Image.types.d.ts +374 -0
  77. package/build/Image.types.d.ts.map +1 -0
  78. package/build/Image.types.js +2 -0
  79. package/build/Image.types.js.map +1 -0
  80. package/build/ImageBackground.d.ts +6 -0
  81. package/build/ImageBackground.d.ts.map +1 -0
  82. package/build/ImageBackground.js +13 -0
  83. package/build/ImageBackground.js.map +1 -0
  84. package/build/ImageViewNativeComponent.d.ts +20 -0
  85. package/build/ImageViewNativeComponent.d.ts.map +1 -0
  86. package/build/ImageViewNativeComponent.js +42 -0
  87. package/build/ImageViewNativeComponent.js.map +1 -0
  88. package/build/NativeImageLoaderKepler.d.ts +18 -0
  89. package/build/NativeImageLoaderKepler.d.ts.map +1 -0
  90. package/build/NativeImageLoaderKepler.js +3 -0
  91. package/build/NativeImageLoaderKepler.js.map +1 -0
  92. package/build/fabric/registerNativeComponent.d.ts +15 -0
  93. package/build/fabric/registerNativeComponent.d.ts.map +1 -0
  94. package/build/fabric/registerNativeComponent.js +47 -0
  95. package/build/fabric/registerNativeComponent.js.map +1 -0
  96. package/build/index.d.ts +4 -0
  97. package/build/index.d.ts.map +1 -0
  98. package/build/index.js +4 -0
  99. package/build/index.js.map +1 -0
  100. package/build/utils/AssetSourceResolver.web.d.ts +24 -0
  101. package/build/utils/AssetSourceResolver.web.d.ts.map +1 -0
  102. package/build/utils/AssetSourceResolver.web.js +67 -0
  103. package/build/utils/AssetSourceResolver.web.js.map +1 -0
  104. package/build/utils/blurhash/base83.d.ts +3 -0
  105. package/build/utils/blurhash/base83.d.ts.map +1 -0
  106. package/build/utils/blurhash/base83.js +103 -0
  107. package/build/utils/blurhash/base83.js.map +1 -0
  108. package/build/utils/blurhash/decode.d.ts +7 -0
  109. package/build/utils/blurhash/decode.d.ts.map +1 -0
  110. package/build/utils/blurhash/decode.js +92 -0
  111. package/build/utils/blurhash/decode.js.map +1 -0
  112. package/build/utils/blurhash/error.d.ts +4 -0
  113. package/build/utils/blurhash/error.d.ts.map +1 -0
  114. package/build/utils/blurhash/error.js +8 -0
  115. package/build/utils/blurhash/error.js.map +1 -0
  116. package/build/utils/blurhash/useBlurhash.d.ts +8 -0
  117. package/build/utils/blurhash/useBlurhash.d.ts.map +1 -0
  118. package/build/utils/blurhash/useBlurhash.js +64 -0
  119. package/build/utils/blurhash/useBlurhash.js.map +1 -0
  120. package/build/utils/blurhash/utils.d.ts +5 -0
  121. package/build/utils/blurhash/utils.d.ts.map +1 -0
  122. package/build/utils/blurhash/utils.js +21 -0
  123. package/build/utils/blurhash/utils.js.map +1 -0
  124. package/build/utils/resolveAssetSource.d.ts +3 -0
  125. package/build/utils/resolveAssetSource.d.ts.map +1 -0
  126. package/build/utils/resolveAssetSource.js +3 -0
  127. package/build/utils/resolveAssetSource.js.map +1 -0
  128. package/build/utils/resolveAssetSource.web.d.ts +9 -0
  129. package/build/utils/resolveAssetSource.web.d.ts.map +1 -0
  130. package/build/utils/resolveAssetSource.web.js +31 -0
  131. package/build/utils/resolveAssetSource.web.js.map +1 -0
  132. package/build/utils/resolveHashString.d.ts +14 -0
  133. package/build/utils/resolveHashString.d.ts.map +1 -0
  134. package/build/utils/resolveHashString.js +31 -0
  135. package/build/utils/resolveHashString.js.map +1 -0
  136. package/build/utils/resolveHashString.web.d.ts +20 -0
  137. package/build/utils/resolveHashString.web.d.ts.map +1 -0
  138. package/build/utils/resolveHashString.web.js +31 -0
  139. package/build/utils/resolveHashString.web.js.map +1 -0
  140. package/build/utils/resolveSources.d.ts +8 -0
  141. package/build/utils/resolveSources.d.ts.map +1 -0
  142. package/build/utils/resolveSources.js +45 -0
  143. package/build/utils/resolveSources.js.map +1 -0
  144. package/build/utils/thumbhash/thumbhash.d.ts +66 -0
  145. package/build/utils/thumbhash/thumbhash.d.ts.map +1 -0
  146. package/build/utils/thumbhash/thumbhash.js +338 -0
  147. package/build/utils/thumbhash/thumbhash.js.map +1 -0
  148. package/build/utils.d.ts +17 -0
  149. package/build/utils.d.ts.map +1 -0
  150. package/build/utils.js +85 -0
  151. package/build/utils.js.map +1 -0
  152. package/build/web/AnimationManager.d.ts +37 -0
  153. package/build/web/AnimationManager.d.ts.map +1 -0
  154. package/build/web/AnimationManager.js +155 -0
  155. package/build/web/AnimationManager.js.map +1 -0
  156. package/build/web/ColorTintFilter.d.ts +12 -0
  157. package/build/web/ColorTintFilter.d.ts.map +1 -0
  158. package/build/web/ColorTintFilter.js +30 -0
  159. package/build/web/ColorTintFilter.js.map +1 -0
  160. package/build/web/ImageWrapper.d.ts +5 -0
  161. package/build/web/ImageWrapper.d.ts.map +1 -0
  162. package/build/web/ImageWrapper.js +44 -0
  163. package/build/web/ImageWrapper.js.map +1 -0
  164. package/build/web/ImageWrapper.types.d.ts +29 -0
  165. package/build/web/ImageWrapper.types.d.ts.map +1 -0
  166. package/build/web/ImageWrapper.types.js +2 -0
  167. package/build/web/ImageWrapper.types.js.map +1 -0
  168. package/build/web/getImageWrapperEventHandler.d.ts +8 -0
  169. package/build/web/getImageWrapperEventHandler.d.ts.map +1 -0
  170. package/build/web/getImageWrapperEventHandler.js +25 -0
  171. package/build/web/getImageWrapperEventHandler.js.map +1 -0
  172. package/build/web/hooks.d.ts +13 -0
  173. package/build/web/hooks.d.ts.map +1 -0
  174. package/build/web/hooks.js +58 -0
  175. package/build/web/hooks.js.map +1 -0
  176. package/build/web/imageStyles.d.ts +2 -0
  177. package/build/web/imageStyles.d.ts.map +1 -0
  178. package/build/web/imageStyles.js +137 -0
  179. package/build/web/imageStyles.js.map +1 -0
  180. package/build/web/positioning.d.ts +11 -0
  181. package/build/web/positioning.d.ts.map +1 -0
  182. package/build/web/positioning.js +35 -0
  183. package/build/web/positioning.js.map +1 -0
  184. package/build/web/useSourceSelection.d.ts +14 -0
  185. package/build/web/useSourceSelection.d.ts.map +1 -0
  186. package/build/web/useSourceSelection.js +98 -0
  187. package/build/web/useSourceSelection.js.map +1 -0
  188. package/expo-module.config.json +9 -0
  189. package/ios/Blurhash.swift +326 -0
  190. package/ios/BlurhashLoader.swift +52 -0
  191. package/ios/ContentFit.swift +55 -0
  192. package/ios/ContentPosition.swift +108 -0
  193. package/ios/ExpoImage.podspec +30 -0
  194. package/ios/ImageCachePolicy.swift +24 -0
  195. package/ios/ImageCacheType.swift +21 -0
  196. package/ios/ImageModule.swift +127 -0
  197. package/ios/ImagePriority.swift +22 -0
  198. package/ios/ImageSource.swift +44 -0
  199. package/ios/ImageTransition.swift +67 -0
  200. package/ios/ImageUtils.swift +227 -0
  201. package/ios/ImageView.swift +469 -0
  202. package/ios/Loaders/PhotoLibraryAssetLoader.swift +146 -0
  203. package/ios/Thumbhash.swift +550 -0
  204. package/ios/ThumbhashLoader.swift +53 -0
  205. package/jest.config.js +3 -0
  206. package/kepler/ExpoImage.cpp +63 -0
  207. package/kepler/ExpoImage.h +29 -0
  208. package/kepler/ExpoImageCacheHandler.cpp +15 -0
  209. package/kepler/ExpoImageCacheHandler.h +28 -0
  210. package/kepler/ExpoImageComponent.cpp +579 -0
  211. package/kepler/ExpoImageComponent.h +199 -0
  212. package/kepler/ImageWrapper/BlurhashImageWrapper.cpp +37 -0
  213. package/kepler/ImageWrapper/BlurhashImageWrapper.h +23 -0
  214. package/kepler/ImageWrapper/CacheImageWrapper.cpp +80 -0
  215. package/kepler/ImageWrapper/CacheImageWrapper.h +41 -0
  216. package/kepler/ImageWrapper/HashImageWrapper.cpp +21 -0
  217. package/kepler/ImageWrapper/HashImageWrapper.h +22 -0
  218. package/kepler/ImageWrapper/ImageWrapper.cpp +24 -0
  219. package/kepler/ImageWrapper/ImageWrapper.h +33 -0
  220. package/kepler/ImageWrapper/LocalImageWrapper.cpp +61 -0
  221. package/kepler/ImageWrapper/LocalImageWrapper.h +30 -0
  222. package/kepler/ImageWrapper/ThumbhashImageWrapper.cpp +33 -0
  223. package/kepler/ImageWrapper/ThumbhashImageWrapper.h +20 -0
  224. package/kepler/KeplerImageViewComponent.h +64 -0
  225. package/kepler/KeplerInit.cpp +35 -0
  226. package/kepler/blurhash/common.h +32 -0
  227. package/kepler/blurhash/decode.cpp +187 -0
  228. package/kepler/blurhash/decode.h +58 -0
  229. package/kepler/contentposition/ImageContentPosition.cpp +86 -0
  230. package/kepler/contentposition/ImageContentPosition.h +48 -0
  231. package/kepler/enums/ImageContentFit.h +17 -0
  232. package/kepler/enums/ImagePriority.h +17 -0
  233. package/kepler/managers/ExpoImageManager.cpp +38 -0
  234. package/kepler/managers/ExpoImageManager.h +23 -0
  235. package/kepler/test/ExpoImage.cpp +73 -0
  236. package/kepler/test/ExpoImageComponent.cpp +290 -0
  237. package/kepler/test/blurhash/decode.cpp +39 -0
  238. package/kepler/test/contentposition/ImageContentPosition.cpp +100 -0
  239. package/kepler/test/managers/ExpoImageManager.cpp +39 -0
  240. package/kepler/test/thumbhash/decode.cpp +18 -0
  241. package/kepler/test/utils/LoaderDelegate.cpp +130 -0
  242. package/kepler/thumbhash/decode.cpp +166 -0
  243. package/kepler/thumbhash/decode.h +22 -0
  244. package/kepler/utils/PlaceholderImageLoaderDelegate.cpp +26 -0
  245. package/kepler/utils/PlaceholderImageLoaderDelegate.h +26 -0
  246. package/kepler/utils/PrefetchImageLoaderDelegate.cpp +55 -0
  247. package/kepler/utils/PrefetchImageLoaderDelegate.h +35 -0
  248. package/kepler/utils/SourceImageLoaderDelegate.cpp +47 -0
  249. package/kepler/utils/SourceImageLoaderDelegate.h +42 -0
  250. package/kepler/utils/SourceImageLoaderDelegateEmitter.cpp +15 -0
  251. package/kepler/utils/SourceImageLoaderDelegateEmitter.h +28 -0
  252. package/kepler-compatibility.json +8 -0
  253. package/package.json +1 -0
  254. package/react-native.config.js +22 -0
  255. package/src/ExpoImage.kepler.tsx +119 -0
  256. package/src/ExpoImage.tsx +119 -0
  257. package/src/ExpoImage.web.tsx +155 -0
  258. package/src/ExpoImageModules.kepler.ts +7 -0
  259. package/src/ExpoImageModules.ts +4 -0
  260. package/src/Image.tsx +82 -0
  261. package/src/Image.types.ts +450 -0
  262. package/src/ImageBackground.tsx +18 -0
  263. package/src/ImageViewNativeComponent.ts +59 -0
  264. package/src/NativeImageLoaderKepler.ts +22 -0
  265. package/src/fabric/registerNativeComponent.ts +70 -0
  266. package/src/index.ts +3 -0
  267. package/src/utils/AssetSourceResolver.web.ts +88 -0
  268. package/src/utils/blurhash/base83.ts +104 -0
  269. package/src/utils/blurhash/decode.ts +114 -0
  270. package/src/utils/blurhash/error.ts +7 -0
  271. package/src/utils/blurhash/useBlurhash.tsx +81 -0
  272. package/src/utils/blurhash/utils.ts +21 -0
  273. package/src/utils/resolveAssetSource.tsx +3 -0
  274. package/src/utils/resolveAssetSource.web.ts +40 -0
  275. package/src/utils/resolveHashString.tsx +36 -0
  276. package/src/utils/resolveHashString.web.tsx +33 -0
  277. package/src/utils/resolveSources.tsx +48 -0
  278. package/src/utils/thumbhash/thumbhash.ts +387 -0
  279. package/src/utils.ts +109 -0
  280. package/src/web/AnimationManager.tsx +224 -0
  281. package/src/web/ColorTintFilter.tsx +36 -0
  282. package/src/web/ImageWrapper.tsx +85 -0
  283. package/src/web/ImageWrapper.types.ts +36 -0
  284. package/src/web/getImageWrapperEventHandler.ts +29 -0
  285. package/src/web/hooks.ts +72 -0
  286. package/src/web/imageStyles.tsx +136 -0
  287. package/src/web/positioning.ts +48 -0
  288. package/src/web/useSourceSelection.ts +151 -0
  289. 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
+ }