@lugg/maps 0.2.0-alpha.9 → 1.0.0-beta.1

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 (184) hide show
  1. package/README.md +21 -20
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/luggmaps/LuggCalloutView.kt +74 -0
  4. package/android/src/main/java/com/luggmaps/LuggCalloutViewManager.kt +38 -0
  5. package/android/src/main/java/com/luggmaps/LuggMapView.kt +290 -0
  6. package/android/src/main/java/com/luggmaps/{LuggGoogleMapViewManager.kt → LuggMapViewManager.kt} +99 -36
  7. package/android/src/main/java/com/luggmaps/LuggMapWrapperView.kt +11 -14
  8. package/android/src/main/java/com/luggmaps/LuggMarkerView.kt +187 -21
  9. package/android/src/main/java/com/luggmaps/LuggMarkerViewManager.kt +28 -0
  10. package/android/src/main/java/com/luggmaps/LuggPackage.kt +8 -4
  11. package/android/src/main/java/com/luggmaps/LuggPolygonView.kt +85 -0
  12. package/android/src/main/java/com/luggmaps/LuggPolygonViewManager.kt +100 -0
  13. package/android/src/main/java/com/luggmaps/LuggPolylineView.kt +16 -0
  14. package/android/src/main/java/com/luggmaps/LuggPolylineViewManager.kt +22 -0
  15. package/android/src/main/java/com/luggmaps/core/GoogleMapProvider.kt +874 -0
  16. package/android/src/main/java/com/luggmaps/core/MapProviderDelegate.kt +60 -0
  17. package/android/src/main/java/com/luggmaps/core/PolylineAnimator.kt +89 -24
  18. package/android/src/main/java/com/luggmaps/events/LongPressEvent.kt +29 -0
  19. package/android/src/main/java/com/luggmaps/events/MarkerDragEvent.kt +41 -0
  20. package/android/src/main/java/com/luggmaps/events/MarkerPressEvent.kt +34 -0
  21. package/android/src/main/java/com/luggmaps/events/PolygonPressEvent.kt +12 -0
  22. package/android/src/main/java/com/luggmaps/events/PressEvent.kt +29 -0
  23. package/ios/LuggCalloutView.h +23 -0
  24. package/ios/LuggCalloutView.mm +145 -0
  25. package/ios/LuggMapView.h +9 -0
  26. package/ios/LuggMapView.mm +343 -0
  27. package/ios/LuggMarkerView.h +15 -0
  28. package/ios/LuggMarkerView.mm +136 -2
  29. package/ios/LuggPolygonView.h +31 -0
  30. package/ios/LuggPolygonView.mm +151 -0
  31. package/ios/LuggPolylineView.h +4 -0
  32. package/ios/LuggPolylineView.mm +23 -0
  33. package/ios/core/AppleMapProvider.h +15 -0
  34. package/ios/core/AppleMapProvider.mm +1173 -0
  35. package/ios/core/GMSPolylineAnimator.h +3 -0
  36. package/ios/core/GMSPolylineAnimator.m +101 -15
  37. package/ios/core/GoogleMapProvider.h +13 -0
  38. package/ios/core/GoogleMapProvider.mm +798 -0
  39. package/ios/core/LuggAnnotationView.h +12 -0
  40. package/ios/core/LuggAnnotationView.mm +55 -0
  41. package/ios/core/MKPolylineAnimator.h +4 -0
  42. package/ios/core/MKPolylineAnimator.m +167 -42
  43. package/ios/core/MapProviderDelegate.h +84 -0
  44. package/ios/core/PolylineAnimatorBase.h +24 -1
  45. package/ios/core/PolylineAnimatorBase.m +82 -19
  46. package/ios/events/LongPressEvent.h +29 -0
  47. package/ios/events/MarkerDragEvent.h +69 -0
  48. package/ios/events/MarkerPressEvent.h +29 -0
  49. package/ios/events/PolygonPressEvent.h +20 -0
  50. package/ios/events/PressEvent.h +29 -0
  51. package/ios/extensions/MKMapView+Zoom.h +2 -0
  52. package/ios/extensions/MKMapView+Zoom.m +14 -4
  53. package/lib/module/MapProvider.js +2 -4
  54. package/lib/module/MapProvider.js.map +1 -1
  55. package/lib/module/MapProvider.web.js +14 -7
  56. package/lib/module/MapProvider.web.js.map +1 -1
  57. package/lib/module/MapView.js +33 -16
  58. package/lib/module/MapView.js.map +1 -1
  59. package/lib/module/MapView.web.js +296 -181
  60. package/lib/module/MapView.web.js.map +1 -1
  61. package/lib/module/components/GeoJson.js +159 -0
  62. package/lib/module/components/GeoJson.js.map +1 -0
  63. package/lib/module/components/GeoJson.types.js +4 -0
  64. package/lib/module/components/GeoJson.types.js.map +1 -0
  65. package/lib/module/components/Marker.js +49 -8
  66. package/lib/module/components/Marker.js.map +1 -1
  67. package/lib/module/components/Marker.types.js +4 -0
  68. package/lib/module/components/Marker.types.js.map +1 -0
  69. package/lib/module/components/Marker.web.js +159 -24
  70. package/lib/module/components/Marker.web.js.map +1 -1
  71. package/lib/module/components/Polygon.js +46 -0
  72. package/lib/module/components/Polygon.js.map +1 -0
  73. package/lib/module/components/Polygon.types.js +4 -0
  74. package/lib/module/components/Polygon.types.js.map +1 -0
  75. package/lib/module/components/Polygon.web.js +87 -0
  76. package/lib/module/components/Polygon.web.js.map +1 -0
  77. package/lib/module/components/Polyline.js +17 -4
  78. package/lib/module/components/Polyline.js.map +1 -1
  79. package/lib/module/components/Polyline.types.js +4 -0
  80. package/lib/module/components/Polyline.types.js.map +1 -0
  81. package/lib/module/components/Polyline.web.js +108 -31
  82. package/lib/module/components/Polyline.web.js.map +1 -1
  83. package/lib/module/components/index.js +4 -2
  84. package/lib/module/components/index.js.map +1 -1
  85. package/lib/module/components/index.web.js +2 -0
  86. package/lib/module/components/index.web.js.map +1 -1
  87. package/lib/module/fabric/LuggCalloutViewNativeComponent.ts +20 -0
  88. package/lib/module/fabric/{LuggGoogleMapViewNativeComponent.ts → LuggMapViewNativeComponent.ts} +43 -7
  89. package/lib/module/fabric/LuggMarkerViewNativeComponent.ts +49 -1
  90. package/lib/module/fabric/LuggPolygonViewNativeComponent.ts +25 -0
  91. package/lib/module/fabric/LuggPolylineViewNativeComponent.ts +8 -0
  92. package/lib/module/index.js +4 -1
  93. package/lib/module/index.js.map +1 -1
  94. package/lib/module/index.web.js +4 -1
  95. package/lib/module/index.web.js.map +1 -1
  96. package/lib/typescript/src/MapProvider.d.ts +1 -1
  97. package/lib/typescript/src/MapProvider.d.ts.map +1 -1
  98. package/lib/typescript/src/MapProvider.web.d.ts +23 -1
  99. package/lib/typescript/src/MapProvider.web.d.ts.map +1 -1
  100. package/lib/typescript/src/MapView.d.ts +4 -4
  101. package/lib/typescript/src/MapView.d.ts.map +1 -1
  102. package/lib/typescript/src/MapView.types.d.ts +35 -9
  103. package/lib/typescript/src/MapView.types.d.ts.map +1 -1
  104. package/lib/typescript/src/MapView.web.d.ts +2 -11
  105. package/lib/typescript/src/MapView.web.d.ts.map +1 -1
  106. package/lib/typescript/src/components/GeoJson.d.ts +4 -0
  107. package/lib/typescript/src/components/GeoJson.d.ts.map +1 -0
  108. package/lib/typescript/src/components/GeoJson.types.d.ts +89 -0
  109. package/lib/typescript/src/components/GeoJson.types.d.ts.map +1 -0
  110. package/lib/typescript/src/components/Marker.d.ts +6 -33
  111. package/lib/typescript/src/components/Marker.d.ts.map +1 -1
  112. package/lib/typescript/src/components/Marker.types.d.ts +100 -0
  113. package/lib/typescript/src/components/Marker.types.d.ts.map +1 -0
  114. package/lib/typescript/src/components/Marker.web.d.ts +2 -5
  115. package/lib/typescript/src/components/Marker.web.d.ts.map +1 -1
  116. package/lib/typescript/src/components/Polygon.d.ts +10 -0
  117. package/lib/typescript/src/components/Polygon.d.ts.map +1 -0
  118. package/lib/typescript/src/components/Polygon.types.d.ts +33 -0
  119. package/lib/typescript/src/components/Polygon.types.d.ts.map +1 -0
  120. package/lib/typescript/src/components/Polygon.web.d.ts +3 -0
  121. package/lib/typescript/src/components/Polygon.web.d.ts.map +1 -0
  122. package/lib/typescript/src/components/Polyline.d.ts +6 -21
  123. package/lib/typescript/src/components/Polyline.d.ts.map +1 -1
  124. package/lib/typescript/src/components/Polyline.types.d.ts +53 -0
  125. package/lib/typescript/src/components/Polyline.types.d.ts.map +1 -0
  126. package/lib/typescript/src/components/Polyline.web.d.ts +2 -5
  127. package/lib/typescript/src/components/Polyline.web.d.ts.map +1 -1
  128. package/lib/typescript/src/components/index.d.ts +8 -2
  129. package/lib/typescript/src/components/index.d.ts.map +1 -1
  130. package/lib/typescript/src/components/index.web.d.ts +6 -2
  131. package/lib/typescript/src/components/index.web.d.ts.map +1 -1
  132. package/lib/typescript/src/fabric/LuggCalloutViewNativeComponent.d.ts +13 -0
  133. package/lib/typescript/src/fabric/LuggCalloutViewNativeComponent.d.ts.map +1 -0
  134. package/lib/typescript/src/fabric/{LuggGoogleMapViewNativeComponent.d.ts → LuggMapViewNativeComponent.d.ts} +30 -4
  135. package/lib/typescript/src/fabric/LuggMapViewNativeComponent.d.ts.map +1 -0
  136. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts +45 -1
  137. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts.map +1 -1
  138. package/lib/typescript/src/fabric/LuggPolygonViewNativeComponent.d.ts +18 -0
  139. package/lib/typescript/src/fabric/LuggPolygonViewNativeComponent.d.ts.map +1 -0
  140. package/lib/typescript/src/fabric/LuggPolylineViewNativeComponent.d.ts +7 -0
  141. package/lib/typescript/src/fabric/LuggPolylineViewNativeComponent.d.ts.map +1 -1
  142. package/lib/typescript/src/index.d.ts +11 -3
  143. package/lib/typescript/src/index.d.ts.map +1 -1
  144. package/lib/typescript/src/index.web.d.ts +9 -1
  145. package/lib/typescript/src/index.web.d.ts.map +1 -1
  146. package/lib/typescript/src/types.d.ts +11 -0
  147. package/lib/typescript/src/types.d.ts.map +1 -1
  148. package/package.json +11 -9
  149. package/src/MapProvider.tsx +1 -3
  150. package/src/MapProvider.web.tsx +22 -3
  151. package/src/MapView.tsx +32 -26
  152. package/src/MapView.types.ts +43 -9
  153. package/src/MapView.web.tsx +368 -210
  154. package/src/components/GeoJson.tsx +221 -0
  155. package/src/components/GeoJson.types.ts +118 -0
  156. package/src/components/Marker.tsx +75 -38
  157. package/src/components/Marker.types.ts +102 -0
  158. package/src/components/Marker.web.tsx +197 -19
  159. package/src/components/Polygon.tsx +52 -0
  160. package/src/components/Polygon.types.ts +33 -0
  161. package/src/components/Polygon.web.tsx +104 -0
  162. package/src/components/Polyline.tsx +23 -22
  163. package/src/components/Polyline.types.ts +55 -0
  164. package/src/components/Polyline.web.tsx +151 -37
  165. package/src/components/index.ts +17 -2
  166. package/src/components/index.web.ts +6 -2
  167. package/src/fabric/LuggCalloutViewNativeComponent.ts +20 -0
  168. package/src/fabric/{LuggGoogleMapViewNativeComponent.ts → LuggMapViewNativeComponent.ts} +43 -7
  169. package/src/fabric/LuggMarkerViewNativeComponent.ts +49 -1
  170. package/src/fabric/LuggPolygonViewNativeComponent.ts +25 -0
  171. package/src/fabric/LuggPolylineViewNativeComponent.ts +8 -0
  172. package/src/index.ts +30 -1
  173. package/src/index.web.ts +16 -1
  174. package/src/types.ts +13 -0
  175. package/android/src/main/java/com/luggmaps/LuggGoogleMapView.kt +0 -511
  176. package/ios/LuggAppleMapView.h +0 -16
  177. package/ios/LuggAppleMapView.mm +0 -592
  178. package/ios/LuggGoogleMapView.h +0 -13
  179. package/ios/LuggGoogleMapView.mm +0 -455
  180. package/lib/module/fabric/LuggAppleMapViewNativeComponent.ts +0 -83
  181. package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts +0 -54
  182. package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts.map +0 -1
  183. package/lib/typescript/src/fabric/LuggGoogleMapViewNativeComponent.d.ts.map +0 -1
  184. package/src/fabric/LuggAppleMapViewNativeComponent.ts +0 -83
@@ -0,0 +1,874 @@
1
+ package com.luggmaps.core
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.Context
5
+ import android.view.View
6
+ import android.widget.ImageView
7
+ import androidx.core.graphics.createBitmap
8
+ import com.facebook.react.uimanager.PixelUtil.dpToPx
9
+ import com.google.android.gms.maps.CameraUpdateFactory
10
+ import com.google.android.gms.maps.GoogleMap
11
+ import com.google.android.gms.maps.GoogleMapOptions
12
+ import com.google.android.gms.maps.MapView
13
+ import com.google.android.gms.maps.OnMapReadyCallback
14
+ import com.google.android.gms.maps.model.AdvancedMarker
15
+ import com.google.android.gms.maps.model.AdvancedMarkerOptions
16
+ import com.google.android.gms.maps.model.BitmapDescriptorFactory
17
+ import com.google.android.gms.maps.model.LatLng
18
+ import com.google.android.gms.maps.model.MapColorScheme
19
+ import com.google.android.gms.maps.model.Marker
20
+ import com.google.android.gms.maps.model.Polygon
21
+ import com.google.android.gms.maps.model.PolygonOptions
22
+ import com.google.android.gms.maps.model.PolylineOptions
23
+ import com.luggmaps.LuggCalloutView
24
+ import com.luggmaps.LuggMapWrapperView
25
+ import com.luggmaps.LuggMarkerView
26
+ import com.luggmaps.LuggMarkerViewDelegate
27
+ import com.luggmaps.LuggPolygonView
28
+ import com.luggmaps.LuggPolygonViewDelegate
29
+ import com.luggmaps.LuggPolylineView
30
+ import com.luggmaps.LuggPolylineViewDelegate
31
+
32
+ class GoogleMapProvider(private val context: Context) :
33
+ MapProvider,
34
+ OnMapReadyCallback,
35
+ LuggMarkerViewDelegate,
36
+ LuggPolylineViewDelegate,
37
+ LuggPolygonViewDelegate,
38
+ GoogleMap.OnCameraMoveStartedListener,
39
+ GoogleMap.OnCameraMoveListener,
40
+ GoogleMap.OnCameraIdleListener,
41
+ GoogleMap.OnMapClickListener,
42
+ GoogleMap.OnMapLongClickListener,
43
+ GoogleMap.OnPolygonClickListener,
44
+ GoogleMap.OnMarkerClickListener,
45
+ GoogleMap.OnMarkerDragListener,
46
+ GoogleMap.InfoWindowAdapter {
47
+
48
+ override var delegate: MapProviderDelegate? = null
49
+ override val isMapReady: Boolean get() = _isMapReady
50
+
51
+ var mapId: String = DEMO_MAP_ID
52
+
53
+ private var wrapperView: LuggMapWrapperView? = null
54
+ private var mapView: MapView? = null
55
+ private var googleMap: GoogleMap? = null
56
+ private var _isMapReady = false
57
+ private var isDragging = false
58
+ private val pendingMarkerViews = mutableSetOf<LuggMarkerView>()
59
+ private val pendingPolylineViews = mutableSetOf<LuggPolylineView>()
60
+ private val pendingPolygonViews = mutableSetOf<LuggPolygonView>()
61
+ private val polylineAnimators = mutableMapOf<LuggPolylineView, PolylineAnimator>()
62
+ private val polygonToViewMap = mutableMapOf<Polygon, LuggPolygonView>()
63
+ private val markerToViewMap = mutableMapOf<Marker, LuggMarkerView>()
64
+ private val liveMarkerViews = mutableSetOf<LuggMarkerView>()
65
+ private var activeNonBubbledMarker: Marker? = null
66
+ private var tapLocation: LatLng? = null
67
+
68
+ // Initial camera settings
69
+ private var initialLatitude: Double = 0.0
70
+ private var initialLongitude: Double = 0.0
71
+ private var initialZoom: Float = 10f
72
+
73
+ // UI settings
74
+ private var zoomEnabled: Boolean = true
75
+ private var scrollEnabled: Boolean = true
76
+ private var rotateEnabled: Boolean = true
77
+ private var pitchEnabled: Boolean = true
78
+ private var userLocationEnabled: Boolean = false
79
+ private var userLocationButtonEnabled: Boolean = false
80
+
81
+ // Zoom limits
82
+ private var minZoom: Float? = null
83
+ private var maxZoom: Float? = null
84
+
85
+ // Theme
86
+ private var theme: String = "system"
87
+
88
+ // Edge Insets
89
+ private var edgeInsets: EdgeInsets = EdgeInsets()
90
+
91
+ // region MapProvider
92
+
93
+ override fun initializeMap(wrapperView: View, latitude: Double, longitude: Double, zoom: Float) {
94
+ if (mapView != null) return
95
+
96
+ initialLatitude = latitude
97
+ initialLongitude = longitude
98
+ initialZoom = zoom
99
+
100
+ val wrapper = wrapperView as LuggMapWrapperView
101
+ this.wrapperView = wrapper
102
+
103
+ val options = GoogleMapOptions().mapId(mapId)
104
+ mapView = MapView(context, options).also { view ->
105
+ view.onCreate(null)
106
+ view.onResume()
107
+ view.getMapAsync(this)
108
+ wrapper.addView(view)
109
+ }
110
+ }
111
+
112
+ override fun destroy() {
113
+ dismissNonBubbledCallout()
114
+ for (markerView in liveMarkerViews) {
115
+ markerView.onUpdate = null
116
+ }
117
+ liveMarkerViews.clear()
118
+ pendingMarkerViews.clear()
119
+ pendingPolylineViews.clear()
120
+ pendingPolygonViews.clear()
121
+ polylineAnimators.values.forEach { it.destroy() }
122
+ polylineAnimators.clear()
123
+ polygonToViewMap.clear()
124
+ markerToViewMap.clear()
125
+ wrapperView?.touchEventHandler = null
126
+ wrapperView = null
127
+ googleMap?.setOnCameraMoveStartedListener(null)
128
+ googleMap?.setOnCameraMoveListener(null)
129
+ googleMap?.setOnCameraIdleListener(null)
130
+ googleMap?.setOnMapClickListener(null)
131
+ googleMap?.setOnMapLongClickListener(null)
132
+ googleMap?.setOnPolygonClickListener(null)
133
+ googleMap?.setOnMarkerClickListener(null)
134
+ googleMap?.setOnMarkerDragListener(null)
135
+ googleMap?.setInfoWindowAdapter(null)
136
+ googleMap?.clear()
137
+ googleMap = null
138
+ _isMapReady = false
139
+ mapView?.onPause()
140
+ mapView?.onDestroy()
141
+ mapView = null
142
+ }
143
+
144
+ override fun onMapReady(map: GoogleMap) {
145
+ googleMap = map
146
+ _isMapReady = true
147
+
148
+ val position = LatLng(initialLatitude, initialLongitude)
149
+ map.moveCamera(CameraUpdateFactory.newLatLngZoom(position, initialZoom))
150
+
151
+ map.setOnCameraMoveStartedListener(this)
152
+ map.setOnCameraMoveListener(this)
153
+ map.setOnCameraIdleListener(this)
154
+ map.setOnMapClickListener(this)
155
+ map.setOnMapLongClickListener(this)
156
+ map.setOnPolygonClickListener(this)
157
+ map.setOnMarkerClickListener(this)
158
+ map.setOnMarkerDragListener(this)
159
+ map.setInfoWindowAdapter(this)
160
+
161
+ wrapperView?.touchEventHandler = { event ->
162
+ if (event.action == android.view.MotionEvent.ACTION_DOWN) {
163
+ tapLocation = map.projection.fromScreenLocation(android.graphics.Point(event.x.toInt(), event.y.toInt()))
164
+ }
165
+ }
166
+
167
+ applyUiSettings()
168
+ applyZoomLimits()
169
+ applyEdgeInsets()
170
+ applyTheme()
171
+ applyUserLocation()
172
+ processPendingMarkers()
173
+ processPendingPolylines()
174
+ processPendingPolygons()
175
+
176
+ delegate?.mapProviderDidReady()
177
+ }
178
+
179
+ // endregion
180
+
181
+ // region Camera Listeners
182
+
183
+ override fun onCameraMoveStarted(reason: Int) {
184
+ isDragging = reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE
185
+ if (isDragging) {
186
+ polylineAnimators.values.forEach { it.pause() }
187
+ }
188
+ }
189
+
190
+ override fun onCameraMove() {
191
+ val map = googleMap ?: return
192
+ val position = map.cameraPosition
193
+ delegate?.mapProviderDidMoveCamera(position.target.latitude, position.target.longitude, position.zoom, isDragging)
194
+ positionLiveMarkers()
195
+ positionNonBubbledCallout()
196
+ }
197
+
198
+ override fun onCameraIdle() {
199
+ val map = googleMap ?: return
200
+ val position = map.cameraPosition
201
+ delegate?.mapProviderDidIdleCamera(position.target.latitude, position.target.longitude, position.zoom, isDragging)
202
+ if (isDragging) {
203
+ polylineAnimators.values.forEach { it.resume() }
204
+ }
205
+ isDragging = false
206
+ }
207
+
208
+ override fun onMapClick(latLng: LatLng) {
209
+ dismissNonBubbledCallout()
210
+ val map = googleMap ?: return
211
+ val point = map.projection.toScreenLocation(latLng)
212
+ delegate?.mapProviderDidPress(latLng.latitude, latLng.longitude, point.x.toFloat(), point.y.toFloat())
213
+ }
214
+
215
+ override fun onMapLongClick(latLng: LatLng) {
216
+ val map = googleMap ?: return
217
+ val point = map.projection.toScreenLocation(latLng)
218
+ delegate?.mapProviderDidLongPress(latLng.latitude, latLng.longitude, point.x.toFloat(), point.y.toFloat())
219
+ }
220
+
221
+ override fun onPolygonClick(polygon: Polygon) {
222
+ val polygonView = polygonToViewMap[polygon]
223
+ if (polygonView?.tappable == true) {
224
+ polygonView.emitPressEvent()
225
+ } else {
226
+ onMapClick(tapLocation ?: return)
227
+ }
228
+ }
229
+
230
+ override fun onMarkerClick(marker: Marker): Boolean {
231
+ dismissNonBubbledCallout()
232
+
233
+ markerToViewMap[marker]?.let { view ->
234
+ val point = googleMap?.projection?.toScreenLocation(marker.position)
235
+ view.emitPressEvent(point?.x?.toFloat() ?: 0f, point?.y?.toFloat() ?: 0f)
236
+
237
+ val calloutView = view.calloutView
238
+ if (calloutView != null && !calloutView.bubbled && calloutView.hasCustomContent) {
239
+ googleMap?.animateCamera(CameraUpdateFactory.newLatLng(marker.position))
240
+ showNonBubbledCallout(marker, calloutView)
241
+ return true
242
+ }
243
+ }
244
+ return false
245
+ }
246
+
247
+ override fun onMarkerDragStart(marker: Marker) {
248
+ markerToViewMap[marker]?.let { view ->
249
+ view.isDragging = true
250
+ view.setCoordinate(marker.position.latitude, marker.position.longitude)
251
+ val point = googleMap?.projection?.toScreenLocation(marker.position)
252
+ view.emitDragStartEvent(point?.x?.toFloat() ?: 0f, point?.y?.toFloat() ?: 0f)
253
+ if (!view.rasterize) positionLiveMarker(view)
254
+ }
255
+ }
256
+
257
+ override fun onMarkerDrag(marker: Marker) {
258
+ markerToViewMap[marker]?.let { view ->
259
+ view.setCoordinate(marker.position.latitude, marker.position.longitude)
260
+ val point = googleMap?.projection?.toScreenLocation(marker.position)
261
+ view.emitDragChangeEvent(point?.x?.toFloat() ?: 0f, point?.y?.toFloat() ?: 0f)
262
+ if (!view.rasterize) positionLiveMarker(view)
263
+ }
264
+ }
265
+
266
+ override fun onMarkerDragEnd(marker: Marker) {
267
+ markerToViewMap[marker]?.let { view ->
268
+ view.isDragging = false
269
+ view.setCoordinate(marker.position.latitude, marker.position.longitude)
270
+ val point = googleMap?.projection?.toScreenLocation(marker.position)
271
+ view.emitDragEndEvent(point?.x?.toFloat() ?: 0f, point?.y?.toFloat() ?: 0f)
272
+ if (!view.rasterize) positionLiveMarker(view)
273
+ }
274
+ }
275
+
276
+ override fun getInfoWindow(marker: Marker): View? {
277
+ // Non-bubbled callouts are rendered as live views, not info windows
278
+ return null
279
+ }
280
+
281
+ override fun getInfoContents(marker: Marker): View? {
282
+ val markerView = markerToViewMap[marker] ?: return null
283
+ val calloutView = markerView.calloutView ?: return null
284
+ if (!calloutView.hasCustomContent || !calloutView.bubbled) return null
285
+
286
+ val bitmap = calloutView.createContentBitmap() ?: return null
287
+ return ImageView(context).apply { setImageBitmap(bitmap) }
288
+ }
289
+
290
+ private fun showNonBubbledCallout(marker: Marker, calloutView: LuggCalloutView) {
291
+ val wrapper = wrapperView ?: return
292
+ val contentView = calloutView.contentView
293
+
294
+ calloutView.onUpdate = {
295
+ layoutNonBubbledCallout()
296
+ positionNonBubbledCallout()
297
+ }
298
+
299
+ dismissInfoWindows()
300
+ wrapper.addView(contentView)
301
+ activeNonBubbledMarker = marker
302
+ layoutNonBubbledCallout()
303
+ positionNonBubbledCallout()
304
+ }
305
+
306
+ private fun dismissInfoWindows() {
307
+ for ((marker, _) in markerToViewMap) {
308
+ if (marker.isInfoWindowShown) {
309
+ marker.hideInfoWindow()
310
+ }
311
+ }
312
+ }
313
+
314
+ private fun dismissNonBubbledCallout() {
315
+ val marker = activeNonBubbledMarker ?: return
316
+ val markerView = markerToViewMap[marker] ?: return
317
+ val calloutView = markerView.calloutView ?: return
318
+ val contentView = calloutView.contentView
319
+
320
+ calloutView.onUpdate = null
321
+ (contentView.parent as? android.view.ViewGroup)?.removeView(contentView)
322
+ activeNonBubbledMarker = null
323
+ }
324
+
325
+ private fun layoutNonBubbledCallout() {
326
+ val marker = activeNonBubbledMarker ?: return
327
+ val markerView = markerToViewMap[marker] ?: return
328
+ val calloutView = markerView.calloutView ?: return
329
+ val contentView = calloutView.contentView
330
+
331
+ var contentWidth = 0
332
+ var contentHeight = 0
333
+ for (i in 0 until contentView.childCount) {
334
+ val child = contentView.getChildAt(i)
335
+ val childRight = child.left + child.width
336
+ val childBottom = child.top + child.height
337
+ if (childRight > contentWidth) contentWidth = childRight
338
+ if (childBottom > contentHeight) contentHeight = childBottom
339
+ }
340
+
341
+ contentView.measure(
342
+ View.MeasureSpec.makeMeasureSpec(contentWidth, View.MeasureSpec.EXACTLY),
343
+ View.MeasureSpec.makeMeasureSpec(contentHeight, View.MeasureSpec.EXACTLY)
344
+ )
345
+ contentView.layout(0, 0, contentWidth, contentHeight)
346
+ }
347
+
348
+ private fun positionNonBubbledCallout() {
349
+ val marker = activeNonBubbledMarker ?: return
350
+ val markerView = markerToViewMap[marker] ?: return
351
+ val calloutView = markerView.calloutView ?: return
352
+ val contentView = calloutView.contentView
353
+ val map = googleMap ?: return
354
+
355
+ val point = map.projection.toScreenLocation(marker.position)
356
+ contentView.translationX = point.x - contentView.width * calloutView.anchorX
357
+ contentView.translationY = point.y - contentView.height * calloutView.anchorY
358
+ }
359
+
360
+ // endregion
361
+
362
+ // region Props
363
+
364
+ override fun setZoomEnabled(enabled: Boolean) {
365
+ zoomEnabled = enabled
366
+ googleMap?.uiSettings?.isZoomGesturesEnabled = enabled
367
+ }
368
+
369
+ override fun setScrollEnabled(enabled: Boolean) {
370
+ scrollEnabled = enabled
371
+ googleMap?.uiSettings?.isScrollGesturesEnabled = enabled
372
+ }
373
+
374
+ override fun setRotateEnabled(enabled: Boolean) {
375
+ rotateEnabled = enabled
376
+ googleMap?.uiSettings?.isRotateGesturesEnabled = enabled
377
+ }
378
+
379
+ override fun setPitchEnabled(enabled: Boolean) {
380
+ pitchEnabled = enabled
381
+ googleMap?.uiSettings?.isTiltGesturesEnabled = enabled
382
+ }
383
+
384
+ @SuppressLint("MissingPermission")
385
+ override fun setUserLocationEnabled(enabled: Boolean) {
386
+ userLocationEnabled = enabled
387
+ val hasPermission =
388
+ context.checkSelfPermission(
389
+ android.Manifest.permission.ACCESS_FINE_LOCATION
390
+ ) == android.content.pm.PackageManager.PERMISSION_GRANTED ||
391
+ context.checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) ==
392
+ android.content.pm.PackageManager.PERMISSION_GRANTED
393
+ googleMap?.isMyLocationEnabled = userLocationEnabled && hasPermission
394
+ }
395
+
396
+ override fun setUserLocationButtonEnabled(enabled: Boolean) {
397
+ userLocationButtonEnabled = enabled
398
+ googleMap?.uiSettings?.isMyLocationButtonEnabled = enabled
399
+ }
400
+
401
+ override fun setTheme(value: String) {
402
+ theme = value
403
+ applyTheme()
404
+ }
405
+
406
+ override fun setMinZoom(zoom: Double) {
407
+ minZoom = if (zoom > 0) zoom.toFloat() else null
408
+ googleMap?.let { map ->
409
+ minZoom?.let { map.setMinZoomPreference(it) } ?: map.resetMinMaxZoomPreference()
410
+ }
411
+ }
412
+
413
+ override fun setMaxZoom(zoom: Double) {
414
+ maxZoom = if (zoom > 0) zoom.toFloat() else null
415
+ googleMap?.let { map ->
416
+ maxZoom?.let { map.setMaxZoomPreference(it) } ?: map.resetMinMaxZoomPreference()
417
+ }
418
+ }
419
+
420
+ override fun setEdgeInsets(edgeInsets: EdgeInsets) {
421
+ val oldInsets = this.edgeInsets
422
+ this.edgeInsets = edgeInsets
423
+ applyEdgeInsets()
424
+
425
+ val map = googleMap
426
+ if (map != null && oldInsets != edgeInsets) {
427
+ mapView?.post {
428
+ setEdgeInsets(edgeInsets, 0)
429
+ }
430
+ }
431
+ }
432
+
433
+ override fun setEdgeInsets(edgeInsets: EdgeInsets, duration: Int) {
434
+ val map = googleMap
435
+ val oldInsets = this.edgeInsets
436
+ this.edgeInsets = edgeInsets
437
+
438
+ if (map != null && oldInsets != edgeInsets) {
439
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(map.cameraPosition)
440
+ applyEdgeInsets()
441
+ when {
442
+ duration < 0 -> map.animateCamera(cameraUpdate)
443
+ duration > 0 -> map.animateCamera(cameraUpdate, duration, null)
444
+ else -> map.moveCamera(cameraUpdate)
445
+ }
446
+ } else {
447
+ applyEdgeInsets()
448
+ }
449
+ }
450
+
451
+ // endregion
452
+
453
+ // region MarkerViewDelegate
454
+
455
+ override fun markerViewDidLayout(markerView: LuggMarkerView) {
456
+ if (googleMap == null) {
457
+ pendingMarkerViews.add(markerView)
458
+ return
459
+ }
460
+
461
+ if (markerView.hasCustomView) {
462
+ markerView.updateIcon { addMarkerViewToMap(markerView) }
463
+ } else {
464
+ syncMarkerView(markerView)
465
+ }
466
+ }
467
+
468
+ override fun markerViewDidUpdate(markerView: LuggMarkerView) {
469
+ syncMarkerView(markerView)
470
+ }
471
+
472
+ // endregion
473
+
474
+ // region PolylineViewDelegate
475
+
476
+ override fun polylineViewDidUpdate(polylineView: LuggPolylineView) {
477
+ syncPolylineView(polylineView)
478
+ }
479
+
480
+ // endregion
481
+
482
+ // region PolygonViewDelegate
483
+
484
+ override fun polygonViewDidUpdate(polygonView: LuggPolygonView) {
485
+ syncPolygonView(polygonView)
486
+ }
487
+
488
+ // endregion
489
+
490
+ // region Marker Management
491
+
492
+ override fun addMarkerView(markerView: LuggMarkerView) {
493
+ markerView.delegate = this
494
+ syncMarkerView(markerView)
495
+ }
496
+
497
+ override fun removeMarkerView(markerView: LuggMarkerView) {
498
+ removeLiveMarker(markerView)
499
+ markerView.marker?.let { markerToViewMap.remove(it) }
500
+ markerView.marker?.remove()
501
+ markerView.marker = null
502
+ }
503
+
504
+ private fun syncMarkerView(markerView: LuggMarkerView) {
505
+ if (googleMap == null) {
506
+ pendingMarkerViews.add(markerView)
507
+ return
508
+ }
509
+
510
+ if (markerView.marker == null) {
511
+ if (markerView.hasCustomView) return
512
+ addMarkerViewToMap(markerView)
513
+ return
514
+ }
515
+
516
+ markerView.marker?.apply {
517
+ if (!markerView.isDragging) {
518
+ position = LatLng(markerView.latitude, markerView.longitude)
519
+ }
520
+ title = markerView.title
521
+ snippet = markerView.description
522
+ setAnchor(markerView.anchorX, markerView.anchorY)
523
+ zIndex = markerView.zIndex
524
+ rotation = markerView.rotate
525
+ isDraggable = markerView.draggable
526
+ }
527
+
528
+ if (markerView.hasCustomView) {
529
+ if (markerView.scaleChanged) {
530
+ markerView.applyScaleToMarker()
531
+ markerView.clearScaleChanged()
532
+ }
533
+ if (!markerView.rasterize) {
534
+ positionLiveMarker(markerView)
535
+ }
536
+ }
537
+ }
538
+
539
+ private fun processPendingMarkers() {
540
+ if (googleMap == null) return
541
+ pendingMarkerViews.forEach { addMarkerViewToMap(it) }
542
+ pendingMarkerViews.clear()
543
+ }
544
+
545
+ private fun addMarkerViewToMap(markerView: LuggMarkerView) {
546
+ val map = googleMap ?: return
547
+
548
+ val position = LatLng(markerView.latitude, markerView.longitude)
549
+ val options = AdvancedMarkerOptions()
550
+ .position(position)
551
+ .title(markerView.title)
552
+ .snippet(markerView.description)
553
+
554
+ val marker = map.addMarker(options) as AdvancedMarker
555
+ marker.setAnchor(markerView.anchorX, markerView.anchorY)
556
+ marker.zIndex = markerView.zIndex
557
+ marker.rotation = markerView.rotate
558
+ marker.isDraggable = markerView.draggable
559
+
560
+ markerView.marker = marker
561
+ markerToViewMap[marker] = markerView
562
+
563
+ if (markerView.hasCustomView) {
564
+ if (markerView.rasterize) {
565
+ markerView.applyIconToMarker()
566
+ } else {
567
+ showLiveMarker(markerView)
568
+ }
569
+ }
570
+ }
571
+
572
+ // Workaround: AdvancedMarker.iconView is buggy on Android, so we manually add the custom
573
+ // content view to the wrapper and position it via screen projection instead. The underlying
574
+ // marker uses a transparent bitmap matching the content size so taps still trigger onMarkerClick.
575
+ private fun showLiveMarker(markerView: LuggMarkerView) {
576
+ val wrapper = wrapperView ?: return
577
+
578
+ markerView.onUpdate = {
579
+ updateLiveMarkerHitArea(markerView)
580
+ positionLiveMarker(markerView)
581
+ }
582
+
583
+ val contentView = markerView.contentView
584
+ contentView.pointerEvents = com.facebook.react.uimanager.PointerEvents.NONE
585
+ (contentView.parent as? android.view.ViewGroup)?.removeView(contentView)
586
+ wrapper.addView(contentView)
587
+ liveMarkerViews.add(markerView)
588
+ markerView.layoutContentView()
589
+ updateLiveMarkerHitArea(markerView)
590
+ positionLiveMarker(markerView)
591
+ }
592
+
593
+ private fun updateLiveMarkerHitArea(markerView: LuggMarkerView) {
594
+ val marker = markerView.marker ?: return
595
+ val contentView = markerView.contentView
596
+ val w = contentView.width.coerceAtLeast(1)
597
+ val h = contentView.height.coerceAtLeast(1)
598
+ marker.setIcon(BitmapDescriptorFactory.fromBitmap(createBitmap(w, h)))
599
+ }
600
+
601
+ private fun removeLiveMarker(markerView: LuggMarkerView) {
602
+ markerView.onUpdate = null
603
+ val contentView = markerView.contentView
604
+ (contentView.parent as? android.view.ViewGroup)?.removeView(contentView)
605
+ liveMarkerViews.remove(markerView)
606
+ }
607
+
608
+ private fun positionLiveMarkers() {
609
+ for (markerView in liveMarkerViews) {
610
+ positionLiveMarker(markerView)
611
+ }
612
+ }
613
+
614
+ private fun positionLiveMarker(markerView: LuggMarkerView) {
615
+ val map = googleMap ?: return
616
+ val contentView = markerView.contentView
617
+ val point = map.projection.toScreenLocation(LatLng(markerView.latitude, markerView.longitude))
618
+ contentView.translationX = point.x - contentView.width * markerView.anchorX
619
+ contentView.translationY = point.y - contentView.height * markerView.anchorY
620
+ }
621
+
622
+ // endregion
623
+
624
+ // region Polyline Management
625
+
626
+ override fun addPolylineView(polylineView: LuggPolylineView) {
627
+ polylineView.delegate = this
628
+ syncPolylineView(polylineView)
629
+ }
630
+
631
+ override fun removePolylineView(polylineView: LuggPolylineView) {
632
+ polylineAnimators[polylineView]?.destroy()
633
+ polylineAnimators.remove(polylineView)
634
+ polylineView.polyline?.remove()
635
+ polylineView.polyline = null
636
+ }
637
+
638
+ private fun syncPolylineView(polylineView: LuggPolylineView) {
639
+ if (googleMap == null) {
640
+ pendingPolylineViews.add(polylineView)
641
+ return
642
+ }
643
+
644
+ if (polylineView.polyline == null) {
645
+ addPolylineViewToMap(polylineView)
646
+ return
647
+ }
648
+
649
+ polylineView.polyline?.width = polylineView.strokeWidth.dpToPx()
650
+ polylineView.polyline?.zIndex = polylineView.zIndex
651
+
652
+ polylineAnimators[polylineView]?.apply {
653
+ coordinates = polylineView.coordinates
654
+ strokeColors = polylineView.strokeColors
655
+ strokeWidth = polylineView.strokeWidth.dpToPx()
656
+ animatedOptions = polylineView.animatedOptions
657
+ animated = polylineView.animated
658
+ update()
659
+ }
660
+ }
661
+
662
+ private fun processPendingPolylines() {
663
+ if (googleMap == null) return
664
+ pendingPolylineViews.forEach { addPolylineViewToMap(it) }
665
+ pendingPolylineViews.clear()
666
+ }
667
+
668
+ private fun addPolylineViewToMap(polylineView: LuggPolylineView) {
669
+ val map = googleMap ?: return
670
+
671
+ val options = PolylineOptions()
672
+ .width(polylineView.strokeWidth.dpToPx())
673
+ .zIndex(polylineView.zIndex)
674
+
675
+ val polyline = map.addPolyline(options)
676
+ polylineView.polyline = polyline
677
+
678
+ val animator = PolylineAnimator().apply {
679
+ this.polyline = polyline
680
+ coordinates = polylineView.coordinates
681
+ strokeColors = polylineView.strokeColors
682
+ strokeWidth = polylineView.strokeWidth.dpToPx()
683
+ animatedOptions = polylineView.animatedOptions
684
+ animated = polylineView.animated
685
+ update()
686
+ }
687
+
688
+ polylineAnimators[polylineView] = animator
689
+ }
690
+
691
+ // endregion
692
+
693
+ // region Polygon Management
694
+
695
+ override fun addPolygonView(polygonView: LuggPolygonView) {
696
+ polygonView.delegate = this
697
+ syncPolygonView(polygonView)
698
+ }
699
+
700
+ override fun removePolygonView(polygonView: LuggPolygonView) {
701
+ polygonView.polygon?.let { polygonToViewMap.remove(it) }
702
+ polygonView.polygon?.remove()
703
+ polygonView.polygon = null
704
+ }
705
+
706
+ private fun syncPolygonView(polygonView: LuggPolygonView) {
707
+ if (googleMap == null) {
708
+ pendingPolygonViews.add(polygonView)
709
+ return
710
+ }
711
+
712
+ if (polygonView.polygon == null) {
713
+ addPolygonViewToMap(polygonView)
714
+ return
715
+ }
716
+
717
+ polygonView.polygon?.apply {
718
+ points = polygonView.coordinates
719
+ holes = polygonView.holes
720
+ fillColor = polygonView.fillColor
721
+ strokeColor = polygonView.strokeColor
722
+ strokeWidth = polygonView.strokeWidth.dpToPx()
723
+ zIndex = polygonView.zIndex
724
+ isClickable = true
725
+ }
726
+ }
727
+
728
+ private fun processPendingPolygons() {
729
+ if (googleMap == null) return
730
+ pendingPolygonViews.forEach { addPolygonViewToMap(it) }
731
+ pendingPolygonViews.clear()
732
+ }
733
+
734
+ private fun addPolygonViewToMap(polygonView: LuggPolygonView) {
735
+ val map = googleMap ?: return
736
+
737
+ val options = PolygonOptions()
738
+ .addAll(polygonView.coordinates)
739
+ .fillColor(polygonView.fillColor)
740
+ .strokeColor(polygonView.strokeColor)
741
+ .strokeWidth(polygonView.strokeWidth.dpToPx())
742
+ .zIndex(polygonView.zIndex)
743
+ .clickable(true)
744
+
745
+ for (hole in polygonView.holes) {
746
+ options.addHole(hole)
747
+ }
748
+
749
+ val polygon = map.addPolygon(options)
750
+ polygonView.polygon = polygon
751
+ polygonToViewMap[polygon] = polygonView
752
+ }
753
+
754
+ // endregion
755
+
756
+ // region Lifecycle
757
+
758
+ override fun pauseAnimations() {
759
+ polylineAnimators.values.forEach { it.pause() }
760
+ }
761
+
762
+ override fun resumeAnimations() {
763
+ polylineAnimators.values.forEach { it.resume() }
764
+ }
765
+
766
+ // endregion
767
+
768
+ // region Commands
769
+
770
+ override fun moveCamera(latitude: Double, longitude: Double, zoom: Double, duration: Int) {
771
+ val map = googleMap ?: return
772
+ val position = LatLng(latitude, longitude)
773
+ val targetZoom = if (zoom > 0) zoom.toFloat() else map.cameraPosition.zoom
774
+ val cameraUpdate = CameraUpdateFactory.newLatLngZoom(position, targetZoom)
775
+ when {
776
+ duration < 0 -> map.animateCamera(cameraUpdate)
777
+ duration > 0 -> map.animateCamera(cameraUpdate, duration, null)
778
+ else -> map.moveCamera(cameraUpdate)
779
+ }
780
+ }
781
+
782
+ override fun fitCoordinates(
783
+ coordinates: List<Any>,
784
+ edgeInsetsTop: Int,
785
+ edgeInsetsLeft: Int,
786
+ edgeInsetsBottom: Int,
787
+ edgeInsetsRight: Int,
788
+ duration: Int
789
+ ) {
790
+ val map = googleMap ?: return
791
+ if (coordinates.isEmpty()) return
792
+
793
+ val latLngs = coordinates.filterIsInstance<LatLng>()
794
+ if (latLngs.isEmpty()) return
795
+
796
+ val boundsBuilder = com.google.android.gms.maps.model.LatLngBounds.Builder()
797
+ latLngs.forEach { boundsBuilder.include(it) }
798
+ val bounds = boundsBuilder.build()
799
+
800
+ val top = edgeInsetsTop.toFloat().dpToPx().toInt()
801
+ val left = edgeInsetsLeft.toFloat().dpToPx().toInt()
802
+ val bottom = edgeInsetsBottom.toFloat().dpToPx().toInt()
803
+ val right = edgeInsetsRight.toFloat().dpToPx().toInt()
804
+
805
+ map.setPadding(
806
+ edgeInsets.left + left,
807
+ edgeInsets.top + top,
808
+ edgeInsets.right + right,
809
+ edgeInsets.bottom + bottom
810
+ )
811
+
812
+ val cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 0)
813
+
814
+ when {
815
+ duration < 0 -> map.animateCamera(cameraUpdate)
816
+ duration > 0 -> map.animateCamera(cameraUpdate, duration, null)
817
+ else -> map.moveCamera(cameraUpdate)
818
+ }
819
+
820
+ map.setPadding(edgeInsets.left, edgeInsets.top, edgeInsets.right, edgeInsets.bottom)
821
+ }
822
+
823
+ // endregion
824
+
825
+ // region Private
826
+
827
+ private fun applyUiSettings() {
828
+ googleMap?.uiSettings?.apply {
829
+ isZoomGesturesEnabled = zoomEnabled
830
+ isScrollGesturesEnabled = scrollEnabled
831
+ isRotateGesturesEnabled = rotateEnabled
832
+ isTiltGesturesEnabled = pitchEnabled
833
+ isMyLocationButtonEnabled = userLocationButtonEnabled
834
+ }
835
+ }
836
+
837
+ private fun applyZoomLimits() {
838
+ googleMap?.apply {
839
+ minZoom?.let { setMinZoomPreference(it) }
840
+ maxZoom?.let { setMaxZoomPreference(it) }
841
+ }
842
+ }
843
+
844
+ private fun applyEdgeInsets() {
845
+ googleMap?.setPadding(edgeInsets.left, edgeInsets.top, edgeInsets.right, edgeInsets.bottom)
846
+ }
847
+
848
+ private fun applyTheme() {
849
+ val colorScheme = when (theme) {
850
+ "dark" -> MapColorScheme.DARK
851
+ "light" -> MapColorScheme.LIGHT
852
+ else -> MapColorScheme.FOLLOW_SYSTEM
853
+ }
854
+ googleMap?.setMapColorScheme(colorScheme)
855
+ }
856
+
857
+ @SuppressLint("MissingPermission")
858
+ private fun applyUserLocation() {
859
+ val hasPermission =
860
+ context.checkSelfPermission(
861
+ android.Manifest.permission.ACCESS_FINE_LOCATION
862
+ ) == android.content.pm.PackageManager.PERMISSION_GRANTED ||
863
+ context.checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) ==
864
+ android.content.pm.PackageManager.PERMISSION_GRANTED
865
+ googleMap?.isMyLocationEnabled = userLocationEnabled && hasPermission
866
+ googleMap?.uiSettings?.isMyLocationButtonEnabled = userLocationButtonEnabled
867
+ }
868
+
869
+ // endregion
870
+
871
+ companion object {
872
+ const val DEMO_MAP_ID = "DEMO_MAP_ID"
873
+ }
874
+ }