expo-gaode-map 2.2.30-next.0 → 2.2.30

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 (82) hide show
  1. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapModule.kt +4 -2
  2. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +117 -57
  3. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapViewModule.kt +8 -15
  4. package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +20 -6
  5. package/android/src/main/java/expo/modules/gaodemap/overlays/ClusterView.kt +24 -13
  6. package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerBitmapRenderer.kt +351 -0
  7. package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +94 -310
  8. package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerViewModule.kt +3 -3
  9. package/build/ExpoGaodeMapModule.d.ts +13 -5
  10. package/build/ExpoGaodeMapModule.d.ts.map +1 -1
  11. package/build/ExpoGaodeMapModule.js +166 -34
  12. package/build/ExpoGaodeMapModule.js.map +1 -1
  13. package/build/ExpoGaodeMapView.d.ts.map +1 -1
  14. package/build/ExpoGaodeMapView.js +12 -0
  15. package/build/ExpoGaodeMapView.js.map +1 -1
  16. package/build/components/AreaMaskOverlay.d.ts +5 -0
  17. package/build/components/AreaMaskOverlay.d.ts.map +1 -0
  18. package/build/components/AreaMaskOverlay.js +20 -0
  19. package/build/components/AreaMaskOverlay.js.map +1 -0
  20. package/build/components/FoldableMapView.d.ts.map +1 -1
  21. package/build/components/FoldableMapView.js +115 -104
  22. package/build/components/FoldableMapView.js.map +1 -1
  23. package/build/components/RouteOverlay.d.ts +5 -0
  24. package/build/components/RouteOverlay.d.ts.map +1 -0
  25. package/build/components/RouteOverlay.js +20 -0
  26. package/build/components/RouteOverlay.js.map +1 -0
  27. package/build/components/overlays/Cluster.d.ts.map +1 -1
  28. package/build/components/overlays/Cluster.js +12 -0
  29. package/build/components/overlays/Cluster.js.map +1 -1
  30. package/build/components/overlays/Marker.d.ts.map +1 -1
  31. package/build/components/overlays/Marker.js +86 -3
  32. package/build/components/overlays/Marker.js.map +1 -1
  33. package/build/hooks/useRoutePlayback.d.ts +4 -0
  34. package/build/hooks/useRoutePlayback.d.ts.map +1 -0
  35. package/build/hooks/useRoutePlayback.js +310 -0
  36. package/build/hooks/useRoutePlayback.js.map +1 -0
  37. package/build/index.d.ts +4 -1
  38. package/build/index.d.ts.map +1 -1
  39. package/build/index.js +4 -2
  40. package/build/index.js.map +1 -1
  41. package/build/types/common.types.d.ts +29 -5
  42. package/build/types/common.types.d.ts.map +1 -1
  43. package/build/types/common.types.js +5 -5
  44. package/build/types/common.types.js.map +1 -1
  45. package/build/types/index.d.ts +3 -2
  46. package/build/types/index.d.ts.map +1 -1
  47. package/build/types/index.js.map +1 -1
  48. package/build/types/location.types.d.ts +28 -0
  49. package/build/types/location.types.d.ts.map +1 -1
  50. package/build/types/location.types.js +5 -0
  51. package/build/types/location.types.js.map +1 -1
  52. package/build/types/map-view.types.d.ts +22 -22
  53. package/build/types/map-view.types.d.ts.map +1 -1
  54. package/build/types/map-view.types.js.map +1 -1
  55. package/build/types/native-module.types.d.ts +2 -2
  56. package/build/types/native-module.types.d.ts.map +1 -1
  57. package/build/types/native-module.types.js.map +1 -1
  58. package/build/types/overlays.types.d.ts +14 -0
  59. package/build/types/overlays.types.d.ts.map +1 -1
  60. package/build/types/overlays.types.js.map +1 -1
  61. package/build/types/route-playback.types.d.ts +118 -0
  62. package/build/types/route-playback.types.d.ts.map +1 -0
  63. package/build/types/route-playback.types.js +2 -0
  64. package/build/types/route-playback.types.js.map +1 -0
  65. package/build/utils/RouteUtils.d.ts +8 -0
  66. package/build/utils/RouteUtils.d.ts.map +1 -0
  67. package/build/utils/RouteUtils.js +140 -0
  68. package/build/utils/RouteUtils.js.map +1 -0
  69. package/ios/ExpoGaodeMapModule.swift +41 -22
  70. package/ios/ExpoGaodeMapView.swift +236 -241
  71. package/ios/ExpoGaodeMapViewModule.swift +16 -11
  72. package/ios/managers/UIManager.swift +5 -4
  73. package/ios/modules/LocationManager.swift +32 -9
  74. package/ios/overlays/ClusterView.swift +114 -12
  75. package/ios/overlays/ClusterViewModule.swift +5 -1
  76. package/ios/overlays/MarkerView.swift +195 -18
  77. package/ios/overlays/MarkerViewModule.swift +7 -7
  78. package/package.json +6 -6
  79. package/build/utils/throttle.d.ts +0 -10
  80. package/build/utils/throttle.d.ts.map +0 -1
  81. package/build/utils/throttle.js +0 -19
  82. package/build/utils/throttle.js.map +0 -1
@@ -0,0 +1,351 @@
1
+ package expo.modules.gaodemap.overlays
2
+
3
+ import android.graphics.Bitmap
4
+ import android.graphics.Canvas
5
+ import android.graphics.Color
6
+ import android.graphics.Rect
7
+ import android.os.Handler
8
+ import android.os.Looper
9
+ import android.view.View
10
+ import android.view.ViewGroup
11
+ import android.widget.ImageView
12
+ import android.widget.TextView
13
+ import androidx.core.graphics.createBitmap
14
+ import expo.modules.gaodemap.companion.IconBitmapCache
15
+ import java.util.concurrent.CountDownLatch
16
+ import java.util.concurrent.TimeUnit
17
+ import kotlin.text.StringBuilder
18
+
19
+ internal data class MarkerBitmapSnapshot(
20
+ val keyPart: String,
21
+ val width: Int,
22
+ val height: Int,
23
+ ) {
24
+ val fullCacheKey: String
25
+ get() = "$keyPart|${width}x${height}"
26
+ }
27
+
28
+ internal object MarkerBitmapRenderer {
29
+ fun hasPendingAsyncImageContent(view: View?): Boolean {
30
+ view ?: return false
31
+ if (view.visibility != View.VISIBLE) return false
32
+
33
+ if (view is ImageView) {
34
+ val resolvedWidth = view.measuredWidth.takeIf { it > 0 } ?: view.width
35
+ val resolvedHeight = view.measuredHeight.takeIf { it > 0 } ?: view.height
36
+ if (resolvedWidth > 0 && resolvedHeight > 0 && view.drawable == null) {
37
+ return true
38
+ }
39
+ }
40
+
41
+ if (view is ViewGroup) {
42
+ for (index in 0 until view.childCount) {
43
+ if (hasPendingAsyncImageContent(view.getChildAt(index))) {
44
+ return true
45
+ }
46
+ }
47
+ }
48
+
49
+ return false
50
+ }
51
+
52
+ fun resolveSnapshot(
53
+ container: ViewGroup,
54
+ customViewWidth: Int,
55
+ customViewHeight: Int,
56
+ cacheKey: String?,
57
+ ): MarkerBitmapSnapshot? {
58
+ if (container.childCount == 0) {
59
+ return null
60
+ }
61
+
62
+ val child = container.getChildAt(0) ?: return null
63
+ if (hasPendingAsyncImageContent(child)) {
64
+ return null
65
+ }
66
+ val contentView = resolveRenderableContentView(child)
67
+ val contentBounds = computeContentBounds(child)
68
+ val measuredWidth =
69
+ contentBounds?.width()
70
+ ?: contentView?.measuredWidth
71
+ ?: child.measuredWidth
72
+ ?: 0
73
+ val measuredHeight =
74
+ contentBounds?.height()
75
+ ?: contentView?.measuredHeight
76
+ ?: child.measuredHeight
77
+ ?: 0
78
+
79
+ val finalWidth = if (measuredWidth > 0) measuredWidth else customViewWidth
80
+ val finalHeight = if (measuredHeight > 0) measuredHeight else customViewHeight
81
+
82
+ if (finalWidth <= 0 || finalHeight <= 0) {
83
+ return null
84
+ }
85
+
86
+ val fingerprint = computeViewFingerprint(container)
87
+
88
+ return MarkerBitmapSnapshot(
89
+ keyPart = cacheKey?.let { "$it|$fingerprint" } ?: fingerprint,
90
+ width = finalWidth,
91
+ height = finalHeight,
92
+ )
93
+ }
94
+
95
+ fun createBitmap(
96
+ container: ViewGroup,
97
+ snapshot: MarkerBitmapSnapshot,
98
+ customViewWidth: Int,
99
+ customViewHeight: Int,
100
+ mainHandler: Handler,
101
+ ): Bitmap? {
102
+ IconBitmapCache.get(snapshot.fullCacheKey)?.let { return it }
103
+
104
+ val bitmap =
105
+ if (Looper.myLooper() == Looper.getMainLooper()) {
106
+ renderViewToBitmapInternal(
107
+ container = container,
108
+ finalWidth = snapshot.width,
109
+ finalHeight = snapshot.height,
110
+ customViewWidth = customViewWidth,
111
+ customViewHeight = customViewHeight,
112
+ )
113
+ } else {
114
+ val latch = CountDownLatch(1)
115
+ var result: Bitmap? = null
116
+ mainHandler.post {
117
+ try {
118
+ result =
119
+ renderViewToBitmapInternal(
120
+ container = container,
121
+ finalWidth = snapshot.width,
122
+ finalHeight = snapshot.height,
123
+ customViewWidth = customViewWidth,
124
+ customViewHeight = customViewHeight,
125
+ )
126
+ } finally {
127
+ latch.countDown()
128
+ }
129
+ }
130
+ try {
131
+ latch.await(200, TimeUnit.MILLISECONDS)
132
+ } catch (_: InterruptedException) {
133
+ }
134
+ result
135
+ }
136
+
137
+ bitmap?.let { IconBitmapCache.put(snapshot.fullCacheKey, it) }
138
+ return bitmap
139
+ }
140
+
141
+ fun computeContentBounds(view: View?): Rect? {
142
+ view ?: return null
143
+ if (view.visibility != View.VISIBLE) return null
144
+
145
+ var resolvedBounds: Rect? = null
146
+
147
+ if (view is ViewGroup && view.childCount > 0) {
148
+ for (i in 0 until view.childCount) {
149
+ val child = view.getChildAt(i) ?: continue
150
+ val childBounds = computeContentBounds(child) ?: continue
151
+ val shiftedBounds = Rect(childBounds)
152
+ shiftedBounds.offset(child.left, child.top)
153
+ resolvedBounds =
154
+ if (resolvedBounds == null) {
155
+ shiftedBounds
156
+ } else {
157
+ Rect(resolvedBounds).apply { union(shiftedBounds) }
158
+ }
159
+ }
160
+ }
161
+
162
+ val hasOwnVisualBounds =
163
+ view.background != null ||
164
+ view.paddingLeft != 0 ||
165
+ view.paddingTop != 0 ||
166
+ view.paddingRight != 0 ||
167
+ view.paddingBottom != 0 ||
168
+ view !is ViewGroup
169
+
170
+ val ownWidth = view.measuredWidth.takeIf { it > 0 } ?: view.width
171
+ val ownHeight = view.measuredHeight.takeIf { it > 0 } ?: view.height
172
+
173
+ if (hasOwnVisualBounds && ownWidth > 0 && ownHeight > 0) {
174
+ val ownBounds = Rect(0, 0, ownWidth, ownHeight)
175
+ resolvedBounds =
176
+ if (resolvedBounds == null) {
177
+ ownBounds
178
+ } else {
179
+ Rect(resolvedBounds).apply { union(ownBounds) }
180
+ }
181
+ }
182
+
183
+ return resolvedBounds
184
+ }
185
+
186
+ fun resolveRenderableContentView(view: View?): View? {
187
+ var current = view ?: return null
188
+
189
+ while (current is ViewGroup && current.childCount == 1) {
190
+ val next = current.getChildAt(0) ?: break
191
+ current = next
192
+ }
193
+
194
+ return current
195
+ }
196
+
197
+ fun computeViewFingerprint(view: View?): String {
198
+ if (view == null) return "null"
199
+
200
+ val sb = StringBuilder()
201
+ val tag = view.tag
202
+ if (tag != null) {
203
+ sb.append("tag=").append(tag.toString()).append(";")
204
+ return sb.toString()
205
+ }
206
+
207
+ val contentDesc = view.contentDescription
208
+ if (!contentDesc.isNullOrEmpty()) {
209
+ sb.append("cdesc=").append(contentDesc.toString()).append(";")
210
+ return sb.toString()
211
+ }
212
+
213
+ fun appendFor(v: View) {
214
+ sb.append(v.javaClass.simpleName)
215
+ when (v) {
216
+ is TextView -> {
217
+ val text = v.text?.toString() ?: ""
218
+ if (text.isNotEmpty()) {
219
+ sb.append("[text=").append(text).append("]")
220
+ }
221
+ }
222
+
223
+ is ImageView -> {
224
+ val resId = v.tag
225
+ if (resId is Int && resId != 0) {
226
+ sb.append("[imgRes=").append(resId).append("]")
227
+ } else {
228
+ val drawable = v.drawable
229
+ if (drawable != null) {
230
+ sb.append("[drawableHash=").append(drawable.hashCode()).append("]")
231
+ }
232
+ }
233
+ }
234
+ }
235
+ sb.append(";")
236
+ if (v is ViewGroup) {
237
+ for (i in 0 until v.childCount) {
238
+ appendFor(v.getChildAt(i))
239
+ }
240
+ }
241
+ }
242
+
243
+ appendFor(view)
244
+ return sb.toString().take(1024)
245
+ }
246
+
247
+ private fun renderViewToBitmapInternal(
248
+ container: ViewGroup,
249
+ finalWidth: Int,
250
+ finalHeight: Int,
251
+ customViewWidth: Int,
252
+ customViewHeight: Int,
253
+ ): Bitmap? {
254
+ try {
255
+ val childView = container.getChildAt(0) ?: return null
256
+
257
+ if (childView.width != finalWidth || childView.height != finalHeight) {
258
+ if (childView.width == 0 || childView.height == 0) {
259
+ return null
260
+ }
261
+
262
+ val widthSpec = View.MeasureSpec.makeMeasureSpec(finalWidth, View.MeasureSpec.EXACTLY)
263
+ val heightSpec = View.MeasureSpec.makeMeasureSpec(finalHeight, View.MeasureSpec.EXACTLY)
264
+ childView.measure(widthSpec, heightSpec)
265
+ childView.layout(0, 0, finalWidth, finalHeight)
266
+ } else if (childView.left != 0 || childView.top != 0) {
267
+ childView.layout(0, 0, finalWidth, finalHeight)
268
+ }
269
+
270
+ val bitmap = createBitmap(finalWidth, finalHeight)
271
+ val canvas = Canvas(bitmap)
272
+ childView.draw(canvas)
273
+
274
+ val shouldTrimTransparentPadding = customViewWidth <= 0 && customViewHeight <= 0
275
+ return if (shouldTrimTransparentPadding) trimTransparentPadding(bitmap) else bitmap
276
+ } catch (_: Exception) {
277
+ return null
278
+ }
279
+ }
280
+
281
+ private fun trimTransparentPadding(bitmap: Bitmap): Bitmap {
282
+ if (bitmap.width <= 1 || bitmap.height <= 1) {
283
+ return bitmap
284
+ }
285
+
286
+ if (hasOpaquePixelsOnAllBitmapEdges(bitmap)) {
287
+ return bitmap
288
+ }
289
+
290
+ var minX = bitmap.width
291
+ var minY = bitmap.height
292
+ var maxX = -1
293
+ var maxY = -1
294
+
295
+ for (y in 0 until bitmap.height) {
296
+ for (x in 0 until bitmap.width) {
297
+ if (Color.alpha(bitmap.getPixel(x, y)) != 0) {
298
+ if (x < minX) minX = x
299
+ if (y < minY) minY = y
300
+ if (x > maxX) maxX = x
301
+ if (y > maxY) maxY = y
302
+ }
303
+ }
304
+ }
305
+
306
+ if (maxX < minX || maxY < minY) {
307
+ return bitmap
308
+ }
309
+
310
+ val trimmedWidth = maxX - minX + 1
311
+ val trimmedHeight = maxY - minY + 1
312
+ if (trimmedWidth == bitmap.width && trimmedHeight == bitmap.height) {
313
+ return bitmap
314
+ }
315
+
316
+ return Bitmap.createBitmap(bitmap, minX, minY, trimmedWidth, trimmedHeight)
317
+ }
318
+
319
+ private fun hasOpaquePixelsOnAllBitmapEdges(bitmap: Bitmap): Boolean {
320
+ var topEdgeHasPixel = false
321
+ var bottomEdgeHasPixel = false
322
+ var leftEdgeHasPixel = false
323
+ var rightEdgeHasPixel = false
324
+
325
+ for (x in 0 until bitmap.width) {
326
+ if (!topEdgeHasPixel && Color.alpha(bitmap.getPixel(x, 0)) != 0) {
327
+ topEdgeHasPixel = true
328
+ }
329
+ if (!bottomEdgeHasPixel && Color.alpha(bitmap.getPixel(x, bitmap.height - 1)) != 0) {
330
+ bottomEdgeHasPixel = true
331
+ }
332
+ if (topEdgeHasPixel && bottomEdgeHasPixel) {
333
+ break
334
+ }
335
+ }
336
+
337
+ for (y in 0 until bitmap.height) {
338
+ if (!leftEdgeHasPixel && Color.alpha(bitmap.getPixel(0, y)) != 0) {
339
+ leftEdgeHasPixel = true
340
+ }
341
+ if (!rightEdgeHasPixel && Color.alpha(bitmap.getPixel(bitmap.width - 1, y)) != 0) {
342
+ rightEdgeHasPixel = true
343
+ }
344
+ if (leftEdgeHasPixel && rightEdgeHasPixel) {
345
+ break
346
+ }
347
+ }
348
+
349
+ return topEdgeHasPixel && bottomEdgeHasPixel && leftEdgeHasPixel && rightEdgeHasPixel
350
+ }
351
+ }