@onekeyfe/react-native-image 3.0.98

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 (186) hide show
  1. package/LICENSE +21 -0
  2. package/OneKeyImage.podspec +32 -0
  3. package/README.md +88 -0
  4. package/android/CMakeLists.txt +12 -0
  5. package/android/build.gradle +85 -0
  6. package/android/consumer-rules.pro +10 -0
  7. package/android/gradle.properties +5 -0
  8. package/android/src/main/AndroidManifest.xml +1 -0
  9. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  10. package/android/src/main/java/com/margelo/nitro/onekeyimage/OneKeyImage.kt +616 -0
  11. package/android/src/main/java/com/margelo/nitro/onekeyimage/OneKeyImageCache.kt +131 -0
  12. package/android/src/main/java/com/margelo/nitro/onekeyimage/OneKeyImageDecodeDimensions.kt +169 -0
  13. package/android/src/main/java/com/margelo/nitro/onekeyimage/OneKeyImageGlideRegistry.kt +285 -0
  14. package/android/src/main/java/com/margelo/nitro/onekeyimage/OneKeyImageModel.kt +68 -0
  15. package/android/src/main/java/com/margelo/nitro/onekeyimage/OneKeyImagePackage.kt +28 -0
  16. package/android/src/main/java/com/margelo/nitro/onekeyimage/OneKeyImageSafety.kt +1120 -0
  17. package/android/src/main/java/com/margelo/nitro/onekeyimage/OneKeyTosUrl.kt +93 -0
  18. package/android/src/test/java/com/margelo/nitro/onekeyimage/OneKeyAnimationTimelineInspectorTest.kt +210 -0
  19. package/android/src/test/java/com/margelo/nitro/onekeyimage/OneKeyImageCacheTypeTest.kt +16 -0
  20. package/android/src/test/java/com/margelo/nitro/onekeyimage/OneKeyImageDecodeDimensionsTest.kt +70 -0
  21. package/android/src/test/java/com/margelo/nitro/onekeyimage/OneKeyImageModelTest.kt +65 -0
  22. package/android/src/test/java/com/margelo/nitro/onekeyimage/OneKeyImageRequestSignatureTest.kt +33 -0
  23. package/android/src/test/java/com/margelo/nitro/onekeyimage/OneKeyImageSafetyTest.kt +346 -0
  24. package/android/src/test/java/com/margelo/nitro/onekeyimage/OneKeyResourceCleanupTest.kt +43 -0
  25. package/android/src/test/java/com/margelo/nitro/onekeyimage/OneKeyTerminalEventPairTest.kt +38 -0
  26. package/android/src/test/java/com/margelo/nitro/onekeyimage/OneKeyTosUrlTest.kt +82 -0
  27. package/ios/OneKeyImage.swift +636 -0
  28. package/ios/OneKeyImageCache.swift +215 -0
  29. package/ios/OneKeyImageRequestContext.swift +781 -0
  30. package/ios/OneKeyTosURL.swift +69 -0
  31. package/ios/tests/OneKeyImageInfrastructureTests.swift +555 -0
  32. package/ios/tests/OneKeyTosURLTests.swift +142 -0
  33. package/lib/module/OneKeyImage.nitro.js +30 -0
  34. package/lib/module/index.js +223 -0
  35. package/lib/module/package.json +1 -0
  36. package/lib/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
  37. package/lib/nitrogen/generated/android/c++/JFunc_void_double_double_OneKeyImageCacheType.hpp +77 -0
  38. package/lib/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
  39. package/lib/nitrogen/generated/android/c++/JHybridOneKeyImageCacheSpec.cpp +130 -0
  40. package/lib/nitrogen/generated/android/c++/JHybridOneKeyImageCacheSpec.hpp +66 -0
  41. package/lib/nitrogen/generated/android/c++/JHybridOneKeyImageSpec.cpp +255 -0
  42. package/lib/nitrogen/generated/android/c++/JHybridOneKeyImageSpec.hpp +93 -0
  43. package/lib/nitrogen/generated/android/c++/JOneKeyImageCachePolicy.hpp +64 -0
  44. package/lib/nitrogen/generated/android/c++/JOneKeyImageCacheType.hpp +61 -0
  45. package/lib/nitrogen/generated/android/c++/JOneKeyImageContentFit.hpp +64 -0
  46. package/lib/nitrogen/generated/android/c++/JOneKeyImageLoadingStrategy.hpp +61 -0
  47. package/lib/nitrogen/generated/android/c++/JOneKeyImagePreloadSource.hpp +88 -0
  48. package/lib/nitrogen/generated/android/c++/JOneKeyImageVariant.hpp +64 -0
  49. package/lib/nitrogen/generated/android/c++/views/JHybridOneKeyImageStateUpdater.cpp +144 -0
  50. package/lib/nitrogen/generated/android/c++/views/JHybridOneKeyImageStateUpdater.hpp +54 -0
  51. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/Func_void.kt +78 -0
  52. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/Func_void_double_double_OneKeyImageCacheType.kt +78 -0
  53. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/Func_void_std__string.kt +78 -0
  54. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/HybridOneKeyImageCacheSpec.kt +69 -0
  55. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/HybridOneKeyImageSpec.kt +189 -0
  56. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImageCachePolicy.kt +25 -0
  57. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImageCacheType.kt +24 -0
  58. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImageContentFit.kt +25 -0
  59. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImageLoadingStrategy.kt +24 -0
  60. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImagePreloadSource.kt +86 -0
  61. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImageVariant.kt +25 -0
  62. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/onekeyimageOnLoad.kt +35 -0
  63. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/views/HybridOneKeyImageManager.kt +96 -0
  64. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/views/HybridOneKeyImageStateUpdater.kt +23 -0
  65. package/lib/nitrogen/generated/android/onekeyimage+autolinking.cmake +85 -0
  66. package/lib/nitrogen/generated/android/onekeyimage+autolinking.gradle +27 -0
  67. package/lib/nitrogen/generated/android/onekeyimageOnLoad.cpp +78 -0
  68. package/lib/nitrogen/generated/android/onekeyimageOnLoad.hpp +34 -0
  69. package/lib/nitrogen/generated/ios/OneKeyImage+autolinking.rb +62 -0
  70. package/lib/nitrogen/generated/ios/OneKeyImage-Swift-Cxx-Bridge.cpp +90 -0
  71. package/lib/nitrogen/generated/ios/OneKeyImage-Swift-Cxx-Bridge.hpp +405 -0
  72. package/lib/nitrogen/generated/ios/OneKeyImage-Swift-Cxx-Umbrella.hpp +71 -0
  73. package/lib/nitrogen/generated/ios/OneKeyImageAutolinking.mm +41 -0
  74. package/lib/nitrogen/generated/ios/OneKeyImageAutolinking.swift +38 -0
  75. package/lib/nitrogen/generated/ios/c++/HybridOneKeyImageCacheSpecSwift.cpp +11 -0
  76. package/lib/nitrogen/generated/ios/c++/HybridOneKeyImageCacheSpecSwift.hpp +114 -0
  77. package/lib/nitrogen/generated/ios/c++/HybridOneKeyImageSpecSwift.cpp +11 -0
  78. package/lib/nitrogen/generated/ios/c++/HybridOneKeyImageSpecSwift.hpp +206 -0
  79. package/lib/nitrogen/generated/ios/c++/views/HybridOneKeyImageComponent.mm +228 -0
  80. package/lib/nitrogen/generated/ios/swift/Func_void.swift +46 -0
  81. package/lib/nitrogen/generated/ios/swift/Func_void_bool.swift +46 -0
  82. package/lib/nitrogen/generated/ios/swift/Func_void_double_double_OneKeyImageCacheType.swift +46 -0
  83. package/lib/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
  84. package/lib/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
  85. package/lib/nitrogen/generated/ios/swift/HybridOneKeyImageCacheSpec.swift +58 -0
  86. package/lib/nitrogen/generated/ios/swift/HybridOneKeyImageCacheSpec_cxx.swift +202 -0
  87. package/lib/nitrogen/generated/ios/swift/HybridOneKeyImageSpec.swift +70 -0
  88. package/lib/nitrogen/generated/ios/swift/HybridOneKeyImageSpec_cxx.swift +539 -0
  89. package/lib/nitrogen/generated/ios/swift/OneKeyImageCachePolicy.swift +48 -0
  90. package/lib/nitrogen/generated/ios/swift/OneKeyImageCacheType.swift +44 -0
  91. package/lib/nitrogen/generated/ios/swift/OneKeyImageContentFit.swift +48 -0
  92. package/lib/nitrogen/generated/ios/swift/OneKeyImageLoadingStrategy.swift +44 -0
  93. package/lib/nitrogen/generated/ios/swift/OneKeyImagePreloadSource.swift +148 -0
  94. package/lib/nitrogen/generated/ios/swift/OneKeyImageVariant.swift +48 -0
  95. package/lib/nitrogen/generated/shared/c++/HybridOneKeyImageCacheSpec.cpp +24 -0
  96. package/lib/nitrogen/generated/shared/c++/HybridOneKeyImageCacheSpec.hpp +68 -0
  97. package/lib/nitrogen/generated/shared/c++/HybridOneKeyImageSpec.cpp +52 -0
  98. package/lib/nitrogen/generated/shared/c++/HybridOneKeyImageSpec.hpp +108 -0
  99. package/lib/nitrogen/generated/shared/c++/OneKeyImageCachePolicy.hpp +84 -0
  100. package/lib/nitrogen/generated/shared/c++/OneKeyImageCacheType.hpp +80 -0
  101. package/lib/nitrogen/generated/shared/c++/OneKeyImageContentFit.hpp +84 -0
  102. package/lib/nitrogen/generated/shared/c++/OneKeyImageLoadingStrategy.hpp +80 -0
  103. package/lib/nitrogen/generated/shared/c++/OneKeyImagePreloadSource.hpp +114 -0
  104. package/lib/nitrogen/generated/shared/c++/OneKeyImageVariant.hpp +84 -0
  105. package/lib/nitrogen/generated/shared/c++/views/HybridOneKeyImageComponent.cpp +62 -0
  106. package/lib/nitrogen/generated/shared/c++/views/HybridOneKeyImageComponent.hpp +132 -0
  107. package/lib/nitrogen/generated/shared/json/OneKeyImageConfig.json +24 -0
  108. package/lib/typescript/package.json +1 -0
  109. package/lib/typescript/src/OneKeyImage.nitro.d.ts +67 -0
  110. package/lib/typescript/src/index.d.ts +55 -0
  111. package/nitro.json +31 -0
  112. package/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
  113. package/nitrogen/generated/android/c++/JFunc_void_double_double_OneKeyImageCacheType.hpp +77 -0
  114. package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
  115. package/nitrogen/generated/android/c++/JHybridOneKeyImageCacheSpec.cpp +130 -0
  116. package/nitrogen/generated/android/c++/JHybridOneKeyImageCacheSpec.hpp +66 -0
  117. package/nitrogen/generated/android/c++/JHybridOneKeyImageSpec.cpp +255 -0
  118. package/nitrogen/generated/android/c++/JHybridOneKeyImageSpec.hpp +93 -0
  119. package/nitrogen/generated/android/c++/JOneKeyImageCachePolicy.hpp +64 -0
  120. package/nitrogen/generated/android/c++/JOneKeyImageCacheType.hpp +61 -0
  121. package/nitrogen/generated/android/c++/JOneKeyImageContentFit.hpp +64 -0
  122. package/nitrogen/generated/android/c++/JOneKeyImageLoadingStrategy.hpp +61 -0
  123. package/nitrogen/generated/android/c++/JOneKeyImagePreloadSource.hpp +88 -0
  124. package/nitrogen/generated/android/c++/JOneKeyImageVariant.hpp +64 -0
  125. package/nitrogen/generated/android/c++/views/JHybridOneKeyImageStateUpdater.cpp +144 -0
  126. package/nitrogen/generated/android/c++/views/JHybridOneKeyImageStateUpdater.hpp +54 -0
  127. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/Func_void.kt +78 -0
  128. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/Func_void_double_double_OneKeyImageCacheType.kt +78 -0
  129. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/Func_void_std__string.kt +78 -0
  130. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/HybridOneKeyImageCacheSpec.kt +69 -0
  131. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/HybridOneKeyImageSpec.kt +189 -0
  132. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImageCachePolicy.kt +25 -0
  133. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImageCacheType.kt +24 -0
  134. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImageContentFit.kt +25 -0
  135. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImageLoadingStrategy.kt +24 -0
  136. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImagePreloadSource.kt +86 -0
  137. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/OneKeyImageVariant.kt +25 -0
  138. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/onekeyimageOnLoad.kt +35 -0
  139. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/views/HybridOneKeyImageManager.kt +96 -0
  140. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onekeyimage/views/HybridOneKeyImageStateUpdater.kt +23 -0
  141. package/nitrogen/generated/android/onekeyimage+autolinking.cmake +85 -0
  142. package/nitrogen/generated/android/onekeyimage+autolinking.gradle +27 -0
  143. package/nitrogen/generated/android/onekeyimageOnLoad.cpp +78 -0
  144. package/nitrogen/generated/android/onekeyimageOnLoad.hpp +34 -0
  145. package/nitrogen/generated/ios/OneKeyImage+autolinking.rb +62 -0
  146. package/nitrogen/generated/ios/OneKeyImage-Swift-Cxx-Bridge.cpp +90 -0
  147. package/nitrogen/generated/ios/OneKeyImage-Swift-Cxx-Bridge.hpp +405 -0
  148. package/nitrogen/generated/ios/OneKeyImage-Swift-Cxx-Umbrella.hpp +71 -0
  149. package/nitrogen/generated/ios/OneKeyImageAutolinking.mm +41 -0
  150. package/nitrogen/generated/ios/OneKeyImageAutolinking.swift +38 -0
  151. package/nitrogen/generated/ios/c++/HybridOneKeyImageCacheSpecSwift.cpp +11 -0
  152. package/nitrogen/generated/ios/c++/HybridOneKeyImageCacheSpecSwift.hpp +114 -0
  153. package/nitrogen/generated/ios/c++/HybridOneKeyImageSpecSwift.cpp +11 -0
  154. package/nitrogen/generated/ios/c++/HybridOneKeyImageSpecSwift.hpp +206 -0
  155. package/nitrogen/generated/ios/c++/views/HybridOneKeyImageComponent.mm +228 -0
  156. package/nitrogen/generated/ios/swift/Func_void.swift +46 -0
  157. package/nitrogen/generated/ios/swift/Func_void_bool.swift +46 -0
  158. package/nitrogen/generated/ios/swift/Func_void_double_double_OneKeyImageCacheType.swift +46 -0
  159. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
  160. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
  161. package/nitrogen/generated/ios/swift/HybridOneKeyImageCacheSpec.swift +58 -0
  162. package/nitrogen/generated/ios/swift/HybridOneKeyImageCacheSpec_cxx.swift +202 -0
  163. package/nitrogen/generated/ios/swift/HybridOneKeyImageSpec.swift +70 -0
  164. package/nitrogen/generated/ios/swift/HybridOneKeyImageSpec_cxx.swift +539 -0
  165. package/nitrogen/generated/ios/swift/OneKeyImageCachePolicy.swift +48 -0
  166. package/nitrogen/generated/ios/swift/OneKeyImageCacheType.swift +44 -0
  167. package/nitrogen/generated/ios/swift/OneKeyImageContentFit.swift +48 -0
  168. package/nitrogen/generated/ios/swift/OneKeyImageLoadingStrategy.swift +44 -0
  169. package/nitrogen/generated/ios/swift/OneKeyImagePreloadSource.swift +148 -0
  170. package/nitrogen/generated/ios/swift/OneKeyImageVariant.swift +48 -0
  171. package/nitrogen/generated/shared/c++/HybridOneKeyImageCacheSpec.cpp +24 -0
  172. package/nitrogen/generated/shared/c++/HybridOneKeyImageCacheSpec.hpp +68 -0
  173. package/nitrogen/generated/shared/c++/HybridOneKeyImageSpec.cpp +52 -0
  174. package/nitrogen/generated/shared/c++/HybridOneKeyImageSpec.hpp +108 -0
  175. package/nitrogen/generated/shared/c++/OneKeyImageCachePolicy.hpp +84 -0
  176. package/nitrogen/generated/shared/c++/OneKeyImageCacheType.hpp +80 -0
  177. package/nitrogen/generated/shared/c++/OneKeyImageContentFit.hpp +84 -0
  178. package/nitrogen/generated/shared/c++/OneKeyImageLoadingStrategy.hpp +80 -0
  179. package/nitrogen/generated/shared/c++/OneKeyImagePreloadSource.hpp +114 -0
  180. package/nitrogen/generated/shared/c++/OneKeyImageVariant.hpp +84 -0
  181. package/nitrogen/generated/shared/c++/views/HybridOneKeyImageComponent.cpp +62 -0
  182. package/nitrogen/generated/shared/c++/views/HybridOneKeyImageComponent.hpp +132 -0
  183. package/nitrogen/generated/shared/json/OneKeyImageConfig.json +24 -0
  184. package/package.json +128 -0
  185. package/src/OneKeyImage.nitro.ts +86 -0
  186. package/src/index.tsx +376 -0
@@ -0,0 +1,131 @@
1
+ package com.margelo.nitro.onekeyimage
2
+
3
+ import com.bumptech.glide.Glide
4
+ import com.bumptech.glide.load.engine.DiskCacheStrategy
5
+ import com.bumptech.glide.request.RequestOptions
6
+ import com.margelo.nitro.NitroModules
7
+ import com.margelo.nitro.core.Promise
8
+ import kotlinx.coroutines.Dispatchers
9
+ import kotlinx.coroutines.withContext
10
+ import kotlin.math.ceil
11
+ import kotlin.math.max
12
+
13
+ class HybridOneKeyImageCache : HybridOneKeyImageCacheSpec() {
14
+ override fun preload(sources: Array<OneKeyImagePreloadSource>): Promise<Boolean> = Promise.async {
15
+ val context = NitroModules.applicationContext
16
+ ?: throw IllegalStateException("React application context is unavailable")
17
+ OneKeyImageGlideRegistry.ensureRegistered(context)
18
+ var allSucceeded = true
19
+ sources.forEach { source ->
20
+ if (source.uri.isBlank()) {
21
+ allSucceeded = false
22
+ return@forEach
23
+ }
24
+ val baseOptions = RequestOptions()
25
+ .dontTransform()
26
+ .downsample(OneKeyImageSafeDownsampleStrategy())
27
+ val options = when (source.cachePolicy ?: OneKeyImageCachePolicy.MEMORY_DISK) {
28
+ OneKeyImageCachePolicy.MEMORY_DISK -> baseOptions
29
+ .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
30
+ OneKeyImageCachePolicy.MEMORY -> baseOptions
31
+ .diskCacheStrategy(DiskCacheStrategy.NONE)
32
+ OneKeyImageCachePolicy.DISK -> baseOptions
33
+ .diskCacheStrategy(DiskCacheStrategy.DATA)
34
+ .skipMemoryCache(true)
35
+ OneKeyImageCachePolicy.NONE -> baseOptions
36
+ .diskCacheStrategy(DiskCacheStrategy.NONE)
37
+ .skipMemoryCache(true)
38
+ }
39
+ val displayWidth = source.resizeWidth?.takeIf { it.isFinite() && it > 0.0 }
40
+ val displayHeight = source.resizeHeight?.takeIf { it.isFinite() && it > 0.0 }
41
+ val displaySize = when {
42
+ displayWidth != null && displayHeight != null -> max(displayWidth, displayHeight)
43
+ displayWidth != null -> displayWidth
44
+ else -> displayHeight
45
+ }
46
+ val density = (source.pixelRatio ?: context.resources.displayMetrics.density.toDouble())
47
+ .takeIf { it.isFinite() }
48
+ ?.coerceAtLeast(1.0)
49
+ ?: 1.0
50
+ val decodeDimensions = OneKeyImageDecodeDimensions.forPreload(
51
+ displayWidth,
52
+ displayHeight,
53
+ density,
54
+ )
55
+ val hasCustomIdentity = OneKeyImageModel.headers(source.headersJson).isNotEmpty()
56
+ val requestUrl = if (source.optimizeTos != false && displaySize != null) {
57
+ OneKeyTosUrl.optimized(
58
+ source.uri,
59
+ ceil(displaySize).toInt(),
60
+ density.toFloat(),
61
+ source.overscan ?: 1.1,
62
+ hasCustomIdentity,
63
+ )
64
+ } else source.uri
65
+
66
+ val succeeded = try {
67
+ load(context, requestUrl, source, options, decodeDimensions)
68
+ true
69
+ } catch (optimizedError: Exception) {
70
+ if (
71
+ requestUrl == source.uri ||
72
+ OneKeyImageSafety.isSafetyFailure(optimizedError)
73
+ ) {
74
+ false
75
+ } else {
76
+ try {
77
+ load(context, source.uri, source, options, decodeDimensions)
78
+ true
79
+ } catch (_: Exception) {
80
+ false
81
+ }
82
+ }
83
+ }
84
+ allSucceeded = allSucceeded && succeeded
85
+ }
86
+ allSucceeded
87
+ }
88
+
89
+ override fun clearMemory(): Promise<Unit> = Promise.async {
90
+ val context = NitroModules.applicationContext
91
+ ?: throw IllegalStateException("React application context is unavailable")
92
+ withContext(Dispatchers.Main) {
93
+ Glide.get(context).clearMemory()
94
+ }
95
+ }
96
+
97
+ override fun clearDisk(): Promise<Unit> = Promise.async {
98
+ val context = NitroModules.applicationContext
99
+ ?: throw IllegalStateException("React application context is unavailable")
100
+ Glide.get(context).clearDiskCache()
101
+ }
102
+
103
+ override fun clearAll(): Promise<Unit> = Promise.async {
104
+ val context = NitroModules.applicationContext
105
+ ?: throw IllegalStateException("React application context is unavailable")
106
+ withContext(Dispatchers.Main) {
107
+ Glide.get(context).clearMemory()
108
+ }
109
+ Glide.get(context).clearDiskCache()
110
+ }
111
+
112
+ private fun load(
113
+ context: android.content.Context,
114
+ url: String,
115
+ source: OneKeyImagePreloadSource,
116
+ options: RequestOptions,
117
+ decodeDimensions: OneKeyImageDecodeDimensions,
118
+ ) {
119
+ val request = Glide.with(context)
120
+ .asDrawable()
121
+ .load(OneKeyImageModel.build(url, source.headersJson))
122
+ .apply(options)
123
+ .override(decodeDimensions.width, decodeDimensions.height)
124
+ val future = request.submit()
125
+ try {
126
+ future.get()
127
+ } finally {
128
+ Glide.with(context).clear(future)
129
+ }
130
+ }
131
+ }
@@ -0,0 +1,169 @@
1
+ package com.margelo.nitro.onekeyimage
2
+
3
+ import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy
4
+ import kotlin.math.ceil
5
+ import kotlin.math.floor
6
+ import kotlin.math.max
7
+ import kotlin.math.min
8
+ import kotlin.math.sqrt
9
+
10
+ /**
11
+ * Physical decode dimensions constrained to one 16 MiB ARGB_8888 bitmap.
12
+ *
13
+ * The same calculation is shared by render and preload so Glide's size-dependent
14
+ * cache identity cannot drift between the two paths.
15
+ */
16
+ internal data class OneKeyImageDecodeDimensions(
17
+ val width: Int,
18
+ val height: Int,
19
+ ) {
20
+ val estimatedBytes: Long
21
+ get() = width.toLong() * height.toLong() * BYTES_PER_PIXEL
22
+
23
+ companion object {
24
+ internal const val MAX_DECODE_BYTES = 16L * 1024L * 1024L
25
+ internal const val MAX_SQUARE_SIDE = 2048
26
+ private const val BYTES_PER_PIXEL = 4L
27
+ private const val MAX_PIXELS = MAX_DECODE_BYTES / BYTES_PER_PIXEL
28
+
29
+ fun forRender(width: Int, height: Int): OneKeyImageDecodeDimensions =
30
+ constrained(width.coerceAtLeast(1), height.coerceAtLeast(1))
31
+
32
+ fun forPreload(
33
+ logicalWidth: Double?,
34
+ logicalHeight: Double?,
35
+ pixelRatio: Double,
36
+ ): OneKeyImageDecodeDimensions {
37
+ val width = logicalWidth?.takeIf { it.isFinite() && it > 0.0 }
38
+ val height = logicalHeight?.takeIf { it.isFinite() && it > 0.0 }
39
+ val density = pixelRatio.takeIf { it.isFinite() }?.coerceAtLeast(1.0) ?: 1.0
40
+ val physicalWidth = width?.let { physicalPixels(it, density) }
41
+ val physicalHeight = height?.let { physicalPixels(it, density) }
42
+
43
+ return when {
44
+ physicalWidth != null && physicalHeight != null ->
45
+ constrained(physicalWidth, physicalHeight)
46
+ physicalWidth != null -> constrained(physicalWidth, physicalWidth)
47
+ physicalHeight != null -> constrained(physicalHeight, physicalHeight)
48
+ else -> OneKeyImageDecodeDimensions(MAX_SQUARE_SIDE, MAX_SQUARE_SIDE)
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Desired size passed to APNG4Android's uniform power-of-two sampler.
54
+ * Returns null only when the source aspect ratio is so extreme that the
55
+ * decoder cannot satisfy the cap without reducing one dimension below 1px.
56
+ */
57
+ fun forAnimatedDecoder(
58
+ sourceWidth: Int,
59
+ sourceHeight: Int,
60
+ targetWidth: Int,
61
+ targetHeight: Int,
62
+ ): OneKeyImageDecodeDimensions? {
63
+ if (sourceWidth <= 0 || sourceHeight <= 0) return null
64
+ val safeTarget = forRender(targetWidth, targetHeight)
65
+ val widthRatio = sourceWidth / safeTarget.width
66
+ val heightRatio = sourceHeight / safeTarget.height
67
+ var sampleSize = highestPowerOfTwoAtMost(min(widthRatio, heightRatio).coerceAtLeast(1))
68
+
69
+ while (
70
+ ceil(sourceWidth / sampleSize.toDouble()) *
71
+ ceil(sourceHeight / sampleSize.toDouble()) > MAX_PIXELS
72
+ ) {
73
+ if (sampleSize > Int.MAX_VALUE / 2) return null
74
+ sampleSize *= 2
75
+ }
76
+ if (sampleSize > min(sourceWidth, sourceHeight)) return null
77
+ return OneKeyImageDecodeDimensions(
78
+ (sourceWidth / sampleSize).coerceAtLeast(1),
79
+ (sourceHeight / sampleSize).coerceAtLeast(1),
80
+ )
81
+ }
82
+
83
+ fun safeStaticScaleFactor(
84
+ sourceWidth: Int,
85
+ sourceHeight: Int,
86
+ requestedWidth: Int,
87
+ requestedHeight: Int,
88
+ ): Float {
89
+ if (sourceWidth <= 0 || sourceHeight <= 0) return 1f
90
+ OneKeyImageSafety.requireStaticDimensions(sourceWidth, sourceHeight)
91
+ val targetScale = max(
92
+ requestedWidth.toDouble() / sourceWidth,
93
+ requestedHeight.toDouble() / sourceHeight,
94
+ ).coerceAtMost(1.0)
95
+ val sourcePixels = sourceWidth.toDouble() * sourceHeight.toDouble()
96
+ val safetyScale = sqrt(MAX_PIXELS.toDouble() / sourcePixels).coerceAtMost(1.0)
97
+ val resolvedScale = min(targetScale, safetyScale)
98
+ return if (resolvedScale < 1.0) {
99
+ // A Double -> Float conversion may round upward and cross the hard
100
+ // byte boundary by a few pixels.
101
+ java.lang.Math.nextDown(resolvedScale.toFloat())
102
+ } else {
103
+ 1f
104
+ }
105
+ }
106
+
107
+ private fun highestPowerOfTwoAtMost(value: Int): Int {
108
+ var result = 1
109
+ while (result <= value / 2) result *= 2
110
+ return result
111
+ }
112
+
113
+ private fun physicalPixels(logicalSize: Double, pixelRatio: Double): Int {
114
+ val pixels = ceil(logicalSize * pixelRatio)
115
+ return when {
116
+ !pixels.isFinite() || pixels >= Int.MAX_VALUE.toDouble() -> Int.MAX_VALUE
117
+ else -> pixels.toInt().coerceAtLeast(1)
118
+ }
119
+ }
120
+
121
+ private fun constrained(width: Int, height: Int): OneKeyImageDecodeDimensions {
122
+ val area = width.toDouble() * height.toDouble()
123
+ if (area <= MAX_PIXELS.toDouble()) {
124
+ return OneKeyImageDecodeDimensions(width, height)
125
+ }
126
+
127
+ val scale = sqrt(MAX_PIXELS.toDouble() / area)
128
+ var constrainedWidth = floor(width * scale).toInt().coerceAtLeast(1)
129
+ var constrainedHeight = floor(height * scale).toInt().coerceAtLeast(1)
130
+
131
+ // Floating-point rounding should already stay below the limit. Keep this
132
+ // final guard so the hard cap remains true for every Int input.
133
+ if (constrainedWidth.toLong() * constrainedHeight.toLong() > MAX_PIXELS) {
134
+ if (constrainedWidth >= constrainedHeight) {
135
+ constrainedWidth = (MAX_PIXELS / constrainedHeight).toInt().coerceAtLeast(1)
136
+ } else {
137
+ constrainedHeight = (MAX_PIXELS / constrainedWidth).toInt().coerceAtLeast(1)
138
+ }
139
+ }
140
+ return OneKeyImageDecodeDimensions(constrainedWidth, constrainedHeight)
141
+ }
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Downsamples static bitmaps for the target while independently enforcing the
147
+ * 16 MiB area cap. `override()` alone cannot enforce an area cap for very wide
148
+ * or tall sources because Glide's default strategy follows target edges.
149
+ */
150
+ internal class OneKeyImageSafeDownsampleStrategy : DownsampleStrategy() {
151
+ override fun getScaleFactor(
152
+ sourceWidth: Int,
153
+ sourceHeight: Int,
154
+ requestedWidth: Int,
155
+ requestedHeight: Int,
156
+ ): Float = OneKeyImageDecodeDimensions.safeStaticScaleFactor(
157
+ sourceWidth,
158
+ sourceHeight,
159
+ requestedWidth,
160
+ requestedHeight,
161
+ )
162
+
163
+ override fun getSampleSizeRounding(
164
+ sourceWidth: Int,
165
+ sourceHeight: Int,
166
+ requestedWidth: Int,
167
+ requestedHeight: Int,
168
+ ): SampleSizeRounding = SampleSizeRounding.MEMORY
169
+ }
@@ -0,0 +1,285 @@
1
+ package com.margelo.nitro.onekeyimage
2
+
3
+ import android.content.Context
4
+ import android.graphics.drawable.Drawable
5
+ import android.graphics.drawable.PictureDrawable
6
+ import android.util.Base64
7
+ import com.bumptech.glide.Glide
8
+ import com.bumptech.glide.Priority
9
+ import com.bumptech.glide.integration.avif.AvifGlideModule
10
+ import com.bumptech.glide.load.DataSource
11
+ import com.bumptech.glide.load.Options
12
+ import com.bumptech.glide.load.ResourceDecoder
13
+ import com.bumptech.glide.load.data.DataFetcher
14
+ import com.bumptech.glide.load.engine.Resource
15
+ import com.bumptech.glide.load.model.ModelLoader
16
+ import com.bumptech.glide.load.model.ModelLoaderFactory
17
+ import com.bumptech.glide.load.model.MultiModelLoaderFactory
18
+ import com.bumptech.glide.load.resource.SimpleResource
19
+ import com.bumptech.glide.load.resource.transcode.ResourceTranscoder
20
+ import com.bumptech.glide.signature.ObjectKey
21
+ import com.caverock.androidsvg.SVG
22
+ import com.caverock.androidsvg.SVGParseException
23
+ import com.facebook.react.modules.network.OkHttpClientProvider
24
+ import com.github.penfeizhou.animation.decode.FrameSeqDecoder
25
+ import com.github.penfeizhou.animation.glide.ByteBufferAnimationDecoder
26
+ import com.github.penfeizhou.animation.glide.GlideAnimationModule
27
+ import com.github.penfeizhou.animation.glide.StreamAnimationDecoder
28
+ import java.io.ByteArrayOutputStream
29
+ import java.io.ByteArrayInputStream
30
+ import java.io.IOException
31
+ import java.io.InputStream
32
+ import java.nio.ByteBuffer
33
+
34
+ /**
35
+ * Registers the small set of Glide integrations required by OneKeyImage.
36
+ *
37
+ * Registration is explicit instead of declaring another AppGlideModule. Android
38
+ * applications may only contain one AppGlideModule, and expo-image owns it while
39
+ * the two image modules coexist during migration.
40
+ */
41
+ internal object OneKeyImageGlideRegistry {
42
+ @Volatile
43
+ private var registered = false
44
+
45
+ fun ensureRegistered(context: Context) {
46
+ if (registered) return
47
+ synchronized(this) {
48
+ if (registered) return
49
+ val appContext = context.applicationContext
50
+ val glide = Glide.get(appContext)
51
+ val registry = glide.registry
52
+
53
+ registry.prepend(
54
+ OneKeyImageDataUriModel::class.java,
55
+ ByteBuffer::class.java,
56
+ OneKeyDataUriModelLoaderFactory(),
57
+ )
58
+ registry.prepend(
59
+ OneKeyImageLocalModel::class.java,
60
+ InputStream::class.java,
61
+ OneKeyImageLocalModelLoaderFactory(appContext),
62
+ )
63
+ val imageHttpClient = OkHttpClientProvider.createClient()
64
+ .newBuilder()
65
+ .addInterceptor(OneKeyImageEncodedDataInterceptor())
66
+ .build()
67
+ registry.prepend(
68
+ OneKeyImageRemoteModel::class.java,
69
+ InputStream::class.java,
70
+ OneKeyImageRemoteModelLoaderFactory(imageHttpClient),
71
+ )
72
+ registry.append(
73
+ InputStream::class.java,
74
+ SVG::class.java,
75
+ OneKeySvgDecoder(),
76
+ )
77
+ registry.register(
78
+ SVG::class.java,
79
+ Drawable::class.java,
80
+ OneKeySvgDrawableTranscoder(),
81
+ )
82
+
83
+ // These dependencies also ship LibraryGlideModules. Calling them directly
84
+ // keeps the feature available after expo-image (and its AppGlideModule) is
85
+ // removed, while remaining harmless when Expo registered them already.
86
+ AvifGlideModule().registerComponents(appContext, glide, registry)
87
+ GlideAnimationModule().registerComponents(appContext, glide, registry)
88
+ val animationDecoder = OneKeySafeAnimationDecoder()
89
+ registry.prepend(
90
+ InputStream::class.java,
91
+ FrameSeqDecoder::class.java,
92
+ OneKeySafeStreamAnimationDecoder(animationDecoder),
93
+ )
94
+ registry.prepend(
95
+ ByteBuffer::class.java,
96
+ FrameSeqDecoder::class.java,
97
+ animationDecoder,
98
+ )
99
+ registered = true
100
+ }
101
+ }
102
+ }
103
+
104
+ private class OneKeySafeAnimationDecoder : ResourceDecoder<ByteBuffer, FrameSeqDecoder<*, *>> {
105
+ private val delegate = ByteBufferAnimationDecoder()
106
+
107
+ override fun handles(source: ByteBuffer, options: Options): Boolean =
108
+ delegate.handles(source, options)
109
+
110
+ override fun decode(
111
+ source: ByteBuffer,
112
+ width: Int,
113
+ height: Int,
114
+ options: Options,
115
+ ): Resource<FrameSeqDecoder<*, *>>? {
116
+ val resource = delegate.decode(source, width, height, options) ?: return null
117
+ return OneKeyResourceCleanup.recycleOnException(resource::recycle) {
118
+ val decoder = resource.get()
119
+ val bounds = decoder.bounds
120
+ val desired = OneKeyImageDecodeDimensions.forAnimatedDecoder(
121
+ bounds.width(),
122
+ bounds.height(),
123
+ width,
124
+ height,
125
+ ) ?: throw OneKeyImageSafetyException(
126
+ "Animated image cannot fit the 16 MiB target decode limit",
127
+ )
128
+ decoder.setDesiredSize(desired.width, desired.height)
129
+ @Suppress("UNCHECKED_CAST")
130
+ resource as Resource<FrameSeqDecoder<*, *>>
131
+ }
132
+ }
133
+ }
134
+
135
+ internal object OneKeyResourceCleanup {
136
+ fun <T> recycleOnException(recycle: () -> Unit, block: () -> T): T = try {
137
+ block()
138
+ } catch (error: Exception) {
139
+ try {
140
+ recycle()
141
+ } catch (cleanupError: Exception) {
142
+ error.addSuppressed(cleanupError)
143
+ }
144
+ throw error
145
+ }
146
+ }
147
+
148
+ /** Penfeizhou's stream decoder swallows IOExceptions while buffering the input. */
149
+ private class OneKeySafeStreamAnimationDecoder(
150
+ private val byteBufferDecoder: ResourceDecoder<ByteBuffer, FrameSeqDecoder<*, *>>,
151
+ ) : ResourceDecoder<InputStream, FrameSeqDecoder<*, *>> {
152
+ private val handlesDelegate = StreamAnimationDecoder(byteBufferDecoder)
153
+
154
+ override fun handles(source: InputStream, options: Options): Boolean =
155
+ handlesDelegate.handles(source, options)
156
+
157
+ override fun decode(
158
+ source: InputStream,
159
+ width: Int,
160
+ height: Int,
161
+ options: Options,
162
+ ): Resource<FrameSeqDecoder<*, *>>? {
163
+ val output = ByteArrayOutputStream(16 * 1024)
164
+ val buffer = ByteArray(16 * 1024)
165
+ while (true) {
166
+ val count = source.read(buffer)
167
+ if (count < 0) break
168
+ if (count == 0) continue
169
+ OneKeyImageSafety.requireEncodedLength(
170
+ output.size().toLong() + count.toLong(),
171
+ OneKeyImageSafety.MAX_ANIMATED_ENCODED_BYTES,
172
+ )
173
+ output.write(buffer, 0, count)
174
+ }
175
+ return byteBufferDecoder.decode(ByteBuffer.wrap(output.toByteArray()), width, height, options)
176
+ }
177
+ }
178
+
179
+ private class OneKeyDataUriModelLoader : ModelLoader<OneKeyImageDataUriModel, ByteBuffer> {
180
+ override fun handles(model: OneKeyImageDataUriModel): Boolean = true
181
+
182
+ override fun buildLoadData(
183
+ model: OneKeyImageDataUriModel,
184
+ width: Int,
185
+ height: Int,
186
+ options: Options,
187
+ ): ModelLoader.LoadData<ByteBuffer> =
188
+ ModelLoader.LoadData(
189
+ OneKeyImageSafetyVersionedKey(ObjectKey(model)),
190
+ OneKeyDataUriFetcher(model.dataUri),
191
+ )
192
+ }
193
+
194
+ private class OneKeyDataUriModelLoaderFactory :
195
+ ModelLoaderFactory<OneKeyImageDataUriModel, ByteBuffer> {
196
+ override fun build(
197
+ multiFactory: MultiModelLoaderFactory,
198
+ ): ModelLoader<OneKeyImageDataUriModel, ByteBuffer> =
199
+ OneKeyDataUriModelLoader()
200
+
201
+ override fun teardown() = Unit
202
+ }
203
+
204
+ private class OneKeyDataUriFetcher(private val dataUri: String) : DataFetcher<ByteBuffer> {
205
+ override fun cleanup() = Unit
206
+ override fun cancel() = Unit
207
+ override fun getDataClass(): Class<ByteBuffer> = ByteBuffer::class.java
208
+ override fun getDataSource(): DataSource = DataSource.LOCAL
209
+
210
+ override fun loadData(
211
+ priority: Priority,
212
+ callback: DataFetcher.DataCallback<in ByteBuffer>,
213
+ ) {
214
+ try {
215
+ val comma = dataUri.indexOf(',')
216
+ require(comma >= 0 && dataUri.substring(0, comma).contains(";base64")) {
217
+ "Only base64 image data URIs are supported"
218
+ }
219
+ val payloadStart = comma + 1
220
+ val decodedByteCount = OneKeyImageSafety.dataUriDecodedByteCount(dataUri, payloadStart)
221
+ OneKeyImageSafety.requireEncodedLength(
222
+ decodedByteCount,
223
+ OneKeyImageSafety.MAX_DATA_URI_DECODED_BYTES,
224
+ )
225
+ val decoded = Base64.decode(dataUri.substring(payloadStart), Base64.DEFAULT)
226
+ OneKeyImageSafety.requireEncodedLength(
227
+ decoded.size.toLong(),
228
+ OneKeyImageSafety.MAX_DATA_URI_DECODED_BYTES,
229
+ )
230
+ val metadata = OneKeyEncodedImageInspector.inspect(ByteArrayInputStream(decoded))
231
+ if (metadata.animated) {
232
+ OneKeyImageSafety.requireEncodedLength(
233
+ decoded.size.toLong(),
234
+ OneKeyImageSafety.MAX_ANIMATED_ENCODED_BYTES,
235
+ )
236
+ val format = metadata.animatedFormat
237
+ ?: throw OneKeyImageSafetyException("Animated image format is unavailable")
238
+ OneKeyAnimationTimelineInspector.validate(format, decoded)
239
+ }
240
+ callback.onDataReady(ByteBuffer.wrap(decoded))
241
+ } catch (error: Exception) {
242
+ callback.onLoadFailed(error)
243
+ }
244
+ }
245
+ }
246
+
247
+ private class OneKeySvgDecoder : ResourceDecoder<InputStream, SVG> {
248
+ override fun handles(source: InputStream, options: Options): Boolean = true
249
+
250
+ @Throws(IOException::class)
251
+ override fun decode(
252
+ source: InputStream,
253
+ width: Int,
254
+ height: Int,
255
+ options: Options,
256
+ ): Resource<SVG> {
257
+ val svg = try {
258
+ SVG.getFromInputStream(source)
259
+ } catch (error: SVGParseException) {
260
+ throw IOException("Cannot decode SVG", error)
261
+ }
262
+ if (svg.documentViewBox == null) {
263
+ val documentWidth = svg.documentWidth
264
+ val documentHeight = svg.documentHeight
265
+ if (documentWidth > 0f && documentHeight > 0f) {
266
+ svg.setDocumentViewBox(0f, 0f, documentWidth, documentHeight)
267
+ }
268
+ }
269
+
270
+ val viewBox = svg.documentViewBox
271
+ if (viewBox != null && viewBox.width() > 0f && viewBox.height() > 0f) {
272
+ val scale = minOf(width.toFloat() / viewBox.width(), height.toFloat() / viewBox.height())
273
+ if (scale.isFinite() && scale > 0f) {
274
+ svg.documentWidth = viewBox.width() * scale
275
+ svg.documentHeight = viewBox.height() * scale
276
+ }
277
+ }
278
+ return SimpleResource(svg)
279
+ }
280
+ }
281
+
282
+ private class OneKeySvgDrawableTranscoder : ResourceTranscoder<SVG, Drawable> {
283
+ override fun transcode(toTranscode: Resource<SVG>, options: Options): Resource<Drawable> =
284
+ SimpleResource(PictureDrawable(toTranscode.get().renderToPicture()))
285
+ }
@@ -0,0 +1,68 @@
1
+ package com.margelo.nitro.onekeyimage
2
+
3
+ import android.net.Uri
4
+ import com.bumptech.glide.load.model.GlideUrl
5
+ import com.bumptech.glide.load.model.LazyHeaders
6
+ import org.json.JSONObject
7
+ import java.nio.ByteBuffer
8
+ import java.security.MessageDigest
9
+ import java.util.Locale
10
+
11
+ internal object OneKeyImageModel {
12
+ fun headers(json: String?): Map<String, String> {
13
+ if (json.isNullOrBlank()) return emptyMap()
14
+ return try {
15
+ val objectValue = JSONObject(json)
16
+ buildMap {
17
+ objectValue.keys().forEach { key ->
18
+ val value = objectValue.opt(key)
19
+ if (value is String) put(key, value)
20
+ }
21
+ }
22
+ } catch (_: Exception) {
23
+ emptyMap()
24
+ }
25
+ }
26
+
27
+ fun build(uri: String, headersJson: String?): Any {
28
+ if (uri.startsWith("data:")) return OneKeyImageDataUriModel(uri)
29
+ if (!uri.startsWith("http://") && !uri.startsWith("https://")) {
30
+ return OneKeyImageLocalModel(Uri.parse(uri))
31
+ }
32
+ val parsedHeaders = headers(headersJson)
33
+ val headerBuilder = LazyHeaders.Builder()
34
+ parsedHeaders.forEach { (name, value) -> headerBuilder.addHeader(name, value) }
35
+ val headers = headerBuilder.build()
36
+ return OneKeyImageRemoteModel(
37
+ glideUrl = GlideUrl(uri, headers),
38
+ headersDigest = remoteHeadersDigest(parsedHeaders),
39
+ )
40
+ }
41
+
42
+ internal fun remoteHeadersDigest(headers: Map<String, String>): String? {
43
+ if (headers.isEmpty()) return null
44
+ val digest = MessageDigest.getInstance("SHA-256")
45
+ headers.entries
46
+ .map { it.key.lowercase(Locale.ROOT) to it.value }
47
+ .sortedWith(compareBy<Pair<String, String>>({ it.first }, { it.second }))
48
+ .forEach { (name, value) ->
49
+ updateLengthPrefixed(digest, name.toByteArray(Charsets.UTF_8))
50
+ updateLengthPrefixed(digest, value.toByteArray(Charsets.UTF_8))
51
+ }
52
+ return digest.digest().joinToString("") { "%02x".format(Locale.ROOT, it.toInt() and 0xff) }
53
+ }
54
+
55
+ private fun updateLengthPrefixed(digest: MessageDigest, value: ByteArray) {
56
+ digest.update(ByteBuffer.allocate(Int.SIZE_BYTES).putInt(value.size).array())
57
+ digest.update(value)
58
+ }
59
+ }
60
+
61
+ internal data class OneKeyImageRemoteModel(
62
+ val glideUrl: GlideUrl,
63
+ val headersDigest: String?,
64
+ )
65
+
66
+ internal data class OneKeyImageLocalModel(val uri: Uri)
67
+
68
+ internal data class OneKeyImageDataUriModel(val dataUri: String)
@@ -0,0 +1,28 @@
1
+ package com.margelo.nitro.onekeyimage
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfoProvider
7
+ import com.facebook.react.uimanager.ViewManager
8
+ import com.margelo.nitro.onekeyimage.views.HybridOneKeyImageManager
9
+
10
+ class OneKeyImagePackage : BaseReactPackage() {
11
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = null
12
+
13
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider =
14
+ ReactModuleInfoProvider { HashMap() }
15
+
16
+ override fun createViewManagers(
17
+ reactContext: ReactApplicationContext,
18
+ ): List<ViewManager<*, *>> {
19
+ OneKeyImageGlideRegistry.ensureRegistered(reactContext)
20
+ return listOf(HybridOneKeyImageManager())
21
+ }
22
+
23
+ companion object {
24
+ init {
25
+ System.loadLibrary("onekeyimage")
26
+ }
27
+ }
28
+ }