@maydon_tech/react-native-nitro-maps 0.1.4 → 0.2.0

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 (217) hide show
  1. package/LICENSE +1 -1
  2. package/NitroMap.podspec +1 -1
  3. package/README.md +82 -9
  4. package/android/CMakeLists.txt +4 -1
  5. package/android/gradle.properties +4 -4
  6. package/android/src/main/cpp/ClusterEngineJNI.cpp +198 -0
  7. package/android/src/main/kotlin/com/margelo/nitro/nitromap/NitroMap.kt +397 -0
  8. package/android/src/main/kotlin/com/margelo/nitro/nitromap/NitroMapConfig.kt +53 -0
  9. package/android/src/main/{java → kotlin}/com/margelo/nitro/nitromap/NitroMapPackage.kt +4 -4
  10. package/android/src/main/kotlin/com/margelo/nitro/nitromap/NitroMapView.kt +73 -0
  11. package/android/src/main/kotlin/com/margelo/nitro/nitromap/UserLocationManager.kt +295 -0
  12. package/android/src/main/kotlin/com/margelo/nitro/nitromap/clustering/ClusterIconRenderer.kt +111 -0
  13. package/android/src/main/kotlin/com/margelo/nitro/nitromap/clustering/ClusteringManager.kt +104 -0
  14. package/android/src/main/kotlin/com/margelo/nitro/nitromap/clustering/NitroClusterEngine.kt +166 -0
  15. package/android/src/main/kotlin/com/margelo/nitro/nitromap/markers/MarkerIconFactory.kt +303 -0
  16. package/android/src/main/kotlin/com/margelo/nitro/nitromap/markers/MarkerSelectionHandler.kt +72 -0
  17. package/android/src/main/kotlin/com/margelo/nitro/nitromap/markers/PriceMarkerRenderer.kt +159 -0
  18. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/MapProviderFactory.kt +24 -0
  19. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/MapProviderInterface.kt +128 -0
  20. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapDelegate.kt +317 -0
  21. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+Clustering.kt +524 -0
  22. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+Markers.kt +358 -0
  23. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+Overlays.kt +272 -0
  24. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+UserLocation.kt +296 -0
  25. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider.kt +815 -0
  26. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/MarkerTagData.kt +19 -0
  27. package/ios/Location/NitroLocationManager.swift +116 -0
  28. package/ios/MarkerRenderer/MarkerIconFactory.swift +1 -3
  29. package/ios/MarkerRenderer/PriceMarkerRenderer.swift +10 -6
  30. package/ios/NitroMap.swift +279 -13
  31. package/ios/NitroMapConfig/NitroMapConfig.swift +45 -0
  32. package/ios/Providers/{GoogleMapDelegate.swift → Google/GoogleMapDelegate.swift} +48 -23
  33. package/ios/Providers/Google/GoogleMapProvider+Camera.swift +180 -0
  34. package/ios/Providers/Google/GoogleMapProvider+Clustering.swift +541 -0
  35. package/ios/Providers/Google/GoogleMapProvider+Markers.swift +270 -0
  36. package/ios/Providers/Google/GoogleMapProvider+Overlays.swift +245 -0
  37. package/ios/Providers/Google/GoogleMapProvider+UserLocation.swift +180 -0
  38. package/ios/Providers/Google/GoogleMapProvider.swift +342 -0
  39. package/ios/Providers/MapProviderFactory.swift +17 -0
  40. package/ios/Providers/MapProviderProtocol.swift +48 -1
  41. package/ios/Shared/ClusterConfig+Factory.swift +2 -2
  42. package/ios/Shared/MapStyleProvider.swift +6 -4
  43. package/ios/Shared/MarkerSelectionHandler.swift +4 -1
  44. package/ios/Utils/ColorValueExtension.swift +46 -67
  45. package/lib/module/components/ImageMarker.js +39 -29
  46. package/lib/module/components/ImageMarker.js.map +1 -1
  47. package/lib/module/components/Marker.js +118 -0
  48. package/lib/module/components/Marker.js.map +1 -0
  49. package/lib/module/components/NitroCircle.js +92 -0
  50. package/lib/module/components/NitroCircle.js.map +1 -0
  51. package/lib/module/components/NitroMap.js +216 -76
  52. package/lib/module/components/NitroMap.js.map +1 -1
  53. package/lib/module/components/NitroPolygon.js +135 -0
  54. package/lib/module/components/NitroPolygon.js.map +1 -0
  55. package/lib/module/components/NitroPolyline.js +115 -0
  56. package/lib/module/components/NitroPolyline.js.map +1 -0
  57. package/lib/module/components/PriceMarker.js +16 -29
  58. package/lib/module/components/PriceMarker.js.map +1 -1
  59. package/lib/module/context/NitroMapContext.js.map +1 -1
  60. package/lib/module/hooks/useNitroCircle.js +18 -0
  61. package/lib/module/hooks/useNitroCircle.js.map +1 -0
  62. package/lib/module/hooks/useNitroMarker.js +26 -9
  63. package/lib/module/hooks/useNitroMarker.js.map +1 -1
  64. package/lib/module/hooks/useNitroOverlay.js +59 -0
  65. package/lib/module/hooks/useNitroOverlay.js.map +1 -0
  66. package/lib/module/hooks/useNitroPolygon.js +18 -0
  67. package/lib/module/hooks/useNitroPolygon.js.map +1 -0
  68. package/lib/module/hooks/useNitroPolyline.js +18 -0
  69. package/lib/module/hooks/useNitroPolyline.js.map +1 -0
  70. package/lib/module/index.js +5 -0
  71. package/lib/module/index.js.map +1 -1
  72. package/lib/module/types/overlay.js +4 -0
  73. package/lib/module/types/overlay.js.map +1 -0
  74. package/lib/module/types/theme.js +4 -0
  75. package/lib/module/types/theme.js.map +1 -0
  76. package/lib/module/utils/colors.js +41 -13
  77. package/lib/module/utils/colors.js.map +1 -1
  78. package/lib/module/utils/validation.js +45 -0
  79. package/lib/module/utils/validation.js.map +1 -0
  80. package/lib/typescript/src/components/ImageMarker.d.ts.map +1 -1
  81. package/lib/typescript/src/components/Marker.d.ts +34 -0
  82. package/lib/typescript/src/components/Marker.d.ts.map +1 -0
  83. package/lib/typescript/src/components/NitroCircle.d.ts +70 -0
  84. package/lib/typescript/src/components/NitroCircle.d.ts.map +1 -0
  85. package/lib/typescript/src/components/NitroMap.d.ts +60 -3
  86. package/lib/typescript/src/components/NitroMap.d.ts.map +1 -1
  87. package/lib/typescript/src/components/NitroPolygon.d.ts +86 -0
  88. package/lib/typescript/src/components/NitroPolygon.d.ts.map +1 -0
  89. package/lib/typescript/src/components/NitroPolyline.d.ts +84 -0
  90. package/lib/typescript/src/components/NitroPolyline.d.ts.map +1 -0
  91. package/lib/typescript/src/components/PriceMarker.d.ts +0 -5
  92. package/lib/typescript/src/components/PriceMarker.d.ts.map +1 -1
  93. package/lib/typescript/src/context/NitroMapContext.d.ts +2 -0
  94. package/lib/typescript/src/context/NitroMapContext.d.ts.map +1 -1
  95. package/lib/typescript/src/hooks/useNitroCircle.d.ts +7 -0
  96. package/lib/typescript/src/hooks/useNitroCircle.d.ts.map +1 -0
  97. package/lib/typescript/src/hooks/useNitroMarker.d.ts +20 -0
  98. package/lib/typescript/src/hooks/useNitroMarker.d.ts.map +1 -1
  99. package/lib/typescript/src/hooks/useNitroOverlay.d.ts +26 -0
  100. package/lib/typescript/src/hooks/useNitroOverlay.d.ts.map +1 -0
  101. package/lib/typescript/src/hooks/useNitroPolygon.d.ts +7 -0
  102. package/lib/typescript/src/hooks/useNitroPolygon.d.ts.map +1 -0
  103. package/lib/typescript/src/hooks/useNitroPolyline.d.ts +7 -0
  104. package/lib/typescript/src/hooks/useNitroPolyline.d.ts.map +1 -0
  105. package/lib/typescript/src/index.d.ts +15 -2
  106. package/lib/typescript/src/index.d.ts.map +1 -1
  107. package/lib/typescript/src/specs/NitroMap.nitro.d.ts +248 -6
  108. package/lib/typescript/src/specs/NitroMap.nitro.d.ts.map +1 -1
  109. package/lib/typescript/src/types/map.d.ts +34 -4
  110. package/lib/typescript/src/types/map.d.ts.map +1 -1
  111. package/lib/typescript/src/types/marker.d.ts +24 -36
  112. package/lib/typescript/src/types/marker.d.ts.map +1 -1
  113. package/lib/typescript/src/types/overlay.d.ts +75 -0
  114. package/lib/typescript/src/types/overlay.d.ts.map +1 -0
  115. package/lib/typescript/src/types/theme.d.ts +93 -0
  116. package/lib/typescript/src/types/theme.d.ts.map +1 -0
  117. package/lib/typescript/src/utils/colors.d.ts +6 -8
  118. package/lib/typescript/src/utils/colors.d.ts.map +1 -1
  119. package/lib/typescript/src/utils/validation.d.ts +12 -0
  120. package/lib/typescript/src/utils/validation.d.ts.map +1 -0
  121. package/nitrogen/generated/android/c++/JCircleData.hpp +94 -0
  122. package/nitrogen/generated/android/c++/JClusterConfig.hpp +5 -7
  123. package/nitrogen/generated/android/c++/JFunc_void_UserLocationChangeEvent.hpp +79 -0
  124. package/nitrogen/generated/android/c++/JFunc_void_UserTrackingMode.hpp +77 -0
  125. package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
  126. package/nitrogen/generated/android/c++/JHybridNitroMapSpec.cpp +328 -21
  127. package/nitrogen/generated/android/c++/JHybridNitroMapSpec.hpp +53 -2
  128. package/nitrogen/generated/android/c++/JMarkerAnimation.hpp +3 -6
  129. package/nitrogen/generated/android/c++/JMarkerData.hpp +15 -3
  130. package/nitrogen/generated/android/c++/JPolygonData.hpp +149 -0
  131. package/nitrogen/generated/android/c++/JPolylineData.hpp +113 -0
  132. package/nitrogen/generated/android/c++/JUserLocationChangeEvent.hpp +70 -0
  133. package/nitrogen/generated/android/c++/JUserTrackingMode.hpp +62 -0
  134. package/nitrogen/generated/android/c++/views/JHybridNitroMapStateUpdater.cpp +72 -4
  135. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/CircleData.kt +62 -0
  136. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ClusterConfig.kt +4 -4
  137. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_UserLocationChangeEvent.kt +80 -0
  138. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_UserTrackingMode.kt +80 -0
  139. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_std__string.kt +80 -0
  140. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/HybridNitroMapSpec.kt +228 -2
  141. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerAnimation.kt +1 -2
  142. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerData.kt +12 -3
  143. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/PolygonData.kt +62 -0
  144. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/PolylineData.kt +62 -0
  145. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/UserLocationChangeEvent.kt +47 -0
  146. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/{ClusterAnimationStyle.kt → UserTrackingMode.kt} +6 -8
  147. package/nitrogen/generated/android/nitromapOnLoad.cpp +6 -0
  148. package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Bridge.cpp +24 -0
  149. package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Bridge.hpp +175 -17
  150. package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Umbrella.hpp +15 -3
  151. package/nitrogen/generated/ios/c++/HybridNitroMapSpecSwift.hpp +249 -16
  152. package/nitrogen/generated/ios/c++/views/HybridNitroMapComponent.mm +90 -5
  153. package/nitrogen/generated/ios/swift/CircleData.swift +143 -0
  154. package/nitrogen/generated/ios/swift/ClusterConfig.swift +22 -15
  155. package/nitrogen/generated/ios/swift/Func_void_UserLocationChangeEvent.swift +47 -0
  156. package/nitrogen/generated/ios/swift/Func_void_UserTrackingMode.swift +47 -0
  157. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +47 -0
  158. package/nitrogen/generated/ios/swift/HybridNitroMapSpec.swift +35 -1
  159. package/nitrogen/generated/ios/swift/HybridNitroMapSpec_cxx.swift +582 -8
  160. package/nitrogen/generated/ios/swift/MarkerAnimation.swift +4 -8
  161. package/nitrogen/generated/ios/swift/MarkerData.swift +54 -2
  162. package/nitrogen/generated/ios/swift/PolygonData.swift +179 -0
  163. package/nitrogen/generated/ios/swift/PolylineData.swift +155 -0
  164. package/nitrogen/generated/ios/swift/UserLocationChangeEvent.swift +69 -0
  165. package/nitrogen/generated/ios/swift/UserTrackingMode.swift +44 -0
  166. package/nitrogen/generated/shared/c++/CircleData.hpp +113 -0
  167. package/nitrogen/generated/shared/c++/ClusterConfig.hpp +5 -8
  168. package/nitrogen/generated/shared/c++/HybridNitroMapSpec.cpp +53 -2
  169. package/nitrogen/generated/shared/c++/HybridNitroMapSpec.hpp +75 -6
  170. package/nitrogen/generated/shared/c++/MarkerAnimation.hpp +4 -8
  171. package/nitrogen/generated/shared/c++/MarkerData.hpp +14 -2
  172. package/nitrogen/generated/shared/c++/PolygonData.hpp +114 -0
  173. package/nitrogen/generated/shared/c++/PolylineData.hpp +114 -0
  174. package/nitrogen/generated/shared/c++/UserLocationChangeEvent.hpp +88 -0
  175. package/nitrogen/generated/shared/c++/UserTrackingMode.hpp +80 -0
  176. package/nitrogen/generated/shared/c++/views/HybridNitroMapComponent.cpp +216 -12
  177. package/nitrogen/generated/shared/c++/views/HybridNitroMapComponent.hpp +23 -1
  178. package/nitrogen/generated/shared/json/NitroMapConfig.json +18 -1
  179. package/package.json +36 -5
  180. package/src/components/ImageMarker.tsx +58 -42
  181. package/src/components/Marker.tsx +161 -0
  182. package/src/components/NitroCircle.tsx +183 -0
  183. package/src/components/NitroMap.tsx +328 -78
  184. package/src/components/NitroPolygon.tsx +229 -0
  185. package/src/components/NitroPolyline.tsx +208 -0
  186. package/src/components/PriceMarker.tsx +23 -48
  187. package/src/context/NitroMapContext.tsx +4 -0
  188. package/src/hooks/useNitroCircle.ts +25 -0
  189. package/src/hooks/useNitroMarker.ts +49 -10
  190. package/src/hooks/useNitroOverlay.ts +68 -0
  191. package/src/hooks/useNitroPolygon.ts +25 -0
  192. package/src/hooks/useNitroPolyline.ts +25 -0
  193. package/src/index.tsx +23 -2
  194. package/src/specs/NitroMap.nitro.ts +294 -5
  195. package/src/types/map.ts +36 -4
  196. package/src/types/marker.ts +24 -44
  197. package/src/types/overlay.ts +77 -0
  198. package/src/types/theme.ts +101 -0
  199. package/src/utils/colors.ts +48 -16
  200. package/src/utils/validation.ts +69 -0
  201. package/android/src/main/java/com/margelo/nitro/nitromap/ClusterIconGenerator.kt +0 -108
  202. package/android/src/main/java/com/margelo/nitro/nitromap/ColorUtils.kt +0 -63
  203. package/android/src/main/java/com/margelo/nitro/nitromap/HybridNitroMap.kt +0 -408
  204. package/android/src/main/java/com/margelo/nitro/nitromap/HybridNitroMapConfig.kt +0 -68
  205. package/android/src/main/java/com/margelo/nitro/nitromap/MarkerIconCache.kt +0 -176
  206. package/android/src/main/java/com/margelo/nitro/nitromap/MarkerIconFactory.kt +0 -252
  207. package/android/src/main/java/com/margelo/nitro/nitromap/clustering/NitroClusterEngine.kt +0 -252
  208. package/android/src/main/java/com/margelo/nitro/nitromap/clustering/QuadTree.kt +0 -195
  209. package/android/src/main/java/com/margelo/nitro/nitromap/providers/GoogleMapProvider.kt +0 -912
  210. package/android/src/main/java/com/margelo/nitro/nitromap/providers/MapProviderInterface.kt +0 -70
  211. package/cpp/QuadTree.hpp +0 -246
  212. package/ios/NitroMapConfig/HybridNitroMapConfig.swift +0 -33
  213. package/ios/Providers/GoogleMapProvider+Camera.swift +0 -164
  214. package/ios/Providers/GoogleMapProvider.swift +0 -924
  215. package/nitrogen/generated/android/c++/JClusterAnimationStyle.hpp +0 -68
  216. package/nitrogen/generated/ios/swift/ClusterAnimationStyle.swift +0 -52
  217. package/nitrogen/generated/shared/c++/ClusterAnimationStyle.hpp +0 -88
@@ -0,0 +1,303 @@
1
+ package com.margelo.nitro.nitromap.markers
2
+
3
+ import android.content.Context
4
+ import android.graphics.Bitmap
5
+ import android.graphics.BitmapFactory
6
+ import android.graphics.Canvas
7
+ import android.graphics.Color
8
+ import android.graphics.Paint
9
+ import android.graphics.PorterDuff
10
+ import android.graphics.PorterDuffXfermode
11
+ import android.graphics.Rect
12
+ import android.graphics.RectF
13
+ import android.util.Base64
14
+ import android.util.Log
15
+ import android.util.LruCache
16
+ import com.google.android.gms.maps.model.BitmapDescriptor
17
+ import com.google.android.gms.maps.model.BitmapDescriptorFactory
18
+ import com.margelo.nitro.nitromap.ImageMarkerConfig
19
+ import com.margelo.nitro.nitromap.MarkerData
20
+ import com.margelo.nitro.nitromap.MarkerStyle
21
+ import kotlinx.coroutines.CoroutineScope
22
+ import kotlinx.coroutines.launch
23
+ import kotlinx.coroutines.withContext
24
+ import kotlinx.coroutines.Dispatchers
25
+ import java.net.HttpURLConnection
26
+ import java.net.URL
27
+
28
+ /**
29
+ * Android equivalent of iOS MarkerIconFactory + MarkerIconCache.
30
+ *
31
+ * - Maps MarkerData → BitmapDescriptor (Google Maps icon).
32
+ * - LruCache for bitmap reuse (avoids texture exhaustion on large datasets).
33
+ * - Price markers: delegated to PriceMarkerRenderer (Canvas drawing).
34
+ * - Image markers: base64 inline or async URL loading.
35
+ */
36
+ // C-3: Accept a CoroutineScope from the provider to avoid unstructured coroutine leaks
37
+ class MarkerIconFactory(private val context: Context, private val scope: CoroutineScope) {
38
+
39
+ companion object {
40
+ private const val TAG = "MarkerIconFactory"
41
+ private const val MAX_CACHE_ENTRIES = 500
42
+ private const val URL_CACHE_ENTRIES = 200
43
+
44
+ // Cache key helpers (deterministic, stable across launches)
45
+ fun priceMarkerKey(price: String, currency: String, selected: Boolean, config: com.margelo.nitro.nitromap.PriceMarkerStyle? = null): String {
46
+ // Include color hash to prevent cross-color cache collisions
47
+ val colorHash = if (config != null) {
48
+ stableHash(buildString {
49
+ config.backgroundColor?.let { append(it.hashCode()) }
50
+ config.selectedBackgroundColor?.let { append(it.hashCode()) }
51
+ config.textColor?.let { append(it.hashCode()) }
52
+ config.selectedTextColor?.let { append(it.hashCode()) }
53
+ append(config.fontSize ?: 0.0)
54
+ })
55
+ } else 0
56
+ return "price_${price}_${currency}_${selected}_$colorHash"
57
+ }
58
+
59
+ fun imageMarkerKey(source: String, width: Double, height: Double, cornerRadius: Double): String {
60
+ val w = (width / 5).toInt() * 5 // round to nearest 5
61
+ val h = (height / 5).toInt() * 5
62
+ val r = (cornerRadius / 5).toInt() * 5
63
+ val sourceHash = stableHash(source)
64
+ return "image_${sourceHash}_${w}_${h}_${r}"
65
+ }
66
+
67
+ // L-5: Math.abs(hash) returns negative for Integer.MIN_VALUE.
68
+ // Use bitwise AND to ensure non-negative result.
69
+ private fun stableHash(s: String): Int {
70
+ var hash = 5381
71
+ for (c in s.toByteArray()) {
72
+ hash = (hash shl 5) + hash + c.toInt()
73
+ }
74
+ return hash and Int.MAX_VALUE
75
+ }
76
+ }
77
+
78
+ // Lock object for thread-safe cache access.
79
+ // LruCache is not thread-safe — all get/put/evict calls must be synchronized.
80
+ private val cacheLock = Any()
81
+
82
+ // Icon bitmap cache (BitmapDescriptor wraps Bitmap — cache the Bitmap separately)
83
+ // L-2/L-3: Override entryRemoved to recycle evicted bitmaps and prevent memory leaks
84
+ private val bitmapCache = object : LruCache<String, Bitmap>(MAX_CACHE_ENTRIES) {
85
+ override fun entryRemoved(evicted: Boolean, key: String?, oldValue: Bitmap?, newValue: Bitmap?) {
86
+ if (evicted && oldValue != null && !oldValue.isRecycled) {
87
+ oldValue.recycle()
88
+ }
89
+ }
90
+ }
91
+ // Separate URL image cache (source bitmaps before rendering)
92
+ private val urlBitmapCache = object : LruCache<String, Bitmap>(URL_CACHE_ENTRIES) {
93
+ override fun entryRemoved(evicted: Boolean, key: String?, oldValue: Bitmap?, newValue: Bitmap?) {
94
+ if (evicted && oldValue != null && !oldValue.isRecycled) {
95
+ oldValue.recycle()
96
+ }
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Callback invoked when an async URL image finishes loading.
102
+ * Passes the marker id and updated BitmapDescriptor.
103
+ */
104
+ var onIconLoaded: ((markerId: String, icon: BitmapDescriptor) -> Unit)? = null
105
+
106
+ // MARK: - Public API
107
+
108
+ fun createIcon(markerData: MarkerData): BitmapDescriptor? {
109
+ return when (markerData.config.style) {
110
+ MarkerStyle.PRICEMARKER -> createPriceMarkerIcon(markerData)
111
+ MarkerStyle.IMAGE -> createImageMarkerIcon(markerData)
112
+ MarkerStyle.DEFAULT -> null
113
+ }
114
+ }
115
+
116
+ fun clearCache() {
117
+ synchronized(cacheLock) {
118
+ bitmapCache.evictAll()
119
+ urlBitmapCache.evictAll()
120
+ }
121
+ Log.d(TAG, "Icon cache cleared")
122
+ }
123
+
124
+ // MARK: - Price Marker
125
+
126
+ private fun createPriceMarkerIcon(markerData: MarkerData): BitmapDescriptor? {
127
+ val config = markerData.config.priceMarker ?: return null
128
+ val cacheKey = priceMarkerKey(config.price, config.currency, config.selected, config)
129
+
130
+ synchronized(cacheLock) {
131
+ bitmapCache.get(cacheKey)?.let {
132
+ return BitmapDescriptorFactory.fromBitmap(it)
133
+ }
134
+ }
135
+
136
+ val bitmap = PriceMarkerRenderer.render(config, context.resources.displayMetrics)
137
+ synchronized(cacheLock) { bitmapCache.put(cacheKey, bitmap) }
138
+ return BitmapDescriptorFactory.fromBitmap(bitmap)
139
+ }
140
+
141
+ // MARK: - Image Marker
142
+
143
+ private fun createImageMarkerIcon(markerData: MarkerData): BitmapDescriptor? {
144
+ val config = markerData.config.image ?: return null
145
+ val imageSource = config.imageBase64 ?: config.imageUrl ?: return null
146
+ val cacheKey = imageMarkerKey(imageSource, config.width, config.height, config.cornerRadius)
147
+
148
+ // Cache hit
149
+ synchronized(cacheLock) {
150
+ bitmapCache.get(cacheKey)?.let {
151
+ return BitmapDescriptorFactory.fromBitmap(it)
152
+ }
153
+ }
154
+
155
+ // Base64 inline — decode synchronously
156
+ if (config.imageBase64 != null) {
157
+ val sourceBitmap = decodeBase64(config.imageBase64) ?: return null
158
+ val rendered = renderImageMarker(sourceBitmap, config)
159
+ synchronized(cacheLock) { bitmapCache.put(cacheKey, rendered) }
160
+ return BitmapDescriptorFactory.fromBitmap(rendered)
161
+ }
162
+
163
+ // URL — check URL bitmap cache first
164
+ val urlString = config.imageUrl ?: return null
165
+ val cachedUrlBitmap = synchronized(cacheLock) { urlBitmapCache.get(urlString) }
166
+ if (cachedUrlBitmap != null) {
167
+ val rendered = renderImageMarker(cachedUrlBitmap, config)
168
+ synchronized(cacheLock) { bitmapCache.put(cacheKey, rendered) }
169
+ return BitmapDescriptorFactory.fromBitmap(rendered)
170
+ }
171
+
172
+ // Async URL load — return placeholder, callback when done
173
+ loadUrlImageAsync(markerData.id, urlString, cacheKey, config)
174
+ val placeholder = createPlaceholder(config)
175
+ synchronized(cacheLock) { bitmapCache.put(cacheKey, placeholder) }
176
+ return BitmapDescriptorFactory.fromBitmap(placeholder)
177
+ }
178
+
179
+ // MARK: - Async URL Loading
180
+
181
+ private fun loadUrlImageAsync(
182
+ markerId: String,
183
+ urlString: String,
184
+ cacheKey: String,
185
+ config: ImageMarkerConfig
186
+ ) {
187
+ scope.launch {
188
+ val sourceBitmap = withContext(Dispatchers.IO) {
189
+ var connection: HttpURLConnection? = null
190
+ try {
191
+ val url = URL(urlString)
192
+ connection = url.openConnection() as HttpURLConnection
193
+ connection.connectTimeout = 10_000
194
+ connection.readTimeout = 10_000
195
+ connection.useCaches = true
196
+ connection.connect()
197
+ if (connection.responseCode !in 200..299) {
198
+ Log.w(TAG, "HTTP ${connection.responseCode} loading $urlString")
199
+ return@withContext null
200
+ }
201
+ BitmapFactory.decodeStream(connection.inputStream)
202
+ } catch (e: Exception) {
203
+ Log.w(TAG, "Failed to load image from $urlString: ${e.message}")
204
+ null
205
+ } finally {
206
+ // H-6: Always disconnect HttpURLConnection
207
+ connection?.disconnect()
208
+ }
209
+ } ?: return@launch
210
+
211
+ // Back on main thread — cache and notify
212
+ val rendered = renderImageMarker(sourceBitmap, config)
213
+ synchronized(cacheLock) {
214
+ urlBitmapCache.put(urlString, sourceBitmap)
215
+ bitmapCache.put(cacheKey, rendered)
216
+ }
217
+ onIconLoaded?.invoke(markerId, BitmapDescriptorFactory.fromBitmap(rendered))
218
+ Log.d(TAG, "Icon loaded for marker $markerId from $urlString")
219
+ }
220
+ }
221
+
222
+ // MARK: - Rendering
223
+
224
+ private fun renderImageMarker(sourceBitmap: Bitmap, config: ImageMarkerConfig): Bitmap {
225
+ val density = context.resources.displayMetrics.density
226
+ val widthPx = (config.width * density).toInt().coerceAtLeast(1)
227
+ val heightPx = (config.height * density).toInt().coerceAtLeast(1)
228
+ val radiusPx = (config.cornerRadius * density).toFloat()
229
+ val borderWidthPx = (config.borderWidth * density).toFloat()
230
+
231
+ val borderColor = PriceMarkerRenderer.resolveColorValue(
232
+ config.borderColor,
233
+ Color.rgb(200, 200, 200)
234
+ )
235
+
236
+ val output = Bitmap.createBitmap(widthPx, heightPx, Bitmap.Config.ARGB_8888)
237
+ val canvas = Canvas(output)
238
+
239
+ // Clip path for rounded corners
240
+ val rect = RectF(0f, 0f, widthPx.toFloat(), heightPx.toFloat())
241
+ val paint = Paint(Paint.ANTI_ALIAS_FLAG)
242
+
243
+ // Draw rounded rect shape as clip mask
244
+ paint.color = Color.WHITE
245
+ canvas.drawRoundRect(rect, radiusPx, radiusPx, paint)
246
+
247
+ // Draw source image using SRC_IN (clips to rounded rect)
248
+ paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
249
+ val scaled = Bitmap.createScaledBitmap(sourceBitmap, widthPx, heightPx, true)
250
+ canvas.drawBitmap(scaled, 0f, 0f, paint)
251
+ paint.xfermode = null
252
+ // L-7: Recycle the scaled intermediate bitmap if it's not the source
253
+ if (scaled !== sourceBitmap) {
254
+ scaled.recycle()
255
+ }
256
+
257
+ // Draw border
258
+ if (borderWidthPx > 0) {
259
+ val borderPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
260
+ style = Paint.Style.STROKE
261
+ color = borderColor
262
+ strokeWidth = borderWidthPx
263
+ }
264
+ // Inset border rect by half stroke width so it stays inside clip
265
+ val inset = borderWidthPx / 2f
266
+ val borderRect = RectF(inset, inset, widthPx.toFloat() - inset, heightPx.toFloat() - inset)
267
+ canvas.drawRoundRect(borderRect, radiusPx, radiusPx, borderPaint)
268
+ }
269
+
270
+ return output
271
+ }
272
+
273
+ private fun createPlaceholder(config: ImageMarkerConfig): Bitmap {
274
+ val density = context.resources.displayMetrics.density
275
+ val widthPx = (config.width * density).toInt().coerceAtLeast(1)
276
+ val heightPx = (config.height * density).toInt().coerceAtLeast(1)
277
+ val radiusPx = (config.cornerRadius * density)
278
+
279
+ val bitmap = Bitmap.createBitmap(widthPx, heightPx, Bitmap.Config.ARGB_8888)
280
+ val canvas = Canvas(bitmap)
281
+ val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
282
+ color = Color.argb((0.3f * 255).toInt(), 200, 200, 200)
283
+ }
284
+ canvas.drawRoundRect(
285
+ RectF(0f, 0f, widthPx.toFloat(), heightPx.toFloat()),
286
+ radiusPx.toFloat(), radiusPx.toFloat(),
287
+ paint
288
+ )
289
+ return bitmap
290
+ }
291
+
292
+ // MARK: - Utilities
293
+
294
+ private fun decodeBase64(base64: String): Bitmap? {
295
+ return try {
296
+ val bytes = Base64.decode(base64, Base64.DEFAULT)
297
+ BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
298
+ } catch (e: Exception) {
299
+ Log.w(TAG, "Failed to decode base64 image: ${e.message}")
300
+ null
301
+ }
302
+ }
303
+ }
@@ -0,0 +1,72 @@
1
+ package com.margelo.nitro.nitromap.markers
2
+
3
+ import com.margelo.nitro.nitromap.MarkerAnimation
4
+ import com.margelo.nitro.nitromap.MarkerConfig
5
+ import com.margelo.nitro.nitromap.MarkerData
6
+ import com.margelo.nitro.nitromap.MarkerStyle
7
+ import com.margelo.nitro.nitromap.PriceMarkerStyle
8
+
9
+ /**
10
+ * Handles marker selection state changes in a pure, immutable fashion.
11
+ *
12
+ * Mirrors iOS MarkerSelectionHandler.swift — only PriceMarker style supports
13
+ * visual selection state. All other marker types return null (no change).
14
+ *
15
+ * Thread-safe: stateless, can be called from any thread.
16
+ */
17
+ object MarkerSelectionHandler {
18
+
19
+ /**
20
+ * Creates an updated MarkerData with the new selection state applied.
21
+ *
22
+ * @return Updated marker data with the new selection state, or null if the marker
23
+ * type doesn't support visual selection state OR if the state has not changed.
24
+ */
25
+ fun updateSelectionState(markerData: MarkerData, selected: Boolean): MarkerData? {
26
+ // Only pricemarker style supports visual selection state
27
+ if (markerData.config.style != MarkerStyle.PRICEMARKER) return null
28
+ val priceConfig = markerData.config.priceMarker ?: return null
29
+
30
+ // Early exit if state hasn't changed
31
+ if (priceConfig.selected == selected) return null
32
+
33
+ // Create updated price config with new selection state (immutable copy)
34
+ val updatedPriceConfig = PriceMarkerStyle(
35
+ price = priceConfig.price,
36
+ currency = priceConfig.currency,
37
+ selected = selected,
38
+ backgroundColor = priceConfig.backgroundColor,
39
+ selectedBackgroundColor = priceConfig.selectedBackgroundColor,
40
+ textColor = priceConfig.textColor,
41
+ selectedTextColor = priceConfig.selectedTextColor,
42
+ fontSize = priceConfig.fontSize,
43
+ paddingHorizontal = priceConfig.paddingHorizontal,
44
+ paddingVertical = priceConfig.paddingVertical,
45
+ shadowOpacity = priceConfig.shadowOpacity
46
+ )
47
+
48
+ val updatedConfig = MarkerConfig(
49
+ style = markerData.config.style,
50
+ image = markerData.config.image,
51
+ priceMarker = updatedPriceConfig
52
+ )
53
+
54
+ return MarkerData(
55
+ id = markerData.id,
56
+ coordinate = markerData.coordinate,
57
+ title = markerData.title,
58
+ description = markerData.description,
59
+ draggable = markerData.draggable,
60
+ opacity = markerData.opacity,
61
+ rotation = markerData.rotation,
62
+ zIndex = markerData.zIndex,
63
+ anchor = markerData.anchor,
64
+ config = updatedConfig,
65
+ accessibilityLabel = markerData.accessibilityLabel,
66
+ clusteringEnabled = markerData.clusteringEnabled,
67
+ animation = markerData.animation,
68
+ animationDuration = markerData.animationDuration,
69
+ animateOnReappear = markerData.animateOnReappear
70
+ )
71
+ }
72
+ }
@@ -0,0 +1,159 @@
1
+ package com.margelo.nitro.nitromap.markers
2
+
3
+ import android.graphics.Bitmap
4
+ import android.graphics.Canvas
5
+ import android.graphics.Color
6
+ import android.graphics.Paint
7
+ import android.graphics.RectF
8
+ import android.graphics.Typeface
9
+ import android.util.DisplayMetrics
10
+ import android.util.TypedValue
11
+ import com.margelo.nitro.nitromap.MarkerColor
12
+ import com.margelo.nitro.nitromap.PriceMarkerStyle
13
+ import com.margelo.nitro.nitromap.Variant_String_MarkerColor
14
+
15
+ /**
16
+ * Android equivalent of iOS PriceMarkerRenderer.swift.
17
+ *
18
+ * Renders a pill-shaped label with price text.
19
+ * Uses Canvas + Paint for density-aware drawing.
20
+ * Mirrors the iOS shadow, padding, and typography.
21
+ */
22
+ object PriceMarkerRenderer {
23
+
24
+ // Default style values (match iOS defaults)
25
+ private val DEFAULT_BG_COLOR = Color.WHITE
26
+ private val DEFAULT_SELECTED_BG_COLOR = Color.rgb(255, 59, 48) // iOS red
27
+ private val DEFAULT_TEXT_COLOR = Color.rgb(51, 51, 51)
28
+ private val DEFAULT_TEXT_COLOR_SELECTED = Color.WHITE
29
+ private const val DEFAULT_FONT_SIZE_SP = 10f
30
+ private const val DEFAULT_PADDING_H_DP = 8f
31
+ private const val DEFAULT_PADDING_V_DP = 6f
32
+ private const val DEFAULT_SHADOW_OPACITY = 0.12f
33
+
34
+ // Shadow constants (match iOS: blur=8, offset=2)
35
+ private const val SHADOW_BLUR_DP = 8f
36
+ private const val SHADOW_OFFSET_DP = 2f
37
+
38
+ fun render(config: PriceMarkerStyle?, displayMetrics: DisplayMetrics): Bitmap {
39
+ val selected = config?.selected ?: false
40
+ val price = config?.price ?: "0"
41
+ val currency = config?.currency ?: ""
42
+ val text = "$price $currency"
43
+
44
+ // Colors
45
+ val bgColor = resolveColor(config?.backgroundColor, DEFAULT_BG_COLOR)
46
+ val selectedBgColor = resolveColor(config?.selectedBackgroundColor, DEFAULT_SELECTED_BG_COLOR)
47
+ val textColor = resolveColor(config?.textColor, DEFAULT_TEXT_COLOR)
48
+ val selectedTextColor = resolveColor(config?.selectedTextColor, DEFAULT_TEXT_COLOR_SELECTED)
49
+
50
+ val activeBg = if (selected) selectedBgColor else bgColor
51
+ val activeText = if (selected) selectedTextColor else textColor
52
+
53
+ // Dimensions
54
+ val density = displayMetrics.density
55
+ val fontSizePx = TypedValue.applyDimension(
56
+ TypedValue.COMPLEX_UNIT_SP,
57
+ (config?.fontSize ?: DEFAULT_FONT_SIZE_SP.toDouble()).toFloat(),
58
+ displayMetrics
59
+ )
60
+ val paddingHPx = dp2px((config?.paddingHorizontal ?: DEFAULT_PADDING_H_DP.toDouble()).toFloat(), density)
61
+ val paddingVPx = dp2px((config?.paddingVertical ?: DEFAULT_PADDING_V_DP.toDouble()).toFloat(), density)
62
+ val shadowBlurPx = dp2px(SHADOW_BLUR_DP, density)
63
+ val shadowOffsetPx = dp2px(SHADOW_OFFSET_DP, density)
64
+ val shadowOpacity = (config?.shadowOpacity ?: DEFAULT_SHADOW_OPACITY.toDouble()).toFloat()
65
+
66
+ // Measure text
67
+ val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
68
+ this.textSize = fontSizePx
69
+ typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)
70
+ }
71
+ val textWidth = textPaint.measureText(text)
72
+ val fontMetrics = textPaint.fontMetrics
73
+ val textHeight = fontMetrics.descent - fontMetrics.ascent
74
+
75
+ // Pill dimensions
76
+ val pillWidth = textWidth + paddingHPx * 2
77
+ val pillHeight = textHeight + paddingVPx * 2
78
+ val cornerRadius = pillHeight / 2f
79
+
80
+ // Canvas size — add room for shadow (match iOS: blur*2 wide, blur+offset+blur/2 tall)
81
+ val canvasWidth = (pillWidth + shadowBlurPx * 2).toInt() + 1
82
+ val canvasHeight = (pillHeight + shadowBlurPx + shadowOffsetPx + shadowBlurPx / 2).toInt() + 1
83
+
84
+ val bitmap = Bitmap.createBitmap(canvasWidth, canvasHeight, Bitmap.Config.ARGB_8888)
85
+ val canvas = Canvas(bitmap)
86
+
87
+ // Pill rect (offset inward to leave room for shadow)
88
+ val left = shadowBlurPx
89
+ val top = shadowBlurPx / 2
90
+ val pillRect = RectF(left, top, left + pillWidth, top + pillHeight)
91
+
92
+ // Shadow paint
93
+ val shadowPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
94
+ color = activeBg
95
+ setShadowLayer(
96
+ shadowBlurPx,
97
+ 0f,
98
+ shadowOffsetPx,
99
+ applyAlpha(Color.BLACK, shadowOpacity)
100
+ )
101
+ }
102
+ canvas.drawRoundRect(pillRect, cornerRadius, cornerRadius, shadowPaint)
103
+
104
+ // Background paint (overdraw without shadow so shape is crisp)
105
+ val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
106
+ color = activeBg
107
+ }
108
+ canvas.drawRoundRect(pillRect, cornerRadius, cornerRadius, bgPaint)
109
+
110
+ // Text
111
+ textPaint.color = activeText
112
+ val textX = pillRect.left + paddingHPx
113
+ val textY = pillRect.top + paddingVPx - fontMetrics.ascent
114
+ canvas.drawText(text, textX, textY, textPaint)
115
+
116
+ return bitmap
117
+ }
118
+
119
+ // MARK: - Helpers
120
+
121
+ private fun dp2px(dp: Float, density: Float) = dp * density
122
+
123
+ private fun applyAlpha(color: Int, alpha: Float): Int {
124
+ val a = (alpha * 255).toInt().coerceIn(0, 255)
125
+ return Color.argb(a, Color.red(color), Color.green(color), Color.blue(color))
126
+ }
127
+
128
+ /**
129
+ * Resolves a Variant_String_MarkerColor to an Android Color int.
130
+ * Supports hex strings (#RRGGBB / #AARRGGBB) and MarkerColor structs.
131
+ */
132
+ internal fun resolveColor(variant: Variant_String_MarkerColor?, default: Int): Int {
133
+ variant ?: return default
134
+ return variant.match(
135
+ first = { hex -> parseHexColor(hex) ?: default },
136
+ second = { mc -> markerColorToInt(mc) }
137
+ )
138
+ }
139
+
140
+ internal fun resolveColorValue(variant: com.margelo.nitro.nitromap.ColorValue?, default: Int): Int {
141
+ variant ?: return default
142
+ return variant.match(
143
+ first = { hex -> parseHexColor(hex) ?: default },
144
+ second = { mc -> markerColorToInt(mc) }
145
+ )
146
+ }
147
+
148
+ private fun parseHexColor(hex: String): Int? {
149
+ return try {
150
+ Color.parseColor(hex)
151
+ } catch (e: IllegalArgumentException) {
152
+ null
153
+ }
154
+ }
155
+
156
+ internal fun markerColorToInt(mc: MarkerColor): Int {
157
+ return Color.argb(mc.a.toInt(), mc.r.toInt(), mc.g.toInt(), mc.b.toInt())
158
+ }
159
+ }
@@ -0,0 +1,24 @@
1
+ package com.margelo.nitro.nitromap.providers
2
+
3
+ import android.content.Context
4
+ import com.margelo.nitro.nitromap.MapProvider
5
+ import com.margelo.nitro.nitromap.providers.google.GoogleMapProvider
6
+
7
+ /**
8
+ * Factory for creating map provider instances.
9
+ * Mirrors iOS MapProviderFactory.swift.
10
+ */
11
+ object MapProviderFactory {
12
+
13
+ fun create(provider: MapProvider, context: Context): MapProviderInterface {
14
+ return when (provider) {
15
+ MapProvider.GOOGLE -> GoogleMapProvider(context)
16
+ MapProvider.APPLE -> throw UnsupportedOperationException(
17
+ "Apple Maps provider is not available on Android"
18
+ )
19
+ MapProvider.YANDEX -> throw UnsupportedOperationException(
20
+ "Yandex Maps provider is not yet implemented"
21
+ )
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,128 @@
1
+ package com.margelo.nitro.nitromap.providers
2
+
3
+ import android.content.Context
4
+ import android.view.View
5
+ import com.margelo.nitro.nitromap.*
6
+
7
+ /**
8
+ * Interface that all map providers must implement.
9
+ * Mirrors iOS MapProviderProtocol.swift.
10
+ *
11
+ * Allows the library to support multiple map backends (Google, Apple, Yandex).
12
+ * Implementation details (command queues, async map init, native view subclasses)
13
+ * stay internal to each provider.
14
+ */
15
+ interface MapProviderInterface {
16
+
17
+ // MARK: - View Lifecycle
18
+
19
+ /** Create the underlying map view. Provider manages its own saved state. */
20
+ fun createMapView(context: Context): View
21
+
22
+ /** Called after the map view is added to the container. Provider starts async map init here. */
23
+ fun onViewAttached(view: View)
24
+
25
+ /** Called when the view is detached. Provider should pause and save state, but keep data. */
26
+ fun onViewDetaching()
27
+
28
+ /** Called on dispose. Provider should perform full cleanup. */
29
+ fun onViewDestroying()
30
+
31
+ // MARK: - Properties
32
+
33
+ var initialRegion: Region?
34
+ var region: Region?
35
+ var showsUserLocation: Boolean?
36
+ var zoomEnabled: Boolean?
37
+ var scrollEnabled: Boolean?
38
+ var rotateEnabled: Boolean?
39
+ var pitchEnabled: Boolean?
40
+ var mapType: MapType?
41
+ /** Currently uses Google Maps JSON format. Will need provider-specific handling for Apple/Yandex. */
42
+ var customMapStyle: Array<MapStyleElement>?
43
+ var clusterConfig: ClusterConfig?
44
+ var mapPadding: EdgePadding
45
+ var showsTraffic: Boolean?
46
+ var showsBuildings: Boolean?
47
+ var showsCompass: Boolean?
48
+ var minZoom: Double
49
+ var maxZoom: Double
50
+ var darkMode: Boolean?
51
+ var userTrackingMode: UserTrackingMode?
52
+ var userLocationImage: String
53
+ var userLocationSize: Double
54
+ var userLocationAnchor: Point?
55
+
56
+ // MARK: - Callbacks
57
+
58
+ var onPress: ((MapPressEvent) -> Unit)?
59
+ var onLongPress: ((MapPressEvent) -> Unit)?
60
+ var onMapReadyCallback: (() -> Unit)?
61
+ var onRegionChange: ((RegionChangeEvent) -> Unit)?
62
+ var onRegionChangeComplete: ((RegionChangeEvent) -> Unit)?
63
+ var onMarkerPress: ((MarkerPressEvent) -> Unit)?
64
+ var onMarkerDragStart: ((MarkerDragEvent) -> Unit)?
65
+ var onMarkerDrag: ((MarkerDragEvent) -> Unit)?
66
+ var onMarkerDragEnd: ((MarkerDragEvent) -> Unit)?
67
+ var onClusterPress: ((ClusterPressEvent) -> Unit)?
68
+ var onPolylinePress: ((String) -> Unit)?
69
+ var onPolygonPress: ((String) -> Unit)?
70
+ var onCirclePress: ((String) -> Unit)?
71
+ var onError: ((MapError) -> Unit)?
72
+ var onMapIdle: (() -> Unit)?
73
+ var onUserLocationChange: ((UserLocationChangeEvent) -> Unit)?
74
+ var onUserTrackingModeChange: ((UserTrackingMode) -> Unit)?
75
+ var onUserLocationError: ((MapError) -> Unit)?
76
+
77
+ // MARK: - User Location
78
+
79
+ fun updateUserLocation(location: android.location.Location, heading: Float?)
80
+ fun setupCustomUserLocationMarker(context: Context)
81
+ /** Disable user location display and clean up location-related resources. */
82
+ fun disableUserLocation()
83
+
84
+ // MARK: - Camera
85
+
86
+ fun animateToRegion(region: Region, duration: Double?)
87
+ fun fitToCoordinates(coordinates: Array<Coordinate>, edgePadding: EdgePadding?, animated: Boolean?)
88
+ fun fitToSuppliedMarkers(markerIds: Array<String>, edgePadding: EdgePadding?, animated: Boolean?)
89
+ fun animateCamera(camera: Camera, duration: Double?)
90
+ fun setCamera(camera: Camera)
91
+ fun getCamera(): Camera
92
+ fun getMapBoundaries(): MapBoundaries?
93
+ fun pointForCoordinate(coordinate: Coordinate): Point
94
+ fun coordinateForPoint(point: Point): Coordinate
95
+ fun centerOnUserLocation()
96
+
97
+ // MARK: - Markers
98
+
99
+ fun addMarker(marker: MarkerData)
100
+ fun addMarkers(markers: Array<MarkerData>)
101
+ fun updateMarker(marker: MarkerData)
102
+ fun removeMarker(id: String)
103
+ fun clearMarkers()
104
+ fun selectMarker(id: String)
105
+ fun deselectMarker()
106
+
107
+ // MARK: - Clustering
108
+
109
+ fun setClusteringEnabled(enabled: Boolean)
110
+ fun refreshClusters()
111
+
112
+ // MARK: - Overlays
113
+
114
+ fun addPolyline(polyline: PolylineData)
115
+ fun updatePolyline(polyline: PolylineData)
116
+ fun removePolyline(id: String)
117
+ fun clearPolylines()
118
+
119
+ fun addPolygon(polygon: PolygonData)
120
+ fun updatePolygon(polygon: PolygonData)
121
+ fun removePolygon(id: String)
122
+ fun clearPolygons()
123
+
124
+ fun addCircle(circle: CircleData)
125
+ fun updateCircle(circle: CircleData)
126
+ fun removeCircle(id: String)
127
+ fun clearCircles()
128
+ }