react-native-google-maps-plus 1.6.2 → 1.7.0-dev.10

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 (96) hide show
  1. package/android/proguard-rules.pro +29 -0
  2. package/android/src/main/java/com/rngooglemapsplus/GoogleMapsViewImpl.kt +461 -445
  3. package/android/src/main/java/com/rngooglemapsplus/LocationHandler.kt +5 -8
  4. package/android/src/main/java/com/rngooglemapsplus/MapCircleBuilder.kt +2 -1
  5. package/android/src/main/java/com/rngooglemapsplus/MapHeatmapBuilder.kt +1 -1
  6. package/android/src/main/java/com/rngooglemapsplus/MapHelper.kt +22 -0
  7. package/android/src/main/java/com/rngooglemapsplus/MapMarkerBuilder.kt +142 -2
  8. package/android/src/main/java/com/rngooglemapsplus/MapPolygonBuilder.kt +2 -1
  9. package/android/src/main/java/com/rngooglemapsplus/MapPolylineBuilder.kt.kt +2 -1
  10. package/android/src/main/java/com/rngooglemapsplus/MapUrlTileOverlayBuilder.kt +40 -0
  11. package/android/src/main/java/com/rngooglemapsplus/RNGoogleMapsPlusView.kt +93 -33
  12. package/android/src/main/java/com/rngooglemapsplus/extensions/LatLngBoundsExtension.kt +10 -0
  13. package/android/src/main/java/com/rngooglemapsplus/extensions/MapObjectTagExtensions.kt +84 -0
  14. package/android/src/main/java/com/rngooglemapsplus/extensions/RNLatLngBoundsExtension.kt +2 -8
  15. package/android/src/main/java/com/rngooglemapsplus/extensions/RNMapTypeExtension.kt +13 -0
  16. package/android/src/main/java/com/rngooglemapsplus/extensions/VisibleRegionExtension.kt +13 -0
  17. package/ios/GoogleMapViewImpl.swift +182 -48
  18. package/ios/MapCircleBuilder.swift +2 -0
  19. package/ios/MapHeatmapBuilder.swift +2 -1
  20. package/ios/MapMarkerBuilder.swift +54 -1
  21. package/ios/MapPolygonBuilder.swift +2 -0
  22. package/ios/MapPolylineBuilder.swift +2 -0
  23. package/ios/MapUrlTileOverlayBuilder.swift +24 -0
  24. package/ios/RNGoogleMapsPlusView.swift +75 -10
  25. package/ios/extensions/GMSCoordinateBounds+Extension.swift +4 -13
  26. package/ios/extensions/GMSVisibleRegion+Extension.swift +14 -0
  27. package/ios/extensions/MapObjectTag+Extension.swift +93 -0
  28. package/ios/extensions/RNLatLngBounds+Extension.swift +4 -4
  29. package/ios/extensions/RNMapType+Extension.swift +18 -0
  30. package/lib/module/types.js.map +1 -1
  31. package/lib/nitrogen/generated/shared/json/RNGoogleMapsPlusViewConfig.json +9 -0
  32. package/lib/typescript/src/RNGoogleMapsPlusView.nitro.d.ts +19 -8
  33. package/lib/typescript/src/RNGoogleMapsPlusView.nitro.d.ts.map +1 -1
  34. package/lib/typescript/src/types.d.ts +18 -5
  35. package/lib/typescript/src/types.d.ts.map +1 -1
  36. package/nitrogen/generated/android/RNGoogleMapsPlusOnLoad.cpp +8 -4
  37. package/nitrogen/generated/android/c++/JFunc_void_RNRegion_RNCamera.hpp +83 -0
  38. package/nitrogen/generated/android/c++/JFunc_void_RNRegion_RNCamera_bool.hpp +2 -0
  39. package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +75 -0
  40. package/nitrogen/generated/android/c++/JFunc_void_std__string_RNLatLng.hpp +77 -0
  41. package/nitrogen/generated/android/c++/JFunc_void_std__string_std__string_RNLatLng.hpp +77 -0
  42. package/nitrogen/generated/android/c++/JHybridRNGoogleMapsPlusViewSpec.cpp +265 -73
  43. package/nitrogen/generated/android/c++/JHybridRNGoogleMapsPlusViewSpec.hpp +34 -14
  44. package/nitrogen/generated/android/c++/JRNLatLngBounds.hpp +8 -8
  45. package/nitrogen/generated/android/c++/JRNMapUiSettings.hpp +11 -3
  46. package/nitrogen/generated/android/c++/JRNMarker.hpp +7 -3
  47. package/nitrogen/generated/android/c++/JRNRegion.hpp +23 -13
  48. package/nitrogen/generated/android/c++/JRNUrlTileOverlay.hpp +78 -0
  49. package/nitrogen/generated/android/c++/views/JHybridRNGoogleMapsPlusViewStateUpdater.cpp +36 -0
  50. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/Func_void_RNRegion_RNCamera.kt +81 -0
  51. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/{Func_void_std__optional_std__string_.kt → Func_void_std__string.kt} +12 -12
  52. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/{Func_void_std__optional_std__string__RNLatLng.kt → Func_void_std__string_RNLatLng.kt} +12 -12
  53. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/Func_void_std__string_std__string_RNLatLng.kt +81 -0
  54. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/HybridRNGoogleMapsPlusViewSpec.kt +147 -21
  55. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/RNLatLngBounds.kt +4 -4
  56. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/RNMapUiSettings.kt +9 -3
  57. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/RNMarker.kt +6 -3
  58. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/RNRegion.kt +11 -5
  59. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/RNUrlTileOverlay.kt +52 -0
  60. package/nitrogen/generated/ios/RNGoogleMapsPlus-Swift-Cxx-Bridge.cpp +32 -8
  61. package/nitrogen/generated/ios/RNGoogleMapsPlus-Swift-Cxx-Bridge.hpp +176 -36
  62. package/nitrogen/generated/ios/RNGoogleMapsPlus-Swift-Cxx-Umbrella.hpp +3 -0
  63. package/nitrogen/generated/ios/c++/HybridRNGoogleMapsPlusViewSpecSwift.hpp +98 -20
  64. package/nitrogen/generated/ios/c++/views/HybridRNGoogleMapsPlusViewComponent.mm +45 -0
  65. package/nitrogen/generated/ios/swift/Func_void_RNRegion_RNCamera.swift +47 -0
  66. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +6 -6
  67. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +47 -0
  68. package/nitrogen/generated/ios/swift/Func_void_std__string_RNLatLng.swift +47 -0
  69. package/nitrogen/generated/ios/swift/Func_void_std__string_std__string_RNLatLng.swift +47 -0
  70. package/nitrogen/generated/ios/swift/HybridRNGoogleMapsPlusViewSpec.swift +18 -7
  71. package/nitrogen/generated/ios/swift/HybridRNGoogleMapsPlusViewSpec_cxx.swift +392 -126
  72. package/nitrogen/generated/ios/swift/RNLatLngBounds.swift +8 -8
  73. package/nitrogen/generated/ios/swift/RNMapUiSettings.swift +61 -1
  74. package/nitrogen/generated/ios/swift/RNMarker.swift +24 -1
  75. package/nitrogen/generated/ios/swift/RNRegion.swift +33 -11
  76. package/nitrogen/generated/ios/swift/RNUrlTileOverlay.swift +133 -0
  77. package/nitrogen/generated/shared/c++/HybridRNGoogleMapsPlusViewSpec.cpp +20 -0
  78. package/nitrogen/generated/shared/c++/HybridRNGoogleMapsPlusViewSpec.hpp +43 -20
  79. package/nitrogen/generated/shared/c++/RNLatLngBounds.hpp +9 -9
  80. package/nitrogen/generated/shared/c++/RNMapUiSettings.hpp +10 -2
  81. package/nitrogen/generated/shared/c++/RNMarker.hpp +6 -2
  82. package/nitrogen/generated/shared/c++/RNRegion.hpp +24 -13
  83. package/nitrogen/generated/shared/c++/RNUrlTileOverlay.hpp +96 -0
  84. package/nitrogen/generated/shared/c++/views/HybridRNGoogleMapsPlusViewComponent.cpp +122 -14
  85. package/nitrogen/generated/shared/c++/views/HybridRNGoogleMapsPlusViewComponent.hpp +19 -9
  86. package/nitrogen/generated/shared/json/RNGoogleMapsPlusViewConfig.json +9 -0
  87. package/package.json +8 -5
  88. package/src/RNGoogleMapsPlusView.nitro.ts +21 -7
  89. package/src/types.ts +19 -5
  90. package/android/src/main/java/com/rngooglemapsplus/extensions/LatLngBounds.kt +0 -15
  91. package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__string_.hpp +0 -76
  92. package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__string__RNLatLng.hpp +0 -78
  93. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string__RNLatLng.swift +0 -54
  94. /package/android/src/main/java/com/rngooglemapsplus/extensions/{RNSize.kt → RNSizeExtension.kt} +0 -0
  95. /package/android/src/main/java/com/rngooglemapsplus/extensions/{RNSnapshotFormat.kt → RNSnapshotFormatExtension.kt} +0 -0
  96. /package/android/src/main/java/com/rngooglemapsplus/extensions/{RNSnapshotResultType.kt → RNSnapshotResultTypeExtension.kt} +0 -0
@@ -38,7 +38,6 @@ class LocationHandler(
38
38
  private var priority: Int = PRIORITY_DEFAULT
39
39
  private var interval: Long = INTERVAL_DEFAULT
40
40
  private var minUpdateInterval: Long = MIN_UPDATE_INTERVAL
41
- private var lastSubmittedLocation: Location? = null
42
41
  private var isActive = false
43
42
 
44
43
  var onUpdate: ((Location) -> Unit)? = null
@@ -57,6 +56,8 @@ class LocationHandler(
57
56
  this.interval = interval ?: INTERVAL_DEFAULT
58
57
  this.minUpdateInterval = minUpdateInterval ?: MIN_UPDATE_INTERVAL
59
58
  buildLocationRequest(this.priority, this.interval, this.minUpdateInterval)
59
+ stop()
60
+ start()
60
61
  }
61
62
 
62
63
  fun showLocationDialog() {
@@ -143,9 +144,8 @@ class LocationHandler(
143
144
  fusedLocationClientProviderClient.lastLocation
144
145
  .addOnSuccessListener(
145
146
  OnSuccessListener { location ->
146
- if (location != null && location != lastSubmittedLocation) {
147
+ if (location != null) {
147
148
  onUpdate?.invoke(location)
148
- lastSubmittedLocation = location
149
149
  }
150
150
  },
151
151
  ).addOnFailureListener { e ->
@@ -157,11 +157,8 @@ class LocationHandler(
157
157
  override fun onLocationResult(locationResult: LocationResult) {
158
158
  val location = locationResult.lastLocation
159
159
  if (location != null) {
160
- if (location != lastSubmittedLocation) {
161
- lastSubmittedLocation = location
162
- listener?.onLocationChanged(location)
163
- onUpdate?.invoke(location)
164
- }
160
+ listener?.onLocationChanged(location)
161
+ onUpdate?.invoke(location)
165
162
  } else {
166
163
  onError?.invoke(RNLocationErrorCode.POSITION_UNAVAILABLE)
167
164
  }
@@ -4,6 +4,7 @@ import android.graphics.Color
4
4
  import com.facebook.react.uimanager.PixelUtil.dpToPx
5
5
  import com.google.android.gms.maps.model.Circle
6
6
  import com.google.android.gms.maps.model.CircleOptions
7
+ import com.rngooglemapsplus.extensions.onUi
7
8
  import com.rngooglemapsplus.extensions.toColor
8
9
  import com.rngooglemapsplus.extensions.toLatLng
9
10
 
@@ -23,7 +24,7 @@ class MapCircleBuilder {
23
24
  prev: RNCircle,
24
25
  next: RNCircle,
25
26
  circle: Circle,
26
- ) {
27
+ ) = onUi {
27
28
  if (prev.center.latitude != next.center.latitude ||
28
29
  prev.center.longitude != next.center.longitude
29
30
  ) {
@@ -19,7 +19,7 @@ class MapHeatmapBuilder {
19
19
  heatmap.gradient?.let {
20
20
  val colors = it.colors.map { c -> c.toColor() }.toIntArray()
21
21
  val startPoints = it.startPoints.map { p -> p.toFloat() }.toFloatArray()
22
- gradient(Gradient(colors, startPoints))
22
+ gradient(Gradient(colors, startPoints, it.colorMapSize.toInt()))
23
23
  }
24
24
  }.build()
25
25
 
@@ -0,0 +1,22 @@
1
+ package com.rngooglemapsplus.extensions
2
+
3
+ import com.facebook.react.bridge.UiThreadUtil
4
+ import kotlinx.coroutines.CompletableDeferred
5
+ import kotlinx.coroutines.runBlocking
6
+
7
+ inline fun onUi(crossinline block: () -> Unit) {
8
+ if (UiThreadUtil.isOnUiThread()) {
9
+ block()
10
+ } else {
11
+ UiThreadUtil.runOnUiThread { block() }
12
+ }
13
+ }
14
+
15
+ inline fun <T> onUiSync(crossinline block: () -> T): T {
16
+ if (UiThreadUtil.isOnUiThread()) return block()
17
+ val result = CompletableDeferred<T>()
18
+ UiThreadUtil.runOnUiThread {
19
+ runCatching(block).onSuccess(result::complete).onFailure(result::completeExceptionally)
20
+ }
21
+ return runBlocking { result.await() }
22
+ }
@@ -1,16 +1,26 @@
1
1
  package com.rngooglemapsplus
2
2
 
3
+ import MarkerTag
3
4
  import android.graphics.Bitmap
5
+ import android.graphics.BitmapFactory
4
6
  import android.graphics.Canvas
7
+ import android.graphics.Typeface
8
+ import android.graphics.drawable.PictureDrawable
9
+ import android.util.Base64
5
10
  import android.util.LruCache
11
+ import android.widget.ImageView
12
+ import android.widget.LinearLayout
6
13
  import androidx.core.graphics.createBitmap
7
14
  import com.caverock.androidsvg.SVG
15
+ import com.caverock.androidsvg.SVGExternalFileResolver
8
16
  import com.facebook.react.uimanager.PixelUtil.dpToPx
17
+ import com.facebook.react.uimanager.ThemedReactContext
9
18
  import com.google.android.gms.maps.model.BitmapDescriptor
10
19
  import com.google.android.gms.maps.model.BitmapDescriptorFactory
11
20
  import com.google.android.gms.maps.model.Marker
12
21
  import com.google.android.gms.maps.model.MarkerOptions
13
22
  import com.rngooglemapsplus.extensions.markerStyleEquals
23
+ import com.rngooglemapsplus.extensions.onUi
14
24
  import com.rngooglemapsplus.extensions.styleHash
15
25
  import com.rngooglemapsplus.extensions.toLatLng
16
26
  import kotlinx.coroutines.CoroutineScope
@@ -20,9 +30,14 @@ import kotlinx.coroutines.SupervisorJob
20
30
  import kotlinx.coroutines.ensureActive
21
31
  import kotlinx.coroutines.launch
22
32
  import kotlinx.coroutines.withContext
33
+ import java.net.HttpURLConnection
34
+ import java.net.URL
35
+ import java.net.URLDecoder
36
+ import java.util.concurrent.ConcurrentHashMap
23
37
  import kotlin.coroutines.coroutineContext
24
38
 
25
39
  class MapMarkerBuilder(
40
+ val context: ThemedReactContext,
26
41
  private val scope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default),
27
42
  ) {
28
43
  private val iconCache =
@@ -33,7 +48,103 @@ class MapMarkerBuilder(
33
48
  ): Int = 1
34
49
  }
35
50
 
36
- private val jobsById = mutableMapOf<String, Job>()
51
+ private val jobsById = ConcurrentHashMap<String, Job>()
52
+
53
+ init {
54
+ // / TODO: refactor with androidsvg 1.5 release
55
+ SVG.registerExternalFileResolver(
56
+ object : SVGExternalFileResolver() {
57
+ override fun resolveImage(filename: String?): Bitmap? {
58
+ if (filename.isNullOrBlank()) return null
59
+
60
+ return runCatching {
61
+ when {
62
+ filename.startsWith("data:image/svg+xml") -> {
63
+ val svgContent =
64
+ if ("base64," in filename) {
65
+ val base64 = filename.substringAfter("base64,")
66
+ String(Base64.decode(base64, Base64.DEFAULT), Charsets.UTF_8)
67
+ } else {
68
+ URLDecoder.decode(filename.substringAfter(","), "UTF-8")
69
+ }
70
+
71
+ val svg = SVG.getFromString(svgContent)
72
+ val width = (svg.documentWidth.takeIf { it > 0 } ?: 128f).toInt()
73
+ val height = (svg.documentHeight.takeIf { it > 0 } ?: 128f).toInt()
74
+
75
+ createBitmap(width, height).apply {
76
+ Canvas(this).also(svg::renderToCanvas)
77
+ }
78
+ }
79
+
80
+ filename.startsWith("http://") || filename.startsWith("https://") -> {
81
+ val conn =
82
+ (URL(filename).openConnection() as HttpURLConnection).apply {
83
+ connectTimeout = 5000
84
+ readTimeout = 5000
85
+ requestMethod = "GET"
86
+ instanceFollowRedirects = true
87
+ }
88
+ conn.connect()
89
+
90
+ val contentType = conn.contentType ?: ""
91
+ val result =
92
+ if (contentType.contains("svg") || filename.endsWith(".svg")) {
93
+ val svgText = conn.inputStream.bufferedReader().use { it.readText() }
94
+ val innerSvg = SVG.getFromString(svgText)
95
+ val w = innerSvg.documentWidth.takeIf { it > 0 } ?: 128f
96
+ val h = innerSvg.documentHeight.takeIf { it > 0 } ?: 128f
97
+ val bmp = createBitmap(w.toInt(), h.toInt())
98
+ val canvas = Canvas(bmp)
99
+ innerSvg.renderToCanvas(canvas)
100
+ bmp
101
+ } else {
102
+ conn.inputStream.use { BitmapFactory.decodeStream(it) }
103
+ }
104
+
105
+ conn.disconnect()
106
+ result
107
+ }
108
+
109
+ else -> null
110
+ }
111
+ }.getOrNull()
112
+ }
113
+
114
+ override fun resolveFont(
115
+ fontFamily: String?,
116
+ fontWeight: Int,
117
+ fontStyle: String?,
118
+ ): Typeface? {
119
+ if (fontFamily.isNullOrBlank()) return null
120
+
121
+ return runCatching {
122
+ val assetManager = context.assets
123
+
124
+ val candidates =
125
+ listOf(
126
+ "fonts/$fontFamily.ttf",
127
+ "fonts/$fontFamily.otf",
128
+ )
129
+
130
+ for (path in candidates) {
131
+ try {
132
+ return Typeface.createFromAsset(assetManager, path)
133
+ } catch (_: Throwable) {
134
+ // / ignore
135
+ }
136
+ }
137
+
138
+ Typeface.create(fontFamily, Typeface.NORMAL)
139
+ }.getOrElse {
140
+ Typeface.create(fontFamily, fontWeight)
141
+ }
142
+ }
143
+
144
+ override fun isFormatSupported(mimeType: String?): Boolean = mimeType?.startsWith("image/") == true
145
+ },
146
+ )
147
+ }
37
148
 
38
149
  fun build(
39
150
  m: RNMarker,
@@ -57,7 +168,7 @@ class MapMarkerBuilder(
57
168
  prev: RNMarker,
58
169
  next: RNMarker,
59
170
  marker: Marker,
60
- ) {
171
+ ) = onUi {
61
172
  if (prev.coordinate.latitude != next.coordinate.latitude ||
62
173
  prev.coordinate.longitude != next.coordinate.longitude
63
174
  ) {
@@ -132,6 +243,10 @@ class MapMarkerBuilder(
132
243
  if (prev.zIndex != next.zIndex) {
133
244
  marker.zIndex = next.zIndex?.toFloat() ?: 0f
134
245
  }
246
+
247
+ if (prev.infoWindowIconSvg != next.infoWindowIconSvg) {
248
+ marker.tag = MarkerTag(id = next.id, iconSvg = next.infoWindowIconSvg)
249
+ }
135
250
  }
136
251
 
137
252
  fun buildIconAsync(
@@ -189,6 +304,31 @@ class MapMarkerBuilder(
189
304
  iconCache.evictAll()
190
305
  }
191
306
 
307
+ fun buildInfoWindow(iconSvg: RNMarkerSvg?): ImageView? {
308
+ val iconSvg = iconSvg ?: return null
309
+
310
+ val svgView =
311
+ ImageView(context).apply {
312
+ layoutParams =
313
+ LinearLayout.LayoutParams(
314
+ iconSvg.width.dpToPx().toInt(),
315
+ iconSvg.height.dpToPx().toInt(),
316
+ )
317
+ }
318
+
319
+ try {
320
+ val svg = SVG.getFromString(iconSvg.svgString)
321
+ svg.setDocumentWidth(iconSvg.width.dpToPx())
322
+ svg.setDocumentHeight(iconSvg.height.dpToPx())
323
+ val drawable = PictureDrawable(svg.renderToPicture())
324
+ svgView.setImageDrawable(drawable)
325
+ } catch (e: Exception) {
326
+ return null
327
+ }
328
+
329
+ return svgView
330
+ }
331
+
192
332
  private suspend fun renderBitmap(m: RNMarker): Bitmap? {
193
333
  m.iconSvg ?: return null
194
334
 
@@ -4,6 +4,7 @@ import android.graphics.Color
4
4
  import com.facebook.react.uimanager.PixelUtil.dpToPx
5
5
  import com.google.android.gms.maps.model.Polygon
6
6
  import com.google.android.gms.maps.model.PolygonOptions
7
+ import com.rngooglemapsplus.extensions.onUi
7
8
  import com.rngooglemapsplus.extensions.toColor
8
9
  import com.rngooglemapsplus.extensions.toLatLng
9
10
 
@@ -30,7 +31,7 @@ class MapPolygonBuilder {
30
31
  prev: RNPolygon,
31
32
  next: RNPolygon,
32
33
  poly: Polygon,
33
- ) {
34
+ ) = onUi {
34
35
  val coordsChanged =
35
36
  prev.coordinates.size != next.coordinates.size ||
36
37
  !prev.coordinates.zip(next.coordinates).all { (a, b) ->
@@ -9,6 +9,7 @@ import com.google.android.gms.maps.model.Polyline
9
9
  import com.google.android.gms.maps.model.PolylineOptions
10
10
  import com.google.android.gms.maps.model.RoundCap
11
11
  import com.google.android.gms.maps.model.SquareCap
12
+ import com.rngooglemapsplus.extensions.onUi
12
13
  import com.rngooglemapsplus.extensions.toColor
13
14
  import com.rngooglemapsplus.extensions.toLatLng
14
15
 
@@ -34,7 +35,7 @@ class MapPolylineBuilder {
34
35
  prev: RNPolyline,
35
36
  next: RNPolyline,
36
37
  polyline: Polyline,
37
- ) {
38
+ ) = onUi {
38
39
  val coordsChanged =
39
40
  prev.coordinates.size != next.coordinates.size ||
40
41
  !prev.coordinates.zip(next.coordinates).all { (a, b) ->
@@ -0,0 +1,40 @@
1
+ package com.rngooglemapsplus
2
+
3
+ import com.google.android.gms.maps.model.TileOverlayOptions
4
+ import com.google.android.gms.maps.model.UrlTileProvider
5
+ import java.net.URL
6
+
7
+ class MapUrlTileOverlayBuilder {
8
+ fun build(t: RNUrlTileOverlay): TileOverlayOptions {
9
+ val provider =
10
+ object : UrlTileProvider(
11
+ t.tileSize.toInt(),
12
+ t.tileSize.toInt(),
13
+ ) {
14
+ override fun getTileUrl(
15
+ x: Int,
16
+ y: Int,
17
+ zoom: Int,
18
+ ): URL? {
19
+ val url =
20
+ t.url
21
+ .replace("{x}", x.toString())
22
+ .replace("{y}", y.toString())
23
+ .replace("{z}", zoom.toString())
24
+
25
+ return try {
26
+ URL(url)
27
+ } catch (e: Exception) {
28
+ null
29
+ }
30
+ }
31
+ }
32
+
33
+ val opts = TileOverlayOptions().tileProvider(provider)
34
+
35
+ t.fadeIn?.let { opts.fadeIn(it) }
36
+ t.zIndex?.let { opts.zIndex(it.toFloat()) }
37
+ t.opacity?.let { opts.transparency(1f - it.toFloat()) }
38
+ return opts
39
+ }
40
+ }
@@ -1,7 +1,7 @@
1
1
  package com.rngooglemapsplus
2
2
 
3
+ import MarkerTag
3
4
  import com.facebook.proguard.annotations.DoNotStrip
4
- import com.facebook.react.bridge.UiThreadUtil
5
5
  import com.facebook.react.uimanager.ThemedReactContext
6
6
  import com.google.android.gms.maps.GoogleMapOptions
7
7
  import com.google.android.gms.maps.model.MapStyleOptions
@@ -14,6 +14,7 @@ import com.rngooglemapsplus.extensions.polylineEquals
14
14
  import com.rngooglemapsplus.extensions.toCameraPosition
15
15
  import com.rngooglemapsplus.extensions.toCompressFormat
16
16
  import com.rngooglemapsplus.extensions.toFileExtension
17
+ import com.rngooglemapsplus.extensions.toGoogleMapType
17
18
  import com.rngooglemapsplus.extensions.toLatLngBounds
18
19
  import com.rngooglemapsplus.extensions.toMapColorScheme
19
20
  import com.rngooglemapsplus.extensions.toSize
@@ -28,11 +29,12 @@ class RNGoogleMapsPlusView(
28
29
  private var locationHandler = LocationHandler(context)
29
30
  private var playServiceHandler = PlayServicesHandler(context)
30
31
 
31
- private val markerBuilder = MapMarkerBuilder()
32
+ private val markerBuilder = MapMarkerBuilder(context)
32
33
  private val polylineBuilder = MapPolylineBuilder()
33
34
  private val polygonBuilder = MapPolygonBuilder()
34
35
  private val circleBuilder = MapCircleBuilder()
35
36
  private val heatmapBuilder = MapHeatmapBuilder()
37
+ private val urlTileOverlayBuilder = MapUrlTileOverlayBuilder()
36
38
 
37
39
  override val view =
38
40
  GoogleMapsViewImpl(context, locationHandler, playServiceHandler, markerBuilder)
@@ -128,9 +130,7 @@ class RNGoogleMapsPlusView(
128
130
  set(value) {
129
131
  if (field == value) return
130
132
  field = value
131
- value?.let {
132
- view.mapType = it.value
133
- }
133
+ view.mapType = value?.toGoogleMapType()
134
134
  }
135
135
 
136
136
  override var markers: Array<RNMarker>? = null
@@ -150,12 +150,19 @@ class RNGoogleMapsPlusView(
150
150
  when {
151
151
  prev == null ->
152
152
  markerBuilder.buildIconAsync(id, next) { icon ->
153
- view.addMarker(id, markerBuilder.build(next, icon))
153
+ view.addMarker(
154
+ id,
155
+ markerBuilder.build(next, icon),
156
+ MarkerTag(
157
+ id = id,
158
+ iconSvg = next.infoWindowIconSvg,
159
+ ),
160
+ )
154
161
  }
155
162
 
156
163
  !prev.markerEquals(next) ->
157
164
  view.updateMarker(id) { marker ->
158
- onUi { markerBuilder.update(prev, next, marker) }
165
+ markerBuilder.update(prev, next, marker)
159
166
  }
160
167
  }
161
168
  }
@@ -179,7 +186,7 @@ class RNGoogleMapsPlusView(
179
186
 
180
187
  !prev.polylineEquals(next) ->
181
188
  view.updatePolyline(id) { polyline ->
182
- onUi { polylineBuilder.update(prev, next, polyline) }
189
+ polylineBuilder.update(prev, next, polyline)
183
190
  }
184
191
  }
185
192
  }
@@ -204,7 +211,7 @@ class RNGoogleMapsPlusView(
204
211
 
205
212
  !prev.polygonEquals(next) ->
206
213
  view.updatePolygon(id) { polygon ->
207
- onUi { polygonBuilder.update(prev, next, polygon) }
214
+ polygonBuilder.update(prev, next, polygon)
208
215
  }
209
216
  }
210
217
  }
@@ -229,7 +236,7 @@ class RNGoogleMapsPlusView(
229
236
 
230
237
  !prev.circleEquals(next) ->
231
238
  view.updateCircle(id) { circle ->
232
- onUi { circleBuilder.update(prev, next, circle) }
239
+ circleBuilder.update(prev, next, circle)
233
240
  }
234
241
  }
235
242
  }
@@ -264,6 +271,21 @@ class RNGoogleMapsPlusView(
264
271
  }
265
272
  }
266
273
 
274
+ override var urlTileOverlays: Array<RNUrlTileOverlay>? = null
275
+ set(value) {
276
+ if (field.contentEquals(value)) return
277
+ val prevById = field?.associateBy { it.id } ?: emptyMap()
278
+ val nextById = value?.associateBy { it.id } ?: emptyMap()
279
+ field = value
280
+ (prevById.keys - nextById.keys).forEach { id ->
281
+ view.removeUrlTileOverlay(id)
282
+ }
283
+
284
+ nextById.forEach { (id, next) ->
285
+ view.addUrlTileOverlay(id, urlTileOverlayBuilder.build(next))
286
+ }
287
+ }
288
+
267
289
  override var locationConfig: RNLocationConfig? = null
268
290
  set(value) {
269
291
  if (field == value) return
@@ -281,6 +303,11 @@ class RNGoogleMapsPlusView(
281
303
  view.onMapReady = cb
282
304
  }
283
305
 
306
+ override var onMapLoaded: ((RNRegion, RNCamera) -> Unit)? = null
307
+ set(cb) {
308
+ view.onMapLoaded = cb
309
+ }
310
+
284
311
  override var onLocationUpdate: ((RNLocation) -> Unit)? = null
285
312
  set(cb) {
286
313
  view.onLocationUpdate = cb
@@ -296,37 +323,47 @@ class RNGoogleMapsPlusView(
296
323
  view.onMapPress = cb
297
324
  }
298
325
 
299
- override var onMarkerPress: ((String?) -> Unit)? = null
326
+ override var onMapLongPress: ((RNLatLng) -> Unit)? = null
327
+ set(cb) {
328
+ view.onMapLongPress = cb
329
+ }
330
+
331
+ override var onMarkerPress: ((String) -> Unit)? = null
300
332
  set(cb) {
301
333
  view.onMarkerPress = cb
302
334
  }
303
335
 
304
- override var onPolylinePress: ((String?) -> Unit)? = null
336
+ override var onPoiPress: ((String, String, RNLatLng) -> Unit)? = null
337
+ set(cb) {
338
+ view.onPoiPress = cb
339
+ }
340
+
341
+ override var onPolylinePress: ((String) -> Unit)? = null
305
342
  set(cb) {
306
343
  view.onPolylinePress = cb
307
344
  }
308
345
 
309
- override var onPolygonPress: ((String?) -> Unit)? = null
346
+ override var onPolygonPress: ((String) -> Unit)? = null
310
347
  set(cb) {
311
348
  view.onPolygonPress = cb
312
349
  }
313
350
 
314
- override var onCirclePress: ((String?) -> Unit)? = null
351
+ override var onCirclePress: ((String) -> Unit)? = null
315
352
  set(cb) {
316
353
  view.onCirclePress = cb
317
354
  }
318
355
 
319
- override var onMarkerDragStart: ((String?, RNLatLng) -> Unit)? = null
356
+ override var onMarkerDragStart: ((String, RNLatLng) -> Unit)? = null
320
357
  set(cb) {
321
358
  view.onMarkerDragStart = cb
322
359
  }
323
360
 
324
- override var onMarkerDrag: ((String?, RNLatLng) -> Unit)? = null
361
+ override var onMarkerDrag: ((String, RNLatLng) -> Unit)? = null
325
362
  set(cb) {
326
363
  view.onMarkerDrag = cb
327
364
  }
328
365
 
329
- override var onMarkerDragEnd: ((String?, RNLatLng) -> Unit)? = null
366
+ override var onMarkerDragEnd: ((String, RNLatLng) -> Unit)? = null
330
367
  set(cb) {
331
368
  view.onMarkerDragEnd = cb
332
369
  }
@@ -341,6 +378,31 @@ class RNGoogleMapsPlusView(
341
378
  view.onIndoorLevelActivated = cb
342
379
  }
343
380
 
381
+ override var onInfoWindowPress: ((String) -> Unit)? = null
382
+ set(cb) {
383
+ view.onInfoWindowPress = cb
384
+ }
385
+
386
+ override var onInfoWindowClose: ((String) -> Unit)? = null
387
+ set(cb) {
388
+ view.onInfoWindowClose = cb
389
+ }
390
+
391
+ override var onInfoWindowLongPress: ((String) -> Unit)? = null
392
+ set(cb) {
393
+ view.onInfoWindowLongPress = cb
394
+ }
395
+
396
+ override var onMyLocationPress: ((RNLocation) -> Unit)? = null
397
+ set(cb) {
398
+ view.onMyLocationPress = cb
399
+ }
400
+
401
+ override var onMyLocationButtonPress: ((Boolean) -> Unit)? = null
402
+ set(cb) {
403
+ view.onMyLocationButtonPress = cb
404
+ }
405
+
344
406
  override var onCameraChangeStart: ((RNRegion, RNCamera, Boolean) -> Unit)? = null
345
407
  set(cb) {
346
408
  view.onCameraChangeStart = cb
@@ -356,19 +418,25 @@ class RNGoogleMapsPlusView(
356
418
  view.onCameraChangeComplete = cb
357
419
  }
358
420
 
421
+ override fun showMarkerInfoWindow(id: String) {
422
+ view.showMarkerInfoWindow(id)
423
+ }
424
+
425
+ override fun hideMarkerInfoWindow(id: String) {
426
+ view.hideMarkerInfoWindow(id)
427
+ }
428
+
359
429
  override fun setCamera(
360
430
  camera: RNCamera,
361
431
  animated: Boolean?,
362
432
  durationMs: Double?,
363
433
  ) {
364
- onUi {
365
- val current = view.currentCamera
366
- view.setCamera(
367
- camera.toCameraPosition(current),
368
- animated == true,
369
- durationMs?.toInt() ?: 3000,
370
- )
371
- }
434
+ val current = view.currentCamera
435
+ view.setCamera(
436
+ camera.toCameraPosition(current),
437
+ animated == true,
438
+ durationMs?.toInt() ?: 3000,
439
+ )
372
440
  }
373
441
 
374
442
  override fun setCameraToCoordinates(
@@ -426,11 +494,3 @@ class RNGoogleMapsPlusView(
426
494
 
427
495
  override fun isGooglePlayServicesAvailable(): Boolean = playServiceHandler.isPlayServicesAvailable()
428
496
  }
429
-
430
- private inline fun onUi(crossinline block: () -> Unit) {
431
- if (UiThreadUtil.isOnUiThread()) {
432
- block()
433
- } else {
434
- UiThreadUtil.runOnUiThread { block() }
435
- }
436
- }
@@ -0,0 +1,10 @@
1
+ package com.rngooglemapsplus.extensions
2
+
3
+ import com.google.android.gms.maps.model.LatLngBounds
4
+ import com.rngooglemapsplus.RNLatLngBounds
5
+
6
+ fun LatLngBounds.toRnLatLngBounds(): RNLatLngBounds =
7
+ RNLatLngBounds(
8
+ northeast = northeast.toRnLatLng(),
9
+ southwest = southwest.toRnLatLng(),
10
+ )