react-native-google-maps-plus 1.7.0-dev.6 → 1.7.0-dev.7

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.
@@ -8,7 +8,6 @@ import android.util.Size
8
8
  import android.widget.FrameLayout
9
9
  import androidx.core.graphics.scale
10
10
  import com.facebook.react.bridge.LifecycleEventListener
11
- import com.facebook.react.bridge.UiThreadUtil
12
11
  import com.facebook.react.uimanager.PixelUtil.dpToPx
13
12
  import com.facebook.react.uimanager.ThemedReactContext
14
13
  import com.google.android.gms.maps.CameraUpdateFactory
@@ -34,6 +33,8 @@ import com.google.android.gms.maps.model.TileOverlay
34
33
  import com.google.android.gms.maps.model.TileOverlayOptions
35
34
  import com.google.maps.android.data.kml.KmlLayer
36
35
  import com.margelo.nitro.core.Promise
36
+ import com.rngooglemapsplus.extensions.onUi
37
+ import com.rngooglemapsplus.extensions.onUiSync
37
38
  import com.rngooglemapsplus.extensions.toGooglePriority
38
39
  import com.rngooglemapsplus.extensions.toLatLng
39
40
  import com.rngooglemapsplus.extensions.toLocationErrorCode
@@ -101,101 +102,95 @@ class GoogleMapsViewImpl(
101
102
  reactContext.addLifecycleEventListener(this)
102
103
  }
103
104
 
104
- fun initMapView(googleMapsOptions: GoogleMapOptions) {
105
- if (initialized) return
106
- initialized = true
107
- val result = playServiceHandler.playServicesAvailability()
108
- val errorCode = result.toRNMapErrorCodeOrNull()
105
+ fun initMapView(googleMapsOptions: GoogleMapOptions) =
106
+ onUi {
107
+ if (initialized) return@onUi
108
+ initialized = true
109
109
 
110
- if (errorCode != null) {
111
- onMapError?.invoke(errorCode)
110
+ val result = playServiceHandler.playServicesAvailability()
111
+ val errorCode = result.toRNMapErrorCodeOrNull()
112
+ if (errorCode != null) {
113
+ onMapError?.invoke(errorCode)
114
+ if (errorCode == RNMapErrorCode.PLAY_SERVICES_MISSING ||
115
+ errorCode == RNMapErrorCode.PLAY_SERVICES_INVALID
116
+ ) {
117
+ return@onUi
118
+ }
119
+ }
112
120
 
113
- if (errorCode == RNMapErrorCode.PLAY_SERVICES_MISSING ||
114
- errorCode == RNMapErrorCode.PLAY_SERVICES_INVALID
115
- ) {
116
- return
121
+ mapView = MapView(reactContext, googleMapsOptions)
122
+ super.addView(mapView)
123
+
124
+ mapView?.onCreate(null)
125
+ mapView?.getMapAsync { map ->
126
+ googleMap = map
127
+ googleMap?.setOnMapLoadedCallback {
128
+ googleMap?.setOnCameraMoveStartedListener(this@GoogleMapsViewImpl)
129
+ googleMap?.setOnCameraMoveListener(this@GoogleMapsViewImpl)
130
+ googleMap?.setOnCameraIdleListener(this@GoogleMapsViewImpl)
131
+ googleMap?.setOnMarkerClickListener(this@GoogleMapsViewImpl)
132
+ googleMap?.setOnPolylineClickListener(this@GoogleMapsViewImpl)
133
+ googleMap?.setOnPolygonClickListener(this@GoogleMapsViewImpl)
134
+ googleMap?.setOnCircleClickListener(this@GoogleMapsViewImpl)
135
+ googleMap?.setOnMapClickListener(this@GoogleMapsViewImpl)
136
+ googleMap?.setOnMapLongClickListener(this@GoogleMapsViewImpl)
137
+ googleMap?.setOnPoiClickListener(this@GoogleMapsViewImpl)
138
+ googleMap?.setOnMarkerDragListener(this@GoogleMapsViewImpl)
139
+ googleMap?.setOnInfoWindowClickListener(this@GoogleMapsViewImpl)
140
+ googleMap?.setOnInfoWindowCloseListener(this@GoogleMapsViewImpl)
141
+ googleMap?.setOnInfoWindowLongClickListener(this@GoogleMapsViewImpl)
142
+ googleMap?.setOnMyLocationClickListener(this@GoogleMapsViewImpl)
143
+ googleMap?.setOnMyLocationButtonClickListener(this@GoogleMapsViewImpl)
144
+ onMapLoaded?.invoke(true)
145
+ }
146
+ applyProps()
147
+ initLocationCallbacks()
148
+ onMapReady?.invoke(true)
117
149
  }
118
150
  }
119
151
 
120
- mapView =
121
- MapView(
122
- reactContext,
123
- googleMapsOptions,
152
+ override fun onCameraMoveStarted(reason: Int) =
153
+ onUi {
154
+ cameraMoveReason = reason
155
+ val visibleRegion = googleMap?.projection?.visibleRegion ?: return@onUi
156
+ val cameraPosition = googleMap?.cameraPosition ?: return@onUi
157
+ onCameraChangeStart?.invoke(
158
+ visibleRegion.toRnRegion(),
159
+ cameraPosition.toRnCamera(),
160
+ GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE == reason,
124
161
  )
125
-
126
- super.addView(mapView)
127
-
128
- mapView?.onCreate(null)
129
- mapView?.getMapAsync { map ->
130
- googleMap = map
131
- googleMap?.setOnMapLoadedCallback {
132
- googleMap?.setOnCameraMoveStartedListener(this@GoogleMapsViewImpl)
133
- googleMap?.setOnCameraMoveListener(this@GoogleMapsViewImpl)
134
- googleMap?.setOnCameraIdleListener(this@GoogleMapsViewImpl)
135
- googleMap?.setOnMarkerClickListener(this@GoogleMapsViewImpl)
136
- googleMap?.setOnPolylineClickListener(this@GoogleMapsViewImpl)
137
- googleMap?.setOnPolygonClickListener(this@GoogleMapsViewImpl)
138
- googleMap?.setOnCircleClickListener(this@GoogleMapsViewImpl)
139
- googleMap?.setOnMapClickListener(this@GoogleMapsViewImpl)
140
- googleMap?.setOnMapLongClickListener(this@GoogleMapsViewImpl)
141
- googleMap?.setOnPoiClickListener(this@GoogleMapsViewImpl)
142
- googleMap?.setOnMarkerDragListener(this@GoogleMapsViewImpl)
143
- googleMap?.setOnInfoWindowClickListener(this@GoogleMapsViewImpl)
144
- googleMap?.setOnInfoWindowCloseListener(this@GoogleMapsViewImpl)
145
- googleMap?.setOnInfoWindowLongClickListener(this@GoogleMapsViewImpl)
146
- googleMap?.setOnMyLocationClickListener(this@GoogleMapsViewImpl)
147
- googleMap?.setOnMyLocationButtonClickListener(this@GoogleMapsViewImpl)
148
- onMapLoaded?.invoke(true)
149
- }
150
- applyProps()
151
- initLocationCallbacks()
152
- onMapReady?.invoke(true)
153
162
  }
154
- }
155
-
156
- override fun onCameraMoveStarted(reason: Int) {
157
- cameraMoveReason = reason
158
- val visibleRegion = googleMap?.projection?.visibleRegion ?: return
159
- val cameraPosition = googleMap?.cameraPosition ?: return
160
-
161
- onCameraChangeStart?.invoke(
162
- visibleRegion.toRnRegion(),
163
- cameraPosition.toRnCamera(),
164
- GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE == reason,
165
- )
166
- }
167
-
168
- override fun onCameraMove() {
169
- val visibleRegion = googleMap?.projection?.visibleRegion ?: return
170
- val cameraPosition = googleMap?.cameraPosition ?: return
171
- val gesture = GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE == cameraMoveReason
172
-
173
- onCameraChange?.invoke(
174
- visibleRegion.toRnRegion(),
175
- cameraPosition.toRnCamera(),
176
- gesture,
177
- )
178
- }
179
163
 
180
- override fun onCameraIdle() {
181
- val visibleRegion = googleMap?.projection?.visibleRegion ?: return
182
- val cameraPosition = googleMap?.cameraPosition ?: return
183
- val gesture = GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE == cameraMoveReason
164
+ override fun onCameraMove() =
165
+ onUi {
166
+ val visibleRegion = googleMap?.projection?.visibleRegion ?: return@onUi
167
+ val cameraPosition = googleMap?.cameraPosition ?: return@onUi
168
+ val gesture = GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE == cameraMoveReason
169
+ onCameraChange?.invoke(
170
+ visibleRegion.toRnRegion(),
171
+ cameraPosition.toRnCamera(),
172
+ gesture,
173
+ )
174
+ }
184
175
 
185
- onCameraChangeComplete?.invoke(
186
- visibleRegion.toRnRegion(),
187
- cameraPosition.toRnCamera(),
188
- gesture,
189
- )
190
- }
176
+ override fun onCameraIdle() =
177
+ onUi {
178
+ val visibleRegion = googleMap?.projection?.visibleRegion ?: return@onUi
179
+ val cameraPosition = googleMap?.cameraPosition ?: return@onUi
180
+ val gesture = GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE == cameraMoveReason
181
+ onCameraChangeComplete?.invoke(
182
+ visibleRegion.toRnRegion(),
183
+ cameraPosition.toRnCamera(),
184
+ gesture,
185
+ )
186
+ }
191
187
 
192
188
  fun initLocationCallbacks() {
193
189
  locationHandler.onUpdate = { location ->
194
- onLocationUpdate?.invoke(location.toRnLocation())
190
+ onUi { onLocationUpdate?.invoke(location.toRnLocation()) }
195
191
  }
196
-
197
192
  locationHandler.onError = { error ->
198
- onLocationError?.invoke(error)
193
+ onUi { onLocationError?.invoke(error) }
199
194
  }
200
195
  locationHandler.start()
201
196
  }
@@ -214,57 +209,37 @@ class GoogleMapsViewImpl(
214
209
  locationConfig = locationConfig
215
210
 
216
211
  if (pendingMarkers.isNotEmpty()) {
217
- pendingMarkers.forEach { (id, opts) ->
218
- internalAddMarker(id, opts)
219
- }
212
+ pendingMarkers.forEach { (id, opts) -> internalAddMarker(id, opts) }
220
213
  pendingMarkers.clear()
221
214
  }
222
-
223
215
  if (pendingPolylines.isNotEmpty()) {
224
- pendingPolylines.forEach { (id, opts) ->
225
- internalAddPolyline(id, opts)
226
- }
216
+ pendingPolylines.forEach { (id, opts) -> internalAddPolyline(id, opts) }
227
217
  pendingPolylines.clear()
228
218
  }
229
-
230
219
  if (pendingPolygons.isNotEmpty()) {
231
- pendingPolygons.forEach { (id, opts) ->
232
- internalAddPolygon(id, opts)
233
- }
220
+ pendingPolygons.forEach { (id, opts) -> internalAddPolygon(id, opts) }
234
221
  pendingPolygons.clear()
235
222
  }
236
-
237
223
  if (pendingCircles.isNotEmpty()) {
238
- pendingCircles.forEach { (id, opts) ->
239
- internalAddCircle(id, opts)
240
- }
224
+ pendingCircles.forEach { (id, opts) -> internalAddCircle(id, opts) }
241
225
  pendingCircles.clear()
242
226
  }
243
-
244
227
  if (pendingHeatmaps.isNotEmpty()) {
245
- pendingHeatmaps.forEach { (id, opts) ->
246
- internalAddHeatmap(id, opts)
247
- }
228
+ pendingHeatmaps.forEach { (id, opts) -> internalAddHeatmap(id, opts) }
248
229
  pendingHeatmaps.clear()
249
230
  }
250
-
251
231
  if (pendingKmlLayers.isNotEmpty()) {
252
- pendingKmlLayers.forEach { (id, string) ->
253
- internalAddKmlLayer(id, string)
254
- }
232
+ pendingKmlLayers.forEach { (id, str) -> internalAddKmlLayer(id, str) }
255
233
  pendingKmlLayers.clear()
256
234
  }
257
-
258
235
  if (pendingUrlTilesOverlays.isNotEmpty()) {
259
- pendingUrlTilesOverlays.forEach { (id, string) ->
260
- internalAddUrlTileOverlay(id, string)
261
- }
236
+ pendingUrlTilesOverlays.forEach { (id, opts) -> internalAddUrlTileOverlay(id, opts) }
262
237
  pendingUrlTilesOverlays.clear()
263
238
  }
264
239
  }
265
240
 
266
241
  val currentCamera: CameraPosition?
267
- get() = googleMap?.cameraPosition
242
+ get() = onUiSync { googleMap?.cameraPosition }
268
243
 
269
244
  var initialProps: RNInitialProps? = null
270
245
 
@@ -300,8 +275,8 @@ class GoogleMapsViewImpl(
300
275
  onUi {
301
276
  try {
302
277
  googleMap?.isMyLocationEnabled = value ?: false
303
- } catch (se: SecurityException) {
304
- onLocationError?.invoke(RNLocationErrorCode.PERMISSION_DENIED)
278
+ } catch (_: SecurityException) {
279
+ onLocationError?.let { cb -> cb(RNLocationErrorCode.PERMISSION_DENIED) }
305
280
  } catch (ex: Exception) {
306
281
  val error = ex.toLocationErrorCode(context)
307
282
  onLocationError?.invoke(error)
@@ -312,41 +287,31 @@ class GoogleMapsViewImpl(
312
287
  var buildingEnabled: Boolean? = null
313
288
  set(value) {
314
289
  field = value
315
- onUi {
316
- googleMap?.isBuildingsEnabled = value ?: false
317
- }
290
+ onUi { googleMap?.isBuildingsEnabled = value ?: false }
318
291
  }
319
292
 
320
293
  var trafficEnabled: Boolean? = null
321
294
  set(value) {
322
295
  field = value
323
- onUi {
324
- googleMap?.isTrafficEnabled = value ?: false
325
- }
296
+ onUi { googleMap?.isTrafficEnabled = value ?: false }
326
297
  }
327
298
 
328
299
  var indoorEnabled: Boolean? = null
329
300
  set(value) {
330
301
  field = value
331
- onUi {
332
- googleMap?.isIndoorEnabled = value ?: false
333
- }
302
+ onUi { googleMap?.isIndoorEnabled = value ?: false }
334
303
  }
335
304
 
336
305
  var customMapStyle: MapStyleOptions? = null
337
306
  set(value) {
338
307
  field = value
339
- onUi {
340
- googleMap?.setMapStyle(value)
341
- }
308
+ onUi { googleMap?.setMapStyle(value) }
342
309
  }
343
310
 
344
311
  var userInterfaceStyle: Int? = null
345
312
  set(value) {
346
313
  field = value
347
- onUi {
348
- googleMap?.mapColorScheme = value ?: MapColorScheme.FOLLOW_SYSTEM
349
- }
314
+ onUi { googleMap?.mapColorScheme = value ?: MapColorScheme.FOLLOW_SYSTEM }
350
315
  }
351
316
 
352
317
  var mapZoomConfig: RNMapZoomConfig? = null
@@ -374,9 +339,7 @@ class GoogleMapsViewImpl(
374
339
  var mapType: Int? = null
375
340
  set(value) {
376
341
  field = value
377
- onUi {
378
- googleMap?.mapType = value ?: 1
379
- }
342
+ onUi { googleMap?.mapType = value ?: 1 }
380
343
  }
381
344
 
382
345
  var locationConfig: RNLocationConfig? = null
@@ -419,15 +382,12 @@ class GoogleMapsViewImpl(
419
382
  cameraPosition: CameraPosition,
420
383
  animated: Boolean,
421
384
  durationMs: Int,
422
- ) {
423
- onUi {
424
- val update = CameraUpdateFactory.newCameraPosition(cameraPosition)
425
-
426
- if (animated) {
427
- googleMap?.animateCamera(update, durationMs, null)
428
- } else {
429
- googleMap?.moveCamera(update)
430
- }
385
+ ) = onUi {
386
+ val update = CameraUpdateFactory.newCameraPosition(cameraPosition)
387
+ if (animated) {
388
+ googleMap?.animateCamera(update, durationMs, null)
389
+ } else {
390
+ googleMap?.moveCamera(update)
431
391
  }
432
392
  }
433
393
 
@@ -436,93 +396,81 @@ class GoogleMapsViewImpl(
436
396
  padding: RNMapPadding,
437
397
  animated: Boolean,
438
398
  durationMs: Int,
439
- ) {
440
- if (coordinates.isEmpty()) {
441
- return
442
- }
443
- onUi {
444
- val builder = LatLngBounds.Builder()
445
- coordinates.forEach { coord ->
446
- builder.include(coord.toLatLng())
447
- }
448
- val bounds = builder.build()
449
-
450
- val latSpan = bounds.northeast.latitude - bounds.southwest.latitude
451
- val lngSpan = bounds.northeast.longitude - bounds.southwest.longitude
452
-
453
- val latPerPixel = latSpan / (mapView?.height ?: 0)
454
- val lngPerPixel = lngSpan / (mapView?.width ?: 0)
399
+ ) = onUi {
400
+ if (coordinates.isEmpty()) return@onUi
401
+ val builder = LatLngBounds.Builder()
402
+ coordinates.forEach { coord -> builder.include(coord.toLatLng()) }
403
+ val bounds = builder.build()
404
+
405
+ val latSpan = bounds.northeast.latitude - bounds.southwest.latitude
406
+ val lngSpan = bounds.northeast.longitude - bounds.southwest.longitude
407
+
408
+ val h = (mapView?.height ?: 0)
409
+ val w = (mapView?.width ?: 0)
410
+ val latPerPixel = if (h != 0) latSpan / h else 0.0
411
+ val lngPerPixel = if (w != 0) lngSpan / w else 0.0
412
+
413
+ builder.include(
414
+ LatLng(
415
+ bounds.northeast.latitude + (padding.top.dpToPx() * latPerPixel),
416
+ bounds.northeast.longitude,
417
+ ),
418
+ )
419
+ builder.include(
420
+ LatLng(
421
+ bounds.southwest.latitude - (padding.bottom.dpToPx() * latPerPixel),
422
+ bounds.southwest.longitude,
423
+ ),
424
+ )
425
+ builder.include(
426
+ LatLng(
427
+ bounds.northeast.latitude,
428
+ bounds.northeast.longitude + (padding.right.dpToPx() * lngPerPixel),
429
+ ),
430
+ )
431
+ builder.include(
432
+ LatLng(
433
+ bounds.southwest.latitude,
434
+ bounds.southwest.longitude - (padding.left.dpToPx() * lngPerPixel),
435
+ ),
436
+ )
455
437
 
456
- builder.include(
457
- LatLng(
458
- bounds.northeast.latitude + (padding.top.dpToPx() * latPerPixel),
459
- bounds.northeast.longitude,
460
- ),
461
- )
462
- builder.include(
463
- LatLng(
464
- bounds.southwest.latitude - (padding.bottom.dpToPx() * latPerPixel),
465
- bounds.southwest.longitude,
466
- ),
438
+ val paddedBounds = builder.build()
439
+ val adjustedWidth =
440
+ (w - padding.left.dpToPx() - padding.right.dpToPx()).toInt().coerceAtLeast(0)
441
+ val adjustedHeight =
442
+ (h - padding.top.dpToPx() - padding.bottom.dpToPx()).toInt().coerceAtLeast(0)
443
+
444
+ val update =
445
+ CameraUpdateFactory.newLatLngBounds(
446
+ paddedBounds,
447
+ adjustedWidth,
448
+ adjustedHeight,
449
+ 0,
467
450
  )
468
- builder.include(
469
- LatLng(
470
- bounds.northeast.latitude,
471
- bounds.northeast.longitude + (padding.right.dpToPx() * lngPerPixel),
472
- ),
473
- )
474
- builder.include(
475
- LatLng(
476
- bounds.southwest.latitude,
477
- bounds.southwest.longitude - (padding.left.dpToPx() * lngPerPixel),
478
- ),
479
- )
480
-
481
- val paddedBounds = builder.build()
482
-
483
- val adjustedWidth =
484
- ((mapView?.width ?: 0) - padding.left.dpToPx() - padding.right.dpToPx()).toInt()
485
- val adjustedHeight =
486
- ((mapView?.height ?: 0) - padding.top.dpToPx() - padding.bottom.dpToPx()).toInt()
487
-
488
- val update =
489
- CameraUpdateFactory.newLatLngBounds(
490
- paddedBounds,
491
- adjustedWidth,
492
- adjustedHeight,
493
- 0,
494
- )
495
- if (animated) {
496
- googleMap?.animateCamera(update, durationMs, null)
497
- } else {
498
- googleMap?.moveCamera(update)
499
- }
451
+ if (animated) {
452
+ googleMap?.animateCamera(update, durationMs, null)
453
+ } else {
454
+ googleMap?.moveCamera(update)
500
455
  }
501
456
  }
502
457
 
503
- fun setCameraBounds(bounds: LatLngBounds?) {
458
+ fun setCameraBounds(bounds: LatLngBounds?) =
504
459
  onUi {
505
460
  googleMap?.setLatLngBoundsForCameraTarget(bounds)
506
461
  }
507
- }
508
462
 
509
463
  fun animateToBounds(
510
464
  bounds: LatLngBounds,
511
465
  padding: Int,
512
466
  durationMs: Int,
513
467
  lockBounds: Boolean,
514
- ) {
515
- onUi {
516
- if (lockBounds) {
517
- googleMap?.setLatLngBoundsForCameraTarget(bounds)
518
- }
519
- val update =
520
- CameraUpdateFactory.newLatLngBounds(
521
- bounds,
522
- padding,
523
- )
524
- googleMap?.animateCamera(update, durationMs, null)
468
+ ) = onUi {
469
+ if (lockBounds) {
470
+ googleMap?.setLatLngBoundsForCameraTarget(bounds)
525
471
  }
472
+ val update = CameraUpdateFactory.newLatLngBounds(bounds, padding)
473
+ googleMap?.animateCamera(update, durationMs, null)
526
474
  }
527
475
 
528
476
  fun snapshot(
@@ -540,12 +488,7 @@ class GoogleMapsViewImpl(
540
488
  promise.resolve(null)
541
489
  return@snapshot
542
490
  }
543
-
544
- val scaledBitmap =
545
- size?.let {
546
- bitmap.scale(it.width, it.height)
547
- } ?: bitmap
548
-
491
+ val scaledBitmap = size?.let { bitmap.scale(it.width, it.height) } ?: bitmap
549
492
  val output = ByteArrayOutputStream()
550
493
  scaledBitmap.compress(compressFormat, (quality * 100).toInt().coerceIn(0, 100), output)
551
494
  val bytes = output.toByteArray()
@@ -559,367 +502,282 @@ class GoogleMapsViewImpl(
559
502
  promise.resolve("data:image/$format;base64,$base64")
560
503
  }
561
504
 
562
- if (scaledBitmap != bitmap) {
563
- scaledBitmap.recycle()
564
- }
505
+ if (scaledBitmap !== bitmap) scaledBitmap.recycle()
565
506
  bitmap.recycle()
566
- } catch (e: Exception) {
507
+ } catch (_: Exception) {
567
508
  promise.resolve(null)
568
509
  }
569
510
  }
570
511
  }
571
-
572
512
  return promise
573
513
  }
574
514
 
575
515
  fun addMarker(
576
516
  id: String,
577
517
  opts: MarkerOptions,
578
- ) {
518
+ ) = onUi {
579
519
  if (googleMap == null) {
580
520
  pendingMarkers.add(id to opts)
581
- return
582
- }
583
-
584
- onUi {
585
- markersById.remove(id)?.remove()
521
+ return@onUi
586
522
  }
523
+ markersById.remove(id)?.remove()
587
524
  internalAddMarker(id, opts)
588
525
  }
589
526
 
590
527
  private fun internalAddMarker(
591
528
  id: String,
592
529
  opts: MarkerOptions,
593
- ) {
594
- onUi {
595
- val marker =
596
- googleMap?.addMarker(opts).also {
597
- it?.tag = id
598
- }
599
- if (marker != null) {
600
- markersById[id] = marker
601
- }
602
- }
530
+ ) = onUi {
531
+ val marker = googleMap?.addMarker(opts).also { it?.tag = id }
532
+ if (marker != null) markersById[id] = marker
603
533
  }
604
534
 
605
535
  fun updateMarker(
606
536
  id: String,
607
537
  block: (Marker) -> Unit,
608
- ) {
609
- val marker = markersById[id] ?: return
610
- onUi {
611
- block(marker)
612
- }
538
+ ) = onUi {
539
+ val marker = markersById[id] ?: return@onUi
540
+ block(marker)
613
541
  }
614
542
 
615
- fun removeMarker(id: String) {
543
+ fun removeMarker(id: String) =
616
544
  onUi {
617
- val marker = markersById.remove(id)
618
- marker?.remove()
545
+ markersById.remove(id)?.remove()
619
546
  }
620
- }
621
547
 
622
- fun clearMarkers() {
548
+ fun clearMarkers() =
623
549
  onUi {
624
550
  markersById.values.forEach { it.remove() }
551
+ markersById.clear()
552
+ pendingMarkers.clear()
625
553
  }
626
- markersById.clear()
627
- pendingMarkers.clear()
628
- }
629
554
 
630
555
  fun addPolyline(
631
556
  id: String,
632
557
  opts: PolylineOptions,
633
- ) {
558
+ ) = onUi {
634
559
  if (googleMap == null) {
635
560
  pendingPolylines.add(id to opts)
636
- return
637
- }
638
- onUi {
639
- polylinesById.remove(id)?.remove()
561
+ return@onUi
640
562
  }
563
+ polylinesById.remove(id)?.remove()
641
564
  internalAddPolyline(id, opts)
642
565
  }
643
566
 
644
567
  private fun internalAddPolyline(
645
568
  id: String,
646
569
  opts: PolylineOptions,
647
- ) {
648
- onUi {
649
- val polyline =
650
- googleMap?.addPolyline(opts).also {
651
- it?.tag = id
652
- }
653
- if (polyline != null) {
654
- polylinesById[id] = polyline
655
- }
656
- }
570
+ ) = onUi {
571
+ val pl = googleMap?.addPolyline(opts).also { it?.tag = id }
572
+ if (pl != null) polylinesById[id] = pl
657
573
  }
658
574
 
659
575
  fun updatePolyline(
660
576
  id: String,
661
577
  block: (Polyline) -> Unit,
662
- ) {
663
- val pl = polylinesById[id] ?: return
664
- onUi {
665
- block(pl)
666
- }
578
+ ) = onUi {
579
+ val pl = polylinesById[id] ?: return@onUi
580
+ block(pl)
667
581
  }
668
582
 
669
- fun removePolyline(id: String) {
583
+ fun removePolyline(id: String) =
670
584
  onUi {
671
585
  polylinesById.remove(id)?.remove()
672
586
  }
673
- }
674
587
 
675
- fun clearPolylines() {
588
+ fun clearPolylines() =
676
589
  onUi {
677
590
  polylinesById.values.forEach { it.remove() }
591
+ polylinesById.clear()
592
+ pendingPolylines.clear()
678
593
  }
679
- polylinesById.clear()
680
- pendingPolylines.clear()
681
- }
682
594
 
683
595
  fun addPolygon(
684
596
  id: String,
685
597
  opts: PolygonOptions,
686
- ) {
598
+ ) = onUi {
687
599
  if (googleMap == null) {
688
600
  pendingPolygons.add(id to opts)
689
- return
690
- }
691
-
692
- onUi {
693
- polygonsById.remove(id)?.remove()
601
+ return@onUi
694
602
  }
603
+ polygonsById.remove(id)?.remove()
695
604
  internalAddPolygon(id, opts)
696
605
  }
697
606
 
698
607
  private fun internalAddPolygon(
699
608
  id: String,
700
609
  opts: PolygonOptions,
701
- ) {
702
- onUi {
703
- val polygon =
704
- googleMap?.addPolygon(opts).also {
705
- it?.tag = id
706
- }
707
- if (polygon != null) {
708
- polygonsById[id] = polygon
709
- }
710
- }
610
+ ) = onUi {
611
+ val polygon = googleMap?.addPolygon(opts).also { it?.tag = id }
612
+ if (polygon != null) polygonsById[id] = polygon
711
613
  }
712
614
 
713
615
  fun updatePolygon(
714
616
  id: String,
715
617
  block: (Polygon) -> Unit,
716
- ) {
717
- val polygon = polygonsById[id] ?: return
718
- onUi {
719
- block(polygon)
720
- }
618
+ ) = onUi {
619
+ val polygon = polygonsById[id] ?: return@onUi
620
+ block(polygon)
721
621
  }
722
622
 
723
- fun removePolygon(id: String) {
623
+ fun removePolygon(id: String) =
724
624
  onUi {
725
625
  polygonsById.remove(id)?.remove()
726
626
  }
727
- }
728
627
 
729
- fun clearPolygons() {
628
+ fun clearPolygons() =
730
629
  onUi {
731
630
  polygonsById.values.forEach { it.remove() }
631
+ polygonsById.clear()
632
+ pendingPolygons.clear()
732
633
  }
733
- polygonsById.clear()
734
- pendingPolygons.clear()
735
- }
736
634
 
737
635
  fun addCircle(
738
636
  id: String,
739
637
  opts: CircleOptions,
740
- ) {
638
+ ) = onUi {
741
639
  if (googleMap == null) {
742
640
  pendingCircles.add(id to opts)
743
- return
744
- }
745
-
746
- onUi {
747
- circlesById.remove(id)?.remove()
641
+ return@onUi
748
642
  }
643
+ circlesById.remove(id)?.remove()
749
644
  internalAddCircle(id, opts)
750
645
  }
751
646
 
752
647
  private fun internalAddCircle(
753
648
  id: String,
754
649
  opts: CircleOptions,
755
- ) {
756
- onUi {
757
- val circle =
758
- googleMap?.addCircle(opts).also {
759
- it?.tag = id
760
- }
761
- if (circle != null) {
762
- circlesById[id] = circle
763
- }
764
- }
650
+ ) = onUi {
651
+ val circle = googleMap?.addCircle(opts).also { it?.tag = id }
652
+ if (circle != null) circlesById[id] = circle
765
653
  }
766
654
 
767
655
  fun updateCircle(
768
656
  id: String,
769
657
  block: (Circle) -> Unit,
770
- ) {
771
- val circle = circlesById[id] ?: return
772
- onUi {
773
- block(circle)
774
- }
658
+ ) = onUi {
659
+ val circle = circlesById[id] ?: return@onUi
660
+ block(circle)
775
661
  }
776
662
 
777
- fun removeCircle(id: String) {
663
+ fun removeCircle(id: String) =
778
664
  onUi {
779
665
  circlesById.remove(id)?.remove()
780
666
  }
781
- }
782
667
 
783
- fun clearCircles() {
668
+ fun clearCircles() =
784
669
  onUi {
785
670
  circlesById.values.forEach { it.remove() }
671
+ circlesById.clear()
672
+ pendingCircles.clear()
786
673
  }
787
- circlesById.clear()
788
- pendingCircles.clear()
789
- }
790
674
 
791
675
  fun addHeatmap(
792
676
  id: String,
793
677
  opts: TileOverlayOptions,
794
- ) {
678
+ ) = onUi {
795
679
  if (googleMap == null) {
796
680
  pendingHeatmaps.add(id to opts)
797
- return
798
- }
799
-
800
- onUi {
801
- heatmapsById.remove(id)?.remove()
681
+ return@onUi
802
682
  }
683
+ heatmapsById.remove(id)?.remove()
803
684
  internalAddHeatmap(id, opts)
804
685
  }
805
686
 
806
687
  private fun internalAddHeatmap(
807
688
  id: String,
808
689
  opts: TileOverlayOptions,
809
- ) {
810
- onUi {
811
- val heatmap =
812
- googleMap?.addTileOverlay(opts)
813
- if (heatmap != null) {
814
- heatmapsById[id] = heatmap
815
- }
816
- }
690
+ ) = onUi {
691
+ val overlay = googleMap?.addTileOverlay(opts)
692
+ if (overlay != null) heatmapsById[id] = overlay
817
693
  }
818
694
 
819
- fun removeHeatmap(id: String) {
695
+ fun removeHeatmap(id: String) =
820
696
  onUi {
821
697
  heatmapsById.remove(id)?.remove()
822
698
  }
823
- }
824
699
 
825
- fun clearHeatmaps() {
700
+ fun clearHeatmaps() =
826
701
  onUi {
827
702
  heatmapsById.values.forEach { it.remove() }
703
+ heatmapsById.clear()
704
+ pendingHeatmaps.clear()
828
705
  }
829
- heatmapsById.clear()
830
- pendingHeatmaps.clear()
831
- }
832
706
 
833
707
  fun addKmlLayer(
834
708
  id: String,
835
709
  kmlString: String,
836
- ) {
710
+ ) = onUi {
837
711
  if (googleMap == null) {
838
712
  pendingKmlLayers.add(id to kmlString)
839
- return
840
- }
841
- onUi {
842
- kmlLayersById.remove(id)?.removeLayerFromMap()
713
+ return@onUi
843
714
  }
715
+ kmlLayersById.remove(id)?.removeLayerFromMap()
844
716
  internalAddKmlLayer(id, kmlString)
845
717
  }
846
718
 
847
719
  private fun internalAddKmlLayer(
848
720
  id: String,
849
721
  kmlString: String,
850
- ) {
851
- onUi {
852
- try {
853
- val inputStream = ByteArrayInputStream(kmlString.toByteArray(StandardCharsets.UTF_8))
854
- val layer = KmlLayer(googleMap, inputStream, context)
855
- kmlLayersById[id] = layer
856
- layer.addLayerToMap()
857
- } catch (e: Exception) {
858
- // / ignore
859
- }
722
+ ) = onUi {
723
+ try {
724
+ val inputStream = ByteArrayInputStream(kmlString.toByteArray(StandardCharsets.UTF_8))
725
+ val layer = KmlLayer(googleMap, inputStream, context)
726
+ kmlLayersById[id] = layer
727
+ layer.addLayerToMap()
728
+ } catch (_: Exception) {
729
+ // ignore
860
730
  }
861
731
  }
862
732
 
863
- fun removeKmlLayer(id: String) {
733
+ fun removeKmlLayer(id: String) =
864
734
  onUi {
865
735
  kmlLayersById.remove(id)?.removeLayerFromMap()
866
736
  }
867
- }
868
737
 
869
- fun clearKmlLayer() {
738
+ fun clearKmlLayer() =
870
739
  onUi {
871
740
  kmlLayersById.values.forEach { it.removeLayerFromMap() }
741
+ kmlLayersById.clear()
742
+ pendingKmlLayers.clear()
872
743
  }
873
- kmlLayersById.clear()
874
- pendingKmlLayers.clear()
875
- }
876
744
 
877
745
  fun addUrlTileOverlay(
878
746
  id: String,
879
747
  opts: TileOverlayOptions,
880
- ) {
748
+ ) = onUi {
881
749
  if (googleMap == null) {
882
750
  pendingUrlTilesOverlays.add(id to opts)
883
- return
884
- }
885
-
886
- onUi {
887
- urlTileOverlaysById.remove(id)?.remove()
751
+ return@onUi
888
752
  }
753
+ urlTileOverlaysById.remove(id)?.remove()
889
754
  internalAddUrlTileOverlay(id, opts)
890
755
  }
891
756
 
892
757
  private fun internalAddUrlTileOverlay(
893
758
  id: String,
894
759
  opts: TileOverlayOptions,
895
- ) {
896
- onUi {
897
- val urlTile =
898
- googleMap?.addTileOverlay(opts)
899
- if (urlTile != null) {
900
- urlTileOverlaysById[id] = urlTile
901
- }
902
- }
760
+ ) = onUi {
761
+ val overlay = googleMap?.addTileOverlay(opts)
762
+ if (overlay != null) urlTileOverlaysById[id] = overlay
903
763
  }
904
764
 
905
- fun removeUrlTileOverlay(id: String) {
765
+ fun removeUrlTileOverlay(id: String) =
906
766
  onUi {
907
767
  urlTileOverlaysById.remove(id)?.remove()
908
768
  }
909
- }
910
769
 
911
- fun clearUrlTileOverlays() {
770
+ fun clearUrlTileOverlays() =
912
771
  onUi {
913
772
  urlTileOverlaysById.values.forEach { it.remove() }
773
+ urlTileOverlaysById.clear()
774
+ pendingUrlTilesOverlays.clear()
914
775
  }
915
- urlTileOverlaysById.clear()
916
- pendingUrlTilesOverlays.clear()
917
- }
918
776
 
919
- fun destroyInternal() {
920
- if (destroyed) return
921
- destroyed = true
777
+ fun destroyInternal() =
922
778
  onUi {
779
+ if (destroyed) return@onUi
780
+ destroyed = true
923
781
  locationHandler.stop()
924
782
  markerBuilder.cancelAllJobs()
925
783
  clearMarkers()
@@ -958,7 +816,6 @@ class GoogleMapsViewImpl(
958
816
  reactContext.removeLifecycleEventListener(this)
959
817
  initialized = false
960
818
  }
961
- }
962
819
 
963
820
  override fun requestLayout() {
964
821
  super.requestLayout()
@@ -972,130 +829,126 @@ class GoogleMapsViewImpl(
972
829
  }
973
830
  }
974
831
 
975
- override fun onAttachedToWindow() {
976
- super.onAttachedToWindow()
977
- locationHandler.start()
978
- }
832
+ override fun onAttachedToWindow() =
833
+ onUi {
834
+ super.onAttachedToWindow()
835
+ locationHandler.start()
836
+ }
979
837
 
980
- override fun onDetachedFromWindow() {
981
- super.onDetachedFromWindow()
982
- locationHandler.stop()
983
- }
838
+ override fun onDetachedFromWindow() =
839
+ onUi {
840
+ super.onDetachedFromWindow()
841
+ locationHandler.stop()
842
+ }
984
843
 
985
- override fun onHostResume() {
844
+ override fun onHostResume() =
986
845
  onUi {
987
846
  locationHandler.start()
988
847
  mapView?.onResume()
989
848
  }
990
- }
991
849
 
992
- override fun onHostPause() {
850
+ override fun onHostPause() =
993
851
  onUi {
994
852
  locationHandler.stop()
995
853
  mapView?.onPause()
996
854
  }
997
- }
998
855
 
999
856
  override fun onHostDestroy() {
1000
857
  destroyInternal()
1001
858
  }
1002
859
 
1003
860
  override fun onMarkerClick(marker: Marker): Boolean {
1004
- marker.showInfoWindow()
1005
- onMarkerPress?.invoke(marker.tag?.toString())
861
+ onUi {
862
+ marker.showInfoWindow()
863
+ onMarkerPress?.invoke(marker.tag?.toString())
864
+ }
1006
865
  return false
1007
866
  }
1008
867
 
1009
- override fun onPolylineClick(polyline: Polyline) {
1010
- onPolylinePress?.invoke(polyline.tag?.toString())
1011
- }
868
+ override fun onPolylineClick(polyline: Polyline) =
869
+ onUi {
870
+ onPolylinePress?.invoke(polyline.tag?.toString())
871
+ }
1012
872
 
1013
- override fun onPolygonClick(polygon: Polygon) {
1014
- onPolygonPress?.invoke(polygon.tag?.toString())
1015
- }
873
+ override fun onPolygonClick(polygon: Polygon) =
874
+ onUi {
875
+ onPolygonPress?.invoke(polygon.tag?.toString())
876
+ }
1016
877
 
1017
- override fun onCircleClick(circle: Circle) {
1018
- onCirclePress?.invoke(circle.tag?.toString())
1019
- }
878
+ override fun onCircleClick(circle: Circle) =
879
+ onUi {
880
+ onCirclePress?.invoke(circle.tag?.toString())
881
+ }
1020
882
 
1021
- override fun onMapClick(coordinates: LatLng) {
1022
- onMapPress?.invoke(
1023
- coordinates.toRnLatLng(),
1024
- )
1025
- }
883
+ override fun onMapClick(coordinates: LatLng) =
884
+ onUi {
885
+ onMapPress?.invoke(coordinates.toRnLatLng())
886
+ }
1026
887
 
1027
- override fun onMapLongClick(coordinates: LatLng) {
1028
- onMapLongPress?.invoke(
1029
- coordinates.toRnLatLng(),
1030
- )
1031
- }
888
+ override fun onMapLongClick(coordinates: LatLng) =
889
+ onUi {
890
+ onMapLongPress?.invoke(coordinates.toRnLatLng())
891
+ }
1032
892
 
1033
- override fun onMarkerDragStart(marker: Marker) {
1034
- onMarkerDragStart?.invoke(
1035
- marker.tag?.toString(),
1036
- marker.position.toRnLatLng(),
1037
- )
1038
- }
893
+ override fun onMarkerDragStart(marker: Marker) =
894
+ onUi {
895
+ onMarkerDragStart?.invoke(marker.tag?.toString(), marker.position.toRnLatLng())
896
+ }
1039
897
 
1040
- override fun onMarkerDrag(marker: Marker) {
1041
- onMarkerDrag?.invoke(
1042
- marker.tag?.toString(),
1043
- marker.position.toRnLatLng(),
1044
- )
1045
- }
898
+ override fun onMarkerDrag(marker: Marker) =
899
+ onUi {
900
+ onMarkerDrag?.invoke(marker.tag?.toString(), marker.position.toRnLatLng())
901
+ }
1046
902
 
1047
- override fun onMarkerDragEnd(marker: Marker) {
1048
- onMarkerDragEnd?.invoke(
1049
- marker.tag?.toString(),
1050
- marker.position.toRnLatLng(),
1051
- )
1052
- }
903
+ override fun onMarkerDragEnd(marker: Marker) =
904
+ onUi {
905
+ onMarkerDragEnd?.invoke(marker.tag?.toString(), marker.position.toRnLatLng())
906
+ }
1053
907
 
1054
- override fun onIndoorBuildingFocused() {
1055
- val building = googleMap?.focusedBuilding ?: return
1056
- onIndoorBuildingFocused?.invoke(building.toRNIndoorBuilding())
1057
- }
908
+ override fun onIndoorBuildingFocused() =
909
+ onUi {
910
+ val building = googleMap?.focusedBuilding ?: return@onUi
911
+ onIndoorBuildingFocused?.invoke(building.toRNIndoorBuilding())
912
+ }
1058
913
 
1059
- override fun onIndoorLevelActivated(indoorBuilding: IndoorBuilding) {
1060
- val activeLevel = indoorBuilding.levels.getOrNull(indoorBuilding.activeLevelIndex) ?: return
1061
- onIndoorLevelActivated?.invoke(
1062
- activeLevel.toRNIndoorLevel(
1063
- indoorBuilding.activeLevelIndex,
1064
- true,
1065
- ),
1066
- )
1067
- }
914
+ override fun onIndoorLevelActivated(indoorBuilding: IndoorBuilding) =
915
+ onUi {
916
+ val activeLevel =
917
+ indoorBuilding.levels.getOrNull(indoorBuilding.activeLevelIndex) ?: return@onUi
918
+ onIndoorLevelActivated?.invoke(
919
+ activeLevel.toRNIndoorLevel(indoorBuilding.activeLevelIndex, true),
920
+ )
921
+ }
1068
922
 
1069
- override fun onPoiClick(poi: PointOfInterest) {
1070
- onPoiPress?.invoke(poi.placeId, poi.name, poi.latLng.toRnLatLng())
1071
- }
923
+ override fun onPoiClick(poi: PointOfInterest) =
924
+ onUi {
925
+ onPoiPress?.invoke(poi.placeId, poi.name, poi.latLng.toRnLatLng())
926
+ }
1072
927
 
1073
- override fun onInfoWindowClick(marker: Marker) {
1074
- onInfoWindowPress?.invoke(marker.tag?.toString())
1075
- }
928
+ override fun onInfoWindowClick(marker: Marker) =
929
+ onUi {
930
+ onInfoWindowPress?.invoke(marker.tag?.toString())
931
+ }
1076
932
 
1077
- override fun onInfoWindowClose(marker: Marker) {
1078
- onInfoWindowClose?.invoke(marker.tag?.toString())
1079
- }
933
+ override fun onInfoWindowClose(marker: Marker) =
934
+ onUi {
935
+ onInfoWindowClose?.invoke(marker.tag?.toString())
936
+ }
1080
937
 
1081
- override fun onInfoWindowLongClick(marker: Marker) {
1082
- onInfoWindowLongPress?.invoke(marker.tag?.toString())
1083
- }
938
+ override fun onInfoWindowLongClick(marker: Marker) =
939
+ onUi {
940
+ onInfoWindowLongPress?.invoke(marker.tag?.toString())
941
+ }
1084
942
 
1085
- override fun onMyLocationClick(location: Location) {
1086
- onMyLocationPress?.invoke(location.toRnLocation())
1087
- }
943
+ override fun onMyLocationClick(location: Location) =
944
+ onUi {
945
+ onMyLocationPress?.invoke(location.toRnLocation())
946
+ }
1088
947
 
1089
948
  override fun onMyLocationButtonClick(): Boolean {
1090
- onMyLocationButtonPress?.invoke(true)
949
+ onUi {
950
+ onMyLocationButtonPress?.invoke(true)
951
+ }
1091
952
  return false
1092
953
  }
1093
954
  }
1094
-
1095
- private inline fun onUi(crossinline block: () -> Unit) {
1096
- if (UiThreadUtil.isOnUiThread()) {
1097
- block()
1098
- } else {
1099
- UiThreadUtil.runOnUiThread { block() }
1100
- }
1101
- }