@lugg/maps 1.0.0-beta.3 → 1.0.0-beta.5

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 (153) hide show
  1. package/README.md +3 -0
  2. package/android/src/main/java/com/luggmaps/LuggCalloutView.kt +4 -2
  3. package/android/src/main/java/com/luggmaps/LuggCalloutViewManager.kt +4 -3
  4. package/android/src/main/java/com/luggmaps/LuggCircleView.kt +85 -0
  5. package/android/src/main/java/com/luggmaps/LuggCircleViewManager.kt +79 -0
  6. package/android/src/main/java/com/luggmaps/LuggGroundOverlayView.kt +81 -0
  7. package/android/src/main/java/com/luggmaps/LuggGroundOverlayViewManager.kt +82 -0
  8. package/android/src/main/java/com/luggmaps/LuggMapView.kt +49 -0
  9. package/android/src/main/java/com/luggmaps/LuggMapViewManager.kt +31 -0
  10. package/android/src/main/java/com/luggmaps/LuggMarkerView.kt +23 -0
  11. package/android/src/main/java/com/luggmaps/LuggMarkerViewManager.kt +13 -0
  12. package/android/src/main/java/com/luggmaps/LuggPackage.kt +4 -1
  13. package/android/src/main/java/com/luggmaps/LuggTileOverlayView.kt +92 -0
  14. package/android/src/main/java/com/luggmaps/LuggTileOverlayViewManager.kt +80 -0
  15. package/android/src/main/java/com/luggmaps/core/GoogleMapProvider.kt +451 -17
  16. package/android/src/main/java/com/luggmaps/core/MapProviderDelegate.kt +14 -0
  17. package/android/src/main/java/com/luggmaps/events/CirclePressEvent.kt +12 -0
  18. package/android/src/main/java/com/luggmaps/events/GroundOverlayPressEvent.kt +12 -0
  19. package/android/src/main/java/com/luggmaps/events/TileOverlayPressEvent.kt +12 -0
  20. package/android/src/main/java/com/luggmaps/extensions/ViewExtensions.kt +11 -0
  21. package/ios/LuggCalloutView.h +1 -1
  22. package/ios/LuggCalloutView.mm +21 -11
  23. package/ios/LuggCircleView.h +31 -0
  24. package/ios/LuggCircleView.mm +133 -0
  25. package/ios/LuggGroundOverlayView.h +30 -0
  26. package/ios/LuggGroundOverlayView.mm +125 -0
  27. package/ios/LuggMapView.mm +84 -2
  28. package/ios/LuggMarkerView.h +3 -0
  29. package/ios/LuggMarkerView.mm +23 -0
  30. package/ios/LuggTileOverlayView.h +31 -0
  31. package/ios/LuggTileOverlayView.mm +130 -0
  32. package/ios/core/AppleMapProvider.mm +595 -17
  33. package/ios/core/GoogleMapProvider.mm +390 -28
  34. package/ios/core/MapProviderDelegate.h +20 -1
  35. package/ios/events/CirclePressEvent.h +20 -0
  36. package/ios/events/GroundOverlayPressEvent.h +20 -0
  37. package/ios/events/TileOverlayPressEvent.h +20 -0
  38. package/lib/module/MapView.js +11 -0
  39. package/lib/module/MapView.js.map +1 -1
  40. package/lib/module/MapView.web.js +3 -0
  41. package/lib/module/MapView.web.js.map +1 -1
  42. package/lib/module/components/Circle.js +46 -0
  43. package/lib/module/components/Circle.js.map +1 -0
  44. package/lib/module/components/Circle.types.js +4 -0
  45. package/lib/module/components/Circle.types.js.map +1 -0
  46. package/lib/module/components/Circle.web.js +79 -0
  47. package/lib/module/components/Circle.web.js.map +1 -0
  48. package/lib/module/components/GroundOverlay.js +45 -0
  49. package/lib/module/components/GroundOverlay.js.map +1 -0
  50. package/lib/module/components/GroundOverlay.types.js +4 -0
  51. package/lib/module/components/GroundOverlay.types.js.map +1 -0
  52. package/lib/module/components/GroundOverlay.web.js +77 -0
  53. package/lib/module/components/GroundOverlay.web.js.map +1 -0
  54. package/lib/module/components/Marker.js +22 -4
  55. package/lib/module/components/Marker.js.map +1 -1
  56. package/lib/module/components/Marker.web.js +20 -7
  57. package/lib/module/components/Marker.web.js.map +1 -1
  58. package/lib/module/components/TileOverlay.js +44 -0
  59. package/lib/module/components/TileOverlay.js.map +1 -0
  60. package/lib/module/components/TileOverlay.types.js +4 -0
  61. package/lib/module/components/TileOverlay.types.js.map +1 -0
  62. package/lib/module/components/TileOverlay.web.js +69 -0
  63. package/lib/module/components/TileOverlay.web.js.map +1 -0
  64. package/lib/module/components/index.js +3 -0
  65. package/lib/module/components/index.js.map +1 -1
  66. package/lib/module/components/index.web.js +3 -0
  67. package/lib/module/components/index.web.js.map +1 -1
  68. package/lib/module/fabric/LuggCalloutViewNativeComponent.ts +1 -1
  69. package/lib/module/fabric/LuggCircleViewNativeComponent.ts +25 -0
  70. package/lib/module/fabric/LuggGroundOverlayViewNativeComponent.ts +29 -0
  71. package/lib/module/fabric/LuggMapViewNativeComponent.ts +9 -1
  72. package/lib/module/fabric/LuggMarkerViewNativeComponent.ts +14 -2
  73. package/lib/module/fabric/LuggTileOverlayViewNativeComponent.ts +30 -0
  74. package/lib/module/index.js +3 -0
  75. package/lib/module/index.js.map +1 -1
  76. package/lib/module/index.web.js +3 -0
  77. package/lib/module/index.web.js.map +1 -1
  78. package/lib/typescript/src/MapView.d.ts.map +1 -1
  79. package/lib/typescript/src/MapView.types.d.ts +36 -1
  80. package/lib/typescript/src/MapView.types.d.ts.map +1 -1
  81. package/lib/typescript/src/MapView.web.d.ts.map +1 -1
  82. package/lib/typescript/src/components/Circle.d.ts +10 -0
  83. package/lib/typescript/src/components/Circle.d.ts.map +1 -0
  84. package/lib/typescript/src/components/Circle.types.d.ts +33 -0
  85. package/lib/typescript/src/components/Circle.types.d.ts.map +1 -0
  86. package/lib/typescript/src/components/Circle.web.d.ts +3 -0
  87. package/lib/typescript/src/components/Circle.web.d.ts.map +1 -0
  88. package/lib/typescript/src/components/GroundOverlay.d.ts +10 -0
  89. package/lib/typescript/src/components/GroundOverlay.d.ts.map +1 -0
  90. package/lib/typescript/src/components/GroundOverlay.types.d.ts +35 -0
  91. package/lib/typescript/src/components/GroundOverlay.types.d.ts.map +1 -0
  92. package/lib/typescript/src/components/GroundOverlay.web.d.ts +3 -0
  93. package/lib/typescript/src/components/GroundOverlay.web.d.ts.map +1 -0
  94. package/lib/typescript/src/components/Marker.d.ts +6 -3
  95. package/lib/typescript/src/components/Marker.d.ts.map +1 -1
  96. package/lib/typescript/src/components/Marker.types.d.ts +18 -6
  97. package/lib/typescript/src/components/Marker.types.d.ts.map +1 -1
  98. package/lib/typescript/src/components/Marker.web.d.ts +3 -2
  99. package/lib/typescript/src/components/Marker.web.d.ts.map +1 -1
  100. package/lib/typescript/src/components/TileOverlay.d.ts +10 -0
  101. package/lib/typescript/src/components/TileOverlay.d.ts.map +1 -0
  102. package/lib/typescript/src/components/TileOverlay.types.d.ts +36 -0
  103. package/lib/typescript/src/components/TileOverlay.types.d.ts.map +1 -0
  104. package/lib/typescript/src/components/TileOverlay.web.d.ts +3 -0
  105. package/lib/typescript/src/components/TileOverlay.web.d.ts.map +1 -0
  106. package/lib/typescript/src/components/index.d.ts +7 -1
  107. package/lib/typescript/src/components/index.d.ts.map +1 -1
  108. package/lib/typescript/src/components/index.web.d.ts +6 -0
  109. package/lib/typescript/src/components/index.web.d.ts.map +1 -1
  110. package/lib/typescript/src/fabric/LuggCalloutViewNativeComponent.d.ts +1 -1
  111. package/lib/typescript/src/fabric/LuggCircleViewNativeComponent.d.ts +18 -0
  112. package/lib/typescript/src/fabric/LuggCircleViewNativeComponent.d.ts.map +1 -0
  113. package/lib/typescript/src/fabric/LuggGroundOverlayViewNativeComponent.d.ts +21 -0
  114. package/lib/typescript/src/fabric/LuggGroundOverlayViewNativeComponent.d.ts.map +1 -0
  115. package/lib/typescript/src/fabric/LuggMapViewNativeComponent.d.ts +6 -1
  116. package/lib/typescript/src/fabric/LuggMapViewNativeComponent.d.ts.map +1 -1
  117. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts +8 -1
  118. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts.map +1 -1
  119. package/lib/typescript/src/fabric/LuggTileOverlayViewNativeComponent.d.ts +21 -0
  120. package/lib/typescript/src/fabric/LuggTileOverlayViewNativeComponent.d.ts.map +1 -0
  121. package/lib/typescript/src/index.d.ts +9 -3
  122. package/lib/typescript/src/index.d.ts.map +1 -1
  123. package/lib/typescript/src/index.web.d.ts +7 -1
  124. package/lib/typescript/src/index.web.d.ts.map +1 -1
  125. package/lib/typescript/src/types.d.ts +0 -4
  126. package/lib/typescript/src/types.d.ts.map +1 -1
  127. package/package.json +5 -2
  128. package/src/MapView.tsx +11 -0
  129. package/src/MapView.types.ts +85 -1
  130. package/src/MapView.web.tsx +11 -0
  131. package/src/components/Circle.tsx +52 -0
  132. package/src/components/Circle.types.ts +33 -0
  133. package/src/components/Circle.web.tsx +93 -0
  134. package/src/components/GroundOverlay.tsx +47 -0
  135. package/src/components/GroundOverlay.types.ts +36 -0
  136. package/src/components/GroundOverlay.web.tsx +85 -0
  137. package/src/components/Marker.tsx +32 -6
  138. package/src/components/Marker.types.ts +19 -6
  139. package/src/components/Marker.web.tsx +191 -148
  140. package/src/components/TileOverlay.tsx +44 -0
  141. package/src/components/TileOverlay.types.ts +37 -0
  142. package/src/components/TileOverlay.web.tsx +95 -0
  143. package/src/components/index.ts +10 -0
  144. package/src/components/index.web.ts +9 -0
  145. package/src/fabric/LuggCalloutViewNativeComponent.ts +1 -1
  146. package/src/fabric/LuggCircleViewNativeComponent.ts +25 -0
  147. package/src/fabric/LuggGroundOverlayViewNativeComponent.ts +29 -0
  148. package/src/fabric/LuggMapViewNativeComponent.ts +9 -1
  149. package/src/fabric/LuggMarkerViewNativeComponent.ts +14 -2
  150. package/src/fabric/LuggTileOverlayViewNativeComponent.ts +30 -0
  151. package/src/index.ts +12 -1
  152. package/src/index.web.ts +15 -0
  153. package/src/types.ts +0 -5
@@ -1,10 +1,14 @@
1
1
  package com.luggmaps.core
2
2
 
3
3
  import android.annotation.SuppressLint
4
+ import android.content.ComponentCallbacks2
4
5
  import android.content.Context
6
+ import android.content.res.Configuration
5
7
  import android.view.View
6
8
  import android.widget.ImageView
7
9
  import androidx.core.graphics.createBitmap
10
+ import androidx.core.view.ViewCompat
11
+ import androidx.core.view.WindowInsetsCompat
8
12
  import com.facebook.react.uimanager.PixelUtil.dpToPx
9
13
  import com.google.android.gms.maps.CameraUpdateFactory
10
14
  import com.google.android.gms.maps.GoogleMap
@@ -14,13 +18,24 @@ import com.google.android.gms.maps.OnMapReadyCallback
14
18
  import com.google.android.gms.maps.model.AdvancedMarker
15
19
  import com.google.android.gms.maps.model.AdvancedMarkerOptions
16
20
  import com.google.android.gms.maps.model.BitmapDescriptorFactory
21
+ import com.google.android.gms.maps.model.Circle
22
+ import com.google.android.gms.maps.model.CircleOptions
23
+ import com.google.android.gms.maps.model.GroundOverlay
24
+ import com.google.android.gms.maps.model.GroundOverlayOptions
17
25
  import com.google.android.gms.maps.model.LatLng
26
+ import com.google.android.gms.maps.model.LatLngBounds
18
27
  import com.google.android.gms.maps.model.MapColorScheme
19
28
  import com.google.android.gms.maps.model.Marker
20
29
  import com.google.android.gms.maps.model.Polygon
21
30
  import com.google.android.gms.maps.model.PolygonOptions
22
31
  import com.google.android.gms.maps.model.PolylineOptions
32
+ import com.google.android.gms.maps.model.TileOverlayOptions
33
+ import com.google.android.gms.maps.model.UrlTileProvider
23
34
  import com.luggmaps.LuggCalloutView
35
+ import com.luggmaps.LuggCircleView
36
+ import com.luggmaps.LuggCircleViewDelegate
37
+ import com.luggmaps.LuggGroundOverlayView
38
+ import com.luggmaps.LuggGroundOverlayViewDelegate
24
39
  import com.luggmaps.LuggMapWrapperView
25
40
  import com.luggmaps.LuggMarkerView
26
41
  import com.luggmaps.LuggMarkerViewDelegate
@@ -28,6 +43,13 @@ import com.luggmaps.LuggPolygonView
28
43
  import com.luggmaps.LuggPolygonViewDelegate
29
44
  import com.luggmaps.LuggPolylineView
30
45
  import com.luggmaps.LuggPolylineViewDelegate
46
+ import com.luggmaps.LuggTileOverlayView
47
+ import com.luggmaps.LuggTileOverlayViewDelegate
48
+ import com.luggmaps.extensions.findViewByTag
49
+ import java.net.URL
50
+ import kotlin.math.atan
51
+ import kotlin.math.pow
52
+ import kotlin.math.sinh
31
53
 
32
54
  class GoogleMapProvider(private val context: Context) :
33
55
  MapProvider,
@@ -35,15 +57,21 @@ class GoogleMapProvider(private val context: Context) :
35
57
  LuggMarkerViewDelegate,
36
58
  LuggPolylineViewDelegate,
37
59
  LuggPolygonViewDelegate,
60
+ LuggCircleViewDelegate,
61
+ LuggGroundOverlayViewDelegate,
62
+ LuggTileOverlayViewDelegate,
38
63
  GoogleMap.OnCameraMoveStartedListener,
39
64
  GoogleMap.OnCameraMoveListener,
40
65
  GoogleMap.OnCameraIdleListener,
41
66
  GoogleMap.OnMapClickListener,
42
67
  GoogleMap.OnMapLongClickListener,
43
68
  GoogleMap.OnPolygonClickListener,
69
+ GoogleMap.OnCircleClickListener,
70
+ GoogleMap.OnGroundOverlayClickListener,
44
71
  GoogleMap.OnMarkerClickListener,
45
72
  GoogleMap.OnMarkerDragListener,
46
- GoogleMap.InfoWindowAdapter {
73
+ GoogleMap.InfoWindowAdapter,
74
+ ComponentCallbacks2 {
47
75
 
48
76
  override var delegate: MapProviderDelegate? = null
49
77
  override val isMapReady: Boolean get() = _isMapReady
@@ -51,6 +79,7 @@ class GoogleMapProvider(private val context: Context) :
51
79
  var mapId: String = DEMO_MAP_ID
52
80
 
53
81
  private var wrapperView: LuggMapWrapperView? = null
82
+ private var currentNightMode: Int = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
54
83
  private var mapView: MapView? = null
55
84
  private var googleMap: GoogleMap? = null
56
85
  private var _isMapReady = false
@@ -58,8 +87,13 @@ class GoogleMapProvider(private val context: Context) :
58
87
  private val pendingMarkerViews = mutableSetOf<LuggMarkerView>()
59
88
  private val pendingPolylineViews = mutableSetOf<LuggPolylineView>()
60
89
  private val pendingPolygonViews = mutableSetOf<LuggPolygonView>()
90
+ private val pendingCircleViews = mutableSetOf<LuggCircleView>()
91
+ private val pendingGroundOverlayViews = mutableSetOf<LuggGroundOverlayView>()
92
+ private val pendingTileOverlayViews = mutableSetOf<LuggTileOverlayView>()
61
93
  private val polylineAnimators = mutableMapOf<LuggPolylineView, PolylineAnimator>()
62
94
  private val polygonToViewMap = mutableMapOf<Polygon, LuggPolygonView>()
95
+ private val circleToViewMap = mutableMapOf<Circle, LuggCircleView>()
96
+ private val groundOverlayToViewMap = mutableMapOf<GroundOverlay, LuggGroundOverlayView>()
63
97
  private val markerToViewMap = mutableMapOf<Marker, LuggMarkerView>()
64
98
  private val liveMarkerViews = mutableSetOf<LuggMarkerView>()
65
99
  private var activeNonBubbledMarker: Marker? = null
@@ -88,6 +122,10 @@ class GoogleMapProvider(private val context: Context) :
88
122
  // Edge Insets
89
123
  private var edgeInsets: EdgeInsets = EdgeInsets()
90
124
 
125
+ // Inset adjustment
126
+ private var insetAdjustment: String = "never"
127
+ private var systemInsets: EdgeInsets = EdgeInsets()
128
+
91
129
  // region MapProvider
92
130
 
93
131
  override fun initializeMap(wrapperView: View, latitude: Double, longitude: Double, zoom: Float) {
@@ -100,6 +138,8 @@ class GoogleMapProvider(private val context: Context) :
100
138
  val wrapper = wrapperView as LuggMapWrapperView
101
139
  this.wrapperView = wrapper
102
140
 
141
+ context.applicationContext.registerComponentCallbacks(this)
142
+
103
143
  val options = GoogleMapOptions().mapId(mapId)
104
144
  mapView = MapView(context, options).also { view ->
105
145
  view.onCreate(null)
@@ -110,6 +150,8 @@ class GoogleMapProvider(private val context: Context) :
110
150
  }
111
151
 
112
152
  override fun destroy() {
153
+ detachWindowInsetsListener()
154
+ context.applicationContext.unregisterComponentCallbacks(this)
113
155
  dismissNonBubbledCallout()
114
156
  for (markerView in liveMarkerViews) {
115
157
  markerView.onUpdate = null
@@ -118,9 +160,14 @@ class GoogleMapProvider(private val context: Context) :
118
160
  pendingMarkerViews.clear()
119
161
  pendingPolylineViews.clear()
120
162
  pendingPolygonViews.clear()
163
+ pendingCircleViews.clear()
164
+ pendingGroundOverlayViews.clear()
165
+ pendingTileOverlayViews.clear()
121
166
  polylineAnimators.values.forEach { it.destroy() }
122
167
  polylineAnimators.clear()
123
168
  polygonToViewMap.clear()
169
+ circleToViewMap.clear()
170
+ groundOverlayToViewMap.clear()
124
171
  markerToViewMap.clear()
125
172
  wrapperView?.touchEventHandler = null
126
173
  wrapperView = null
@@ -130,6 +177,8 @@ class GoogleMapProvider(private val context: Context) :
130
177
  googleMap?.setOnMapClickListener(null)
131
178
  googleMap?.setOnMapLongClickListener(null)
132
179
  googleMap?.setOnPolygonClickListener(null)
180
+ googleMap?.setOnCircleClickListener(null)
181
+ googleMap?.setOnGroundOverlayClickListener(null)
133
182
  googleMap?.setOnMarkerClickListener(null)
134
183
  googleMap?.setOnMarkerDragListener(null)
135
184
  googleMap?.setInfoWindowAdapter(null)
@@ -154,6 +203,8 @@ class GoogleMapProvider(private val context: Context) :
154
203
  map.setOnMapClickListener(this)
155
204
  map.setOnMapLongClickListener(this)
156
205
  map.setOnPolygonClickListener(this)
206
+ map.setOnCircleClickListener(this)
207
+ map.setOnGroundOverlayClickListener(this)
157
208
  map.setOnMarkerClickListener(this)
158
209
  map.setOnMarkerDragListener(this)
159
210
  map.setInfoWindowAdapter(this)
@@ -167,11 +218,15 @@ class GoogleMapProvider(private val context: Context) :
167
218
  applyUiSettings()
168
219
  applyZoomLimits()
169
220
  applyEdgeInsets()
221
+ applyInsetAdjustment()
170
222
  applyTheme()
171
223
  applyUserLocation()
172
224
  processPendingMarkers()
173
225
  processPendingPolylines()
174
226
  processPendingPolygons()
227
+ processPendingCircles()
228
+ processPendingGroundOverlays()
229
+ processPendingTileOverlays()
175
230
 
176
231
  delegate?.mapProviderDidReady()
177
232
  }
@@ -227,6 +282,22 @@ class GoogleMapProvider(private val context: Context) :
227
282
  }
228
283
  }
229
284
 
285
+ override fun onCircleClick(circle: Circle) {
286
+ val circleView = circleToViewMap[circle]
287
+ if (circleView?.tappable == true) {
288
+ circleView.emitPressEvent()
289
+ } else {
290
+ onMapClick(tapLocation ?: return)
291
+ }
292
+ }
293
+
294
+ override fun onGroundOverlayClick(groundOverlay: GroundOverlay) {
295
+ val view = groundOverlayToViewMap[groundOverlay]
296
+ if (view?.tappable == true) {
297
+ view.emitPressEvent()
298
+ }
299
+ }
300
+
230
301
  override fun onMarkerClick(marker: Marker): Boolean {
231
302
  dismissNonBubbledCallout()
232
303
 
@@ -236,10 +307,17 @@ class GoogleMapProvider(private val context: Context) :
236
307
 
237
308
  val calloutView = view.calloutView
238
309
  if (calloutView != null && !calloutView.bubbled && calloutView.hasCustomContent) {
239
- googleMap?.animateCamera(CameraUpdateFactory.newLatLng(marker.position))
310
+ if (view.centerOnPress) {
311
+ googleMap?.animateCamera(CameraUpdateFactory.newLatLng(marker.position))
312
+ }
240
313
  showNonBubbledCallout(marker, calloutView)
241
314
  return true
242
315
  }
316
+
317
+ if (!view.centerOnPress) {
318
+ marker.showInfoWindow()
319
+ return true
320
+ }
243
321
  }
244
322
  return false
245
323
  }
@@ -353,8 +431,8 @@ class GoogleMapProvider(private val context: Context) :
353
431
  val map = googleMap ?: return
354
432
 
355
433
  val point = map.projection.toScreenLocation(marker.position)
356
- contentView.translationX = point.x - contentView.width * calloutView.anchorX
357
- contentView.translationY = point.y - markerView.contentView.height * markerView.anchorY - contentView.height * calloutView.anchorY
434
+ contentView.translationX = point.x - contentView.width / 2f + calloutView.offsetX
435
+ contentView.translationY = point.y - markerView.scaledContentHeight * markerView.anchorY - contentView.height + calloutView.offsetY
358
436
  }
359
437
 
360
438
  // endregion
@@ -398,6 +476,15 @@ class GoogleMapProvider(private val context: Context) :
398
476
  googleMap?.uiSettings?.isMyLocationButtonEnabled = enabled
399
477
  }
400
478
 
479
+ override fun setMapType(value: String) {
480
+ googleMap?.mapType = when (value) {
481
+ "satellite" -> GoogleMap.MAP_TYPE_SATELLITE
482
+ "terrain" -> GoogleMap.MAP_TYPE_TERRAIN
483
+ "hybrid" -> GoogleMap.MAP_TYPE_HYBRID
484
+ else -> GoogleMap.MAP_TYPE_NORMAL
485
+ }
486
+ }
487
+
401
488
  override fun setTheme(value: String) {
402
489
  theme = value
403
490
  applyTheme()
@@ -437,7 +524,7 @@ class GoogleMapProvider(private val context: Context) :
437
524
 
438
525
  if (map != null && oldInsets != edgeInsets) {
439
526
  val cameraUpdate = CameraUpdateFactory.newCameraPosition(map.cameraPosition)
440
- applyEdgeInsets()
527
+ applyEdgeInsets(duration)
441
528
  when {
442
529
  duration < 0 -> map.animateCamera(cameraUpdate)
443
530
  duration > 0 -> map.animateCamera(cameraUpdate, duration, null)
@@ -448,6 +535,17 @@ class GoogleMapProvider(private val context: Context) :
448
535
  }
449
536
  }
450
537
 
538
+ override fun setInsetAdjustment(value: String) {
539
+ insetAdjustment = value
540
+ applyInsetAdjustment()
541
+ }
542
+
543
+ override fun setPoiEnabled(enabled: Boolean) {}
544
+
545
+ override fun setPoiFilterMode(mode: String) {}
546
+
547
+ override fun setPoiFilterCategories(categories: List<String>) {}
548
+
451
549
  // endregion
452
550
 
453
551
  // region MarkerViewDelegate
@@ -469,6 +567,30 @@ class GoogleMapProvider(private val context: Context) :
469
567
  syncMarkerView(markerView)
470
568
  }
471
569
 
570
+ override fun showCalloutForMarkerView(markerView: LuggMarkerView) {
571
+ val marker = markerView.marker ?: return
572
+ val calloutView = markerView.calloutView
573
+
574
+ if (calloutView != null && calloutView.hasCustomContent) {
575
+ dismissNonBubbledCallout()
576
+ if (calloutView.bubbled) {
577
+ marker.showInfoWindow()
578
+ } else {
579
+ showNonBubbledCallout(marker, calloutView)
580
+ }
581
+ return
582
+ }
583
+
584
+ if (!markerView.title.isNullOrEmpty()) {
585
+ marker.showInfoWindow()
586
+ }
587
+ }
588
+
589
+ override fun hideCalloutForMarkerView(markerView: LuggMarkerView) {
590
+ dismissNonBubbledCallout()
591
+ markerView.marker?.hideInfoWindow()
592
+ }
593
+
472
594
  // endregion
473
595
 
474
596
  // region PolylineViewDelegate
@@ -487,6 +609,30 @@ class GoogleMapProvider(private val context: Context) :
487
609
 
488
610
  // endregion
489
611
 
612
+ // region CircleViewDelegate
613
+
614
+ override fun circleViewDidUpdate(circleView: LuggCircleView) {
615
+ syncCircleView(circleView)
616
+ }
617
+
618
+ // endregion
619
+
620
+ // region GroundOverlayViewDelegate
621
+
622
+ override fun groundOverlayViewDidUpdate(groundOverlayView: LuggGroundOverlayView) {
623
+ syncGroundOverlayView(groundOverlayView)
624
+ }
625
+
626
+ // endregion
627
+
628
+ // region TileOverlayViewDelegate
629
+
630
+ override fun tileOverlayViewDidUpdate(tileOverlayView: LuggTileOverlayView) {
631
+ syncTileOverlayView(tileOverlayView)
632
+ }
633
+
634
+ // endregion
635
+
490
636
  // region Marker Management
491
637
 
492
638
  override fun addMarkerView(markerView: LuggMarkerView) {
@@ -753,6 +899,218 @@ class GoogleMapProvider(private val context: Context) :
753
899
 
754
900
  // endregion
755
901
 
902
+ // region Circle Management
903
+
904
+ override fun addCircleView(circleView: LuggCircleView) {
905
+ circleView.delegate = this
906
+ syncCircleView(circleView)
907
+ }
908
+
909
+ override fun removeCircleView(circleView: LuggCircleView) {
910
+ circleView.circle?.let { circleToViewMap.remove(it) }
911
+ circleView.circle?.remove()
912
+ circleView.circle = null
913
+ }
914
+
915
+ private fun syncCircleView(circleView: LuggCircleView) {
916
+ if (googleMap == null) {
917
+ pendingCircleViews.add(circleView)
918
+ return
919
+ }
920
+
921
+ if (circleView.circle == null) {
922
+ addCircleViewToMap(circleView)
923
+ return
924
+ }
925
+
926
+ circleView.circle?.apply {
927
+ center = circleView.center
928
+ radius = circleView.radius
929
+ fillColor = circleView.fillColor
930
+ strokeColor = circleView.strokeColor
931
+ strokeWidth = circleView.strokeWidth.dpToPx()
932
+ zIndex = circleView.zIndex
933
+ isClickable = true
934
+ }
935
+ }
936
+
937
+ private fun processPendingCircles() {
938
+ if (googleMap == null) return
939
+ pendingCircleViews.forEach { addCircleViewToMap(it) }
940
+ pendingCircleViews.clear()
941
+ }
942
+
943
+ private fun addCircleViewToMap(circleView: LuggCircleView) {
944
+ val map = googleMap ?: return
945
+
946
+ val options = CircleOptions()
947
+ .center(circleView.center)
948
+ .radius(circleView.radius)
949
+ .fillColor(circleView.fillColor)
950
+ .strokeColor(circleView.strokeColor)
951
+ .strokeWidth(circleView.strokeWidth.dpToPx())
952
+ .zIndex(circleView.zIndex)
953
+ .clickable(true)
954
+
955
+ val circle = map.addCircle(options)
956
+ circleView.circle = circle
957
+ circleToViewMap[circle] = circleView
958
+ }
959
+
960
+ // endregion
961
+
962
+ // region Ground Overlay Management
963
+
964
+ override fun addGroundOverlayView(groundOverlayView: LuggGroundOverlayView) {
965
+ groundOverlayView.delegate = this
966
+ syncGroundOverlayView(groundOverlayView)
967
+ }
968
+
969
+ override fun removeGroundOverlayView(groundOverlayView: LuggGroundOverlayView) {
970
+ groundOverlayView.delegate = null
971
+ groundOverlayView.groundOverlay?.let { groundOverlayToViewMap.remove(it) }
972
+ groundOverlayView.groundOverlay?.remove()
973
+ groundOverlayView.groundOverlay = null
974
+ }
975
+
976
+ private fun syncGroundOverlayView(groundOverlayView: LuggGroundOverlayView) {
977
+ if (googleMap == null) {
978
+ pendingGroundOverlayViews.add(groundOverlayView)
979
+ return
980
+ }
981
+
982
+ val imageUri = groundOverlayView.imageUri
983
+ if (imageUri.isEmpty()) return
984
+
985
+ // Remove old overlay
986
+ groundOverlayView.groundOverlay?.let { groundOverlayToViewMap.remove(it) }
987
+ groundOverlayView.groundOverlay?.remove()
988
+ groundOverlayView.groundOverlay = null
989
+
990
+ // Load image async and add overlay
991
+ Thread {
992
+ try {
993
+ val connection = URL(imageUri).openConnection() as java.net.HttpURLConnection
994
+ connection.instanceFollowRedirects = true
995
+ connection.connect()
996
+ val bitmap = android.graphics.BitmapFactory.decodeStream(connection.inputStream)
997
+ connection.disconnect()
998
+ if (bitmap != null) {
999
+ mapView?.post {
1000
+ addGroundOverlayToMap(groundOverlayView, bitmap)
1001
+ }
1002
+ }
1003
+ } catch (_: Exception) {}
1004
+ }.start()
1005
+ }
1006
+
1007
+ private fun addGroundOverlayToMap(groundOverlayView: LuggGroundOverlayView, bitmap: android.graphics.Bitmap) {
1008
+ val map = googleMap ?: return
1009
+
1010
+ val bounds = LatLngBounds(groundOverlayView.southwest, groundOverlayView.northeast)
1011
+ val options = GroundOverlayOptions()
1012
+ .image(BitmapDescriptorFactory.fromBitmap(bitmap))
1013
+ .positionFromBounds(bounds)
1014
+ .transparency(1f - groundOverlayView.overlayOpacity)
1015
+ .bearing(groundOverlayView.bearing)
1016
+ .zIndex(groundOverlayView.zIndex)
1017
+ .clickable(groundOverlayView.tappable)
1018
+
1019
+ val overlay = map.addGroundOverlay(options)
1020
+ if (overlay != null) {
1021
+ groundOverlayView.groundOverlay = overlay
1022
+ groundOverlayToViewMap[overlay] = groundOverlayView
1023
+ }
1024
+ }
1025
+
1026
+ private fun processPendingGroundOverlays() {
1027
+ if (googleMap == null) return
1028
+ pendingGroundOverlayViews.forEach { syncGroundOverlayView(it) }
1029
+ pendingGroundOverlayViews.clear()
1030
+ }
1031
+
1032
+ // endregion
1033
+
1034
+ // region Tile Overlay Management
1035
+
1036
+ override fun addTileOverlayView(tileOverlayView: LuggTileOverlayView) {
1037
+ tileOverlayView.delegate = this
1038
+ syncTileOverlayView(tileOverlayView)
1039
+ }
1040
+
1041
+ override fun removeTileOverlayView(tileOverlayView: LuggTileOverlayView) {
1042
+ tileOverlayView.delegate = null
1043
+ tileOverlayView.tileOverlay?.remove()
1044
+ tileOverlayView.tileOverlay = null
1045
+ }
1046
+
1047
+ private fun syncTileOverlayView(tileOverlayView: LuggTileOverlayView) {
1048
+ if (googleMap == null) {
1049
+ pendingTileOverlayViews.add(tileOverlayView)
1050
+ return
1051
+ }
1052
+
1053
+ val urlTemplate = tileOverlayView.urlTemplate
1054
+ if (urlTemplate.isEmpty()) return
1055
+
1056
+ // Remove old overlay
1057
+ tileOverlayView.tileOverlay?.remove()
1058
+ tileOverlayView.tileOverlay = null
1059
+
1060
+ val tileSize = tileOverlayView.tileSize
1061
+ val hasBounds = tileOverlayView.hasBounds
1062
+ val swLat = tileOverlayView.boundsSwLat
1063
+ val swLng = tileOverlayView.boundsSwLng
1064
+ val neLat = tileOverlayView.boundsNeLat
1065
+ val neLng = tileOverlayView.boundsNeLng
1066
+
1067
+ val tileProvider = object : UrlTileProvider(tileSize, tileSize) {
1068
+ override fun getTileUrl(x: Int, y: Int, zoom: Int): URL? {
1069
+ if (hasBounds) {
1070
+ val n = 2.0.pow(zoom.toDouble())
1071
+ val tileSWLat = Math.toDegrees(atan(sinh(Math.PI * (1 - 2.0 * (y + 1) / n))))
1072
+ val tileNELat = Math.toDegrees(atan(sinh(Math.PI * (1 - 2.0 * y / n))))
1073
+ val tileSWLng = x / n * 360.0 - 180.0
1074
+ val tileNELng = (x + 1) / n * 360.0 - 180.0
1075
+
1076
+ if (tileNELat < swLat ||
1077
+ tileSWLat > neLat ||
1078
+ tileNELng < swLng ||
1079
+ tileSWLng > neLng
1080
+ ) {
1081
+ return null
1082
+ }
1083
+ }
1084
+
1085
+ val url = urlTemplate
1086
+ .replace("{x}", x.toString())
1087
+ .replace("{y}", y.toString())
1088
+ .replace("{z}", zoom.toString())
1089
+ return try {
1090
+ URL(url)
1091
+ } catch (_: Exception) {
1092
+ null
1093
+ }
1094
+ }
1095
+ }
1096
+
1097
+ val options = TileOverlayOptions()
1098
+ .tileProvider(tileProvider)
1099
+ .transparency(1f - tileOverlayView.overlayOpacity)
1100
+ .zIndex(tileOverlayView.zIndex)
1101
+
1102
+ val overlay = googleMap?.addTileOverlay(options)
1103
+ tileOverlayView.tileOverlay = overlay
1104
+ }
1105
+
1106
+ private fun processPendingTileOverlays() {
1107
+ if (googleMap == null) return
1108
+ pendingTileOverlayViews.forEach { syncTileOverlayView(it) }
1109
+ pendingTileOverlayViews.clear()
1110
+ }
1111
+
1112
+ // endregion
1113
+
756
1114
  // region Lifecycle
757
1115
 
758
1116
  override fun pauseAnimations() {
@@ -790,11 +1148,11 @@ class GoogleMapProvider(private val context: Context) :
790
1148
  val map = googleMap ?: return
791
1149
  if (coordinates.isEmpty()) return
792
1150
 
793
- val latLngs = coordinates.filterIsInstance<LatLng>()
794
- if (latLngs.isEmpty()) return
1151
+ val latLongs = coordinates.filterIsInstance<LatLng>()
1152
+ if (latLongs.isEmpty()) return
795
1153
 
796
- val boundsBuilder = com.google.android.gms.maps.model.LatLngBounds.Builder()
797
- latLngs.forEach { boundsBuilder.include(it) }
1154
+ val boundsBuilder = LatLngBounds.Builder()
1155
+ latLongs.forEach { boundsBuilder.include(it) }
798
1156
  val bounds = boundsBuilder.build()
799
1157
 
800
1158
  val top = edgeInsetsTop.toFloat().dpToPx().toInt()
@@ -802,11 +1160,12 @@ class GoogleMapProvider(private val context: Context) :
802
1160
  val bottom = edgeInsetsBottom.toFloat().dpToPx().toInt()
803
1161
  val right = edgeInsetsRight.toFloat().dpToPx().toInt()
804
1162
 
1163
+ val combined = combinedEdgeInsets()
805
1164
  map.setPadding(
806
- edgeInsets.left + left,
807
- edgeInsets.top + top,
808
- edgeInsets.right + right,
809
- edgeInsets.bottom + bottom
1165
+ combined.left + left,
1166
+ combined.top + top,
1167
+ combined.right + right,
1168
+ combined.bottom + bottom
810
1169
  )
811
1170
 
812
1171
  val cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 0)
@@ -817,7 +1176,7 @@ class GoogleMapProvider(private val context: Context) :
817
1176
  else -> map.moveCamera(cameraUpdate)
818
1177
  }
819
1178
 
820
- map.setPadding(edgeInsets.left, edgeInsets.top, edgeInsets.right, edgeInsets.bottom)
1179
+ map.setPadding(combined.left, combined.top, combined.right, combined.bottom)
821
1180
  }
822
1181
 
823
1182
  // endregion
@@ -841,17 +1200,92 @@ class GoogleMapProvider(private val context: Context) :
841
1200
  }
842
1201
  }
843
1202
 
844
- private fun applyEdgeInsets() {
845
- googleMap?.setPadding(edgeInsets.left, edgeInsets.top, edgeInsets.right, edgeInsets.bottom)
1203
+ private fun applyInsetAdjustment() {
1204
+ if (insetAdjustment == "automatic") {
1205
+ attachWindowInsetsListener()
1206
+ } else {
1207
+ detachWindowInsetsListener()
1208
+ systemInsets = EdgeInsets()
1209
+ }
1210
+ applyEdgeInsets()
1211
+ }
1212
+
1213
+ private fun combinedEdgeInsets(): EdgeInsets =
1214
+ if (insetAdjustment == "automatic") {
1215
+ EdgeInsets(
1216
+ edgeInsets.top + systemInsets.top,
1217
+ edgeInsets.left + systemInsets.left,
1218
+ edgeInsets.bottom + systemInsets.bottom,
1219
+ edgeInsets.right + systemInsets.right
1220
+ )
1221
+ } else {
1222
+ edgeInsets
1223
+ }
1224
+
1225
+ private fun applyEdgeInsets(duration: Int = 0) {
1226
+ val combined = combinedEdgeInsets()
1227
+ googleMap?.setPadding(combined.left, combined.top, combined.right, combined.bottom)
1228
+ applyWatermarkTranslation(combined, duration)
1229
+ }
1230
+
1231
+ private fun applyWatermarkTranslation(insets: EdgeInsets, duration: Int = 0) {
1232
+ val view = mapView ?: return
1233
+ view.findViewByTag("GoogleWatermark")?.let { watermark ->
1234
+ val targetY = -insets.bottom.toFloat()
1235
+ val targetX = insets.left.toFloat()
1236
+ if (duration > 0) {
1237
+ watermark.animate()
1238
+ .translationY(targetY)
1239
+ .translationX(targetX)
1240
+ .setDuration(duration.toLong())
1241
+ .start()
1242
+ } else if (duration < 0) {
1243
+ watermark.animate()
1244
+ .translationY(targetY)
1245
+ .translationX(targetX)
1246
+ .start()
1247
+ } else {
1248
+ watermark.translationY = targetY
1249
+ watermark.translationX = targetX
1250
+ }
1251
+ }
1252
+ }
1253
+
1254
+ private fun attachWindowInsetsListener() {
1255
+ val view = mapView ?: return
1256
+ ViewCompat.setOnApplyWindowInsetsListener(view) { _, windowInsets ->
1257
+ val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
1258
+ systemInsets = EdgeInsets(insets.top, insets.left, insets.bottom, insets.right)
1259
+ applyEdgeInsets()
1260
+ windowInsets
1261
+ }
1262
+ ViewCompat.requestApplyInsets(view)
1263
+ }
1264
+
1265
+ private fun detachWindowInsetsListener() {
1266
+ mapView?.let { ViewCompat.setOnApplyWindowInsetsListener(it, null) }
1267
+ }
1268
+
1269
+ override fun onConfigurationChanged(newConfig: Configuration) {
1270
+ val newNightMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK
1271
+ if (newNightMode != currentNightMode) {
1272
+ currentNightMode = newNightMode
1273
+ applyTheme()
1274
+ }
846
1275
  }
847
1276
 
1277
+ @Deprecated("Deprecated in Java")
1278
+ override fun onLowMemory() {}
1279
+
1280
+ override fun onTrimMemory(level: Int) {}
1281
+
848
1282
  private fun applyTheme() {
849
1283
  val colorScheme = when (theme) {
850
1284
  "dark" -> MapColorScheme.DARK
851
1285
  "light" -> MapColorScheme.LIGHT
852
1286
  else -> MapColorScheme.FOLLOW_SYSTEM
853
1287
  }
854
- googleMap?.setMapColorScheme(colorScheme)
1288
+ googleMap?.mapColorScheme = colorScheme
855
1289
  }
856
1290
 
857
1291
  @SuppressLint("MissingPermission")