react-native-google-maps-plus 1.7.0-dev.1 → 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 (95) hide show
  1. package/android/src/main/java/com/rngooglemapsplus/GoogleMapsViewImpl.kt +457 -451
  2. package/android/src/main/java/com/rngooglemapsplus/LocationHandler.kt +3 -8
  3. package/android/src/main/java/com/rngooglemapsplus/MapCircleBuilder.kt +2 -1
  4. package/android/src/main/java/com/rngooglemapsplus/MapHeatmapBuilder.kt +1 -1
  5. package/android/src/main/java/com/rngooglemapsplus/MapHelper.kt +22 -0
  6. package/android/src/main/java/com/rngooglemapsplus/MapMarkerBuilder.kt +103 -2
  7. package/android/src/main/java/com/rngooglemapsplus/MapPolygonBuilder.kt +2 -1
  8. package/android/src/main/java/com/rngooglemapsplus/MapPolylineBuilder.kt.kt +2 -1
  9. package/android/src/main/java/com/rngooglemapsplus/MapUrlTileOverlayBuilder.kt +40 -0
  10. package/android/src/main/java/com/rngooglemapsplus/RNGoogleMapsPlusView.kt +84 -34
  11. package/android/src/main/java/com/rngooglemapsplus/extensions/LatLngBoundsExtension.kt +10 -0
  12. package/android/src/main/java/com/rngooglemapsplus/extensions/MapObjectTagExtensions.kt +84 -0
  13. package/android/src/main/java/com/rngooglemapsplus/extensions/RNLatLngBoundsExtension.kt +2 -8
  14. package/android/src/main/java/com/rngooglemapsplus/extensions/RNMapTypeExtension.kt +13 -0
  15. package/android/src/main/java/com/rngooglemapsplus/extensions/VisibleRegionExtension.kt +13 -0
  16. package/ios/GoogleMapViewImpl.swift +164 -48
  17. package/ios/MapCircleBuilder.swift +2 -0
  18. package/ios/MapHeatmapBuilder.swift +2 -1
  19. package/ios/MapMarkerBuilder.swift +54 -1
  20. package/ios/MapPolygonBuilder.swift +2 -0
  21. package/ios/MapPolylineBuilder.swift +2 -0
  22. package/ios/MapUrlTileOverlayBuilder.swift +24 -0
  23. package/ios/RNGoogleMapsPlusView.swift +68 -11
  24. package/ios/extensions/GMSCoordinateBounds+Extension.swift +4 -13
  25. package/ios/extensions/GMSVisibleRegion+Extension.swift +14 -0
  26. package/ios/extensions/MapObjectTag+Extension.swift +93 -0
  27. package/ios/extensions/RNLatLngBounds+Extension.swift +4 -4
  28. package/ios/extensions/RNMapType+Extension.swift +18 -0
  29. package/lib/module/types.js.map +1 -1
  30. package/lib/nitrogen/generated/shared/json/RNGoogleMapsPlusViewConfig.json +7 -0
  31. package/lib/typescript/src/RNGoogleMapsPlusView.nitro.d.ts +18 -9
  32. package/lib/typescript/src/RNGoogleMapsPlusView.nitro.d.ts.map +1 -1
  33. package/lib/typescript/src/types.d.ts +18 -5
  34. package/lib/typescript/src/types.d.ts.map +1 -1
  35. package/nitrogen/generated/android/RNGoogleMapsPlusOnLoad.cpp +8 -4
  36. package/nitrogen/generated/android/c++/JFunc_void_RNRegion_RNCamera.hpp +83 -0
  37. package/nitrogen/generated/android/c++/JFunc_void_RNRegion_RNCamera_bool.hpp +2 -0
  38. package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +75 -0
  39. package/nitrogen/generated/android/c++/JFunc_void_std__string_RNLatLng.hpp +77 -0
  40. package/nitrogen/generated/android/c++/JFunc_void_std__string_std__string_RNLatLng.hpp +77 -0
  41. package/nitrogen/generated/android/c++/JHybridRNGoogleMapsPlusViewSpec.cpp +237 -83
  42. package/nitrogen/generated/android/c++/JHybridRNGoogleMapsPlusViewSpec.hpp +32 -16
  43. package/nitrogen/generated/android/c++/JRNLatLngBounds.hpp +8 -8
  44. package/nitrogen/generated/android/c++/JRNMapUiSettings.hpp +11 -3
  45. package/nitrogen/generated/android/c++/JRNMarker.hpp +7 -3
  46. package/nitrogen/generated/android/c++/JRNRegion.hpp +23 -13
  47. package/nitrogen/generated/android/c++/JRNUrlTileOverlay.hpp +78 -0
  48. package/nitrogen/generated/android/c++/views/JHybridRNGoogleMapsPlusViewStateUpdater.cpp +28 -0
  49. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/Func_void_RNRegion_RNCamera.kt +81 -0
  50. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/{Func_void_std__optional_std__string_.kt → Func_void_std__string.kt} +12 -12
  51. 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
  52. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/Func_void_std__string_std__string_RNLatLng.kt +81 -0
  53. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/HybridRNGoogleMapsPlusViewSpec.kt +122 -24
  54. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/RNLatLngBounds.kt +4 -4
  55. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/RNMapUiSettings.kt +9 -3
  56. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/RNMarker.kt +6 -3
  57. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/RNRegion.kt +11 -5
  58. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rngooglemapsplus/RNUrlTileOverlay.kt +52 -0
  59. package/nitrogen/generated/ios/RNGoogleMapsPlus-Swift-Cxx-Bridge.cpp +32 -8
  60. package/nitrogen/generated/ios/RNGoogleMapsPlus-Swift-Cxx-Bridge.hpp +168 -43
  61. package/nitrogen/generated/ios/RNGoogleMapsPlus-Swift-Cxx-Umbrella.hpp +3 -0
  62. package/nitrogen/generated/ios/c++/HybridRNGoogleMapsPlusViewSpecSwift.hpp +86 -22
  63. package/nitrogen/generated/ios/c++/views/HybridRNGoogleMapsPlusViewComponent.mm +35 -0
  64. package/nitrogen/generated/ios/swift/Func_void_RNRegion_RNCamera.swift +47 -0
  65. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +6 -6
  66. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +47 -0
  67. package/nitrogen/generated/ios/swift/Func_void_std__string_RNLatLng.swift +47 -0
  68. package/nitrogen/generated/ios/swift/Func_void_std__string_std__string_RNLatLng.swift +47 -0
  69. package/nitrogen/generated/ios/swift/HybridRNGoogleMapsPlusViewSpec.swift +17 -8
  70. package/nitrogen/generated/ios/swift/HybridRNGoogleMapsPlusViewSpec_cxx.swift +340 -138
  71. package/nitrogen/generated/ios/swift/RNLatLngBounds.swift +8 -8
  72. package/nitrogen/generated/ios/swift/RNMapUiSettings.swift +61 -1
  73. package/nitrogen/generated/ios/swift/RNMarker.swift +24 -1
  74. package/nitrogen/generated/ios/swift/RNRegion.swift +33 -11
  75. package/nitrogen/generated/ios/swift/RNUrlTileOverlay.swift +133 -0
  76. package/nitrogen/generated/shared/c++/HybridRNGoogleMapsPlusViewSpec.cpp +16 -0
  77. package/nitrogen/generated/shared/c++/HybridRNGoogleMapsPlusViewSpec.hpp +41 -22
  78. package/nitrogen/generated/shared/c++/RNLatLngBounds.hpp +9 -9
  79. package/nitrogen/generated/shared/c++/RNMapUiSettings.hpp +10 -2
  80. package/nitrogen/generated/shared/c++/RNMarker.hpp +6 -2
  81. package/nitrogen/generated/shared/c++/RNRegion.hpp +24 -13
  82. package/nitrogen/generated/shared/c++/RNUrlTileOverlay.hpp +96 -0
  83. package/nitrogen/generated/shared/c++/views/HybridRNGoogleMapsPlusViewComponent.cpp +100 -16
  84. package/nitrogen/generated/shared/c++/views/HybridRNGoogleMapsPlusViewComponent.hpp +18 -10
  85. package/nitrogen/generated/shared/json/RNGoogleMapsPlusViewConfig.json +7 -0
  86. package/package.json +4 -2
  87. package/src/RNGoogleMapsPlusView.nitro.ts +20 -8
  88. package/src/types.ts +19 -5
  89. package/android/src/main/java/com/rngooglemapsplus/extensions/LatLngBounds.kt +0 -15
  90. package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__string_.hpp +0 -76
  91. package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__string__RNLatLng.hpp +0 -78
  92. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string__RNLatLng.swift +0 -54
  93. /package/android/src/main/java/com/rngooglemapsplus/extensions/{RNSize.kt → RNSizeExtension.kt} +0 -0
  94. /package/android/src/main/java/com/rngooglemapsplus/extensions/{RNSnapshotFormat.kt → RNSnapshotFormatExtension.kt} +0 -0
  95. /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
@@ -145,9 +144,8 @@ class LocationHandler(
145
144
  fusedLocationClientProviderClient.lastLocation
146
145
  .addOnSuccessListener(
147
146
  OnSuccessListener { location ->
148
- if (location != null && location != lastSubmittedLocation) {
147
+ if (location != null) {
149
148
  onUpdate?.invoke(location)
150
- lastSubmittedLocation = location
151
149
  }
152
150
  },
153
151
  ).addOnFailureListener { e ->
@@ -159,11 +157,8 @@ class LocationHandler(
159
157
  override fun onLocationResult(locationResult: LocationResult) {
160
158
  val location = locationResult.lastLocation
161
159
  if (location != null) {
162
- if (location != lastSubmittedLocation) {
163
- lastSubmittedLocation = location
164
- listener?.onLocationChanged(location)
165
- onUpdate?.invoke(location)
166
- }
160
+ listener?.onLocationChanged(location)
161
+ onUpdate?.invoke(location)
167
162
  } else {
168
163
  onError?.invoke(RNLocationErrorCode.POSITION_UNAVAILABLE)
169
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,18 +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
5
9
  import android.util.Base64
6
10
  import android.util.LruCache
11
+ import android.widget.ImageView
12
+ import android.widget.LinearLayout
7
13
  import androidx.core.graphics.createBitmap
8
14
  import com.caverock.androidsvg.SVG
9
15
  import com.caverock.androidsvg.SVGExternalFileResolver
10
16
  import com.facebook.react.uimanager.PixelUtil.dpToPx
17
+ import com.facebook.react.uimanager.ThemedReactContext
11
18
  import com.google.android.gms.maps.model.BitmapDescriptor
12
19
  import com.google.android.gms.maps.model.BitmapDescriptorFactory
13
20
  import com.google.android.gms.maps.model.Marker
14
21
  import com.google.android.gms.maps.model.MarkerOptions
15
22
  import com.rngooglemapsplus.extensions.markerStyleEquals
23
+ import com.rngooglemapsplus.extensions.onUi
16
24
  import com.rngooglemapsplus.extensions.styleHash
17
25
  import com.rngooglemapsplus.extensions.toLatLng
18
26
  import kotlinx.coroutines.CoroutineScope
@@ -22,10 +30,14 @@ import kotlinx.coroutines.SupervisorJob
22
30
  import kotlinx.coroutines.ensureActive
23
31
  import kotlinx.coroutines.launch
24
32
  import kotlinx.coroutines.withContext
33
+ import java.net.HttpURLConnection
34
+ import java.net.URL
25
35
  import java.net.URLDecoder
36
+ import java.util.concurrent.ConcurrentHashMap
26
37
  import kotlin.coroutines.coroutineContext
27
38
 
28
39
  class MapMarkerBuilder(
40
+ val context: ThemedReactContext,
29
41
  private val scope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default),
30
42
  ) {
31
43
  private val iconCache =
@@ -36,9 +48,10 @@ class MapMarkerBuilder(
36
48
  ): Int = 1
37
49
  }
38
50
 
39
- private val jobsById = mutableMapOf<String, Job>()
51
+ private val jobsById = ConcurrentHashMap<String, Job>()
40
52
 
41
53
  init {
54
+ // / TODO: refactor with androidsvg 1.5 release
42
55
  SVG.registerExternalFileResolver(
43
56
  object : SVGExternalFileResolver() {
44
57
  override fun resolveImage(filename: String?): Bitmap? {
@@ -64,11 +77,70 @@ class MapMarkerBuilder(
64
77
  }
65
78
  }
66
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
+
67
109
  else -> null
68
110
  }
69
111
  }.getOrNull()
70
112
  }
71
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
+
72
144
  override fun isFormatSupported(mimeType: String?): Boolean = mimeType?.startsWith("image/") == true
73
145
  },
74
146
  )
@@ -96,7 +168,7 @@ class MapMarkerBuilder(
96
168
  prev: RNMarker,
97
169
  next: RNMarker,
98
170
  marker: Marker,
99
- ) {
171
+ ) = onUi {
100
172
  if (prev.coordinate.latitude != next.coordinate.latitude ||
101
173
  prev.coordinate.longitude != next.coordinate.longitude
102
174
  ) {
@@ -171,6 +243,10 @@ class MapMarkerBuilder(
171
243
  if (prev.zIndex != next.zIndex) {
172
244
  marker.zIndex = next.zIndex?.toFloat() ?: 0f
173
245
  }
246
+
247
+ if (prev.infoWindowIconSvg != next.infoWindowIconSvg) {
248
+ marker.tag = MarkerTag(id = next.id, iconSvg = next.infoWindowIconSvg)
249
+ }
174
250
  }
175
251
 
176
252
  fun buildIconAsync(
@@ -228,6 +304,31 @@ class MapMarkerBuilder(
228
304
  iconCache.evictAll()
229
305
  }
230
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
+
231
332
  private suspend fun renderBitmap(m: RNMarker): Bitmap? {
232
333
  m.iconSvg ?: return null
233
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,7 +303,7 @@ class RNGoogleMapsPlusView(
281
303
  view.onMapReady = cb
282
304
  }
283
305
 
284
- override var onMapLoaded: ((Boolean) -> Unit)? = null
306
+ override var onMapLoaded: ((RNRegion, RNCamera) -> Unit)? = null
285
307
  set(cb) {
286
308
  view.onMapLoaded = cb
287
309
  }
@@ -306,37 +328,42 @@ class RNGoogleMapsPlusView(
306
328
  view.onMapLongPress = cb
307
329
  }
308
330
 
309
- override var onMarkerPress: ((String?) -> Unit)? = null
331
+ override var onMarkerPress: ((String) -> Unit)? = null
310
332
  set(cb) {
311
333
  view.onMarkerPress = cb
312
334
  }
313
335
 
314
- 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
315
342
  set(cb) {
316
343
  view.onPolylinePress = cb
317
344
  }
318
345
 
319
- override var onPolygonPress: ((String?) -> Unit)? = null
346
+ override var onPolygonPress: ((String) -> Unit)? = null
320
347
  set(cb) {
321
348
  view.onPolygonPress = cb
322
349
  }
323
350
 
324
- override var onCirclePress: ((String?) -> Unit)? = null
351
+ override var onCirclePress: ((String) -> Unit)? = null
325
352
  set(cb) {
326
353
  view.onCirclePress = cb
327
354
  }
328
355
 
329
- override var onMarkerDragStart: ((String?, RNLatLng) -> Unit)? = null
356
+ override var onMarkerDragStart: ((String, RNLatLng) -> Unit)? = null
330
357
  set(cb) {
331
358
  view.onMarkerDragStart = cb
332
359
  }
333
360
 
334
- override var onMarkerDrag: ((String?, RNLatLng) -> Unit)? = null
361
+ override var onMarkerDrag: ((String, RNLatLng) -> Unit)? = null
335
362
  set(cb) {
336
363
  view.onMarkerDrag = cb
337
364
  }
338
365
 
339
- override var onMarkerDragEnd: ((String?, RNLatLng) -> Unit)? = null
366
+ override var onMarkerDragEnd: ((String, RNLatLng) -> Unit)? = null
340
367
  set(cb) {
341
368
  view.onMarkerDragEnd = cb
342
369
  }
@@ -351,6 +378,31 @@ class RNGoogleMapsPlusView(
351
378
  view.onIndoorLevelActivated = cb
352
379
  }
353
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
+
354
406
  override var onCameraChangeStart: ((RNRegion, RNCamera, Boolean) -> Unit)? = null
355
407
  set(cb) {
356
408
  view.onCameraChangeStart = cb
@@ -366,19 +418,25 @@ class RNGoogleMapsPlusView(
366
418
  view.onCameraChangeComplete = cb
367
419
  }
368
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
+
369
429
  override fun setCamera(
370
430
  camera: RNCamera,
371
431
  animated: Boolean?,
372
432
  durationMs: Double?,
373
433
  ) {
374
- onUi {
375
- val current = view.currentCamera
376
- view.setCamera(
377
- camera.toCameraPosition(current),
378
- animated == true,
379
- durationMs?.toInt() ?: 3000,
380
- )
381
- }
434
+ val current = view.currentCamera
435
+ view.setCamera(
436
+ camera.toCameraPosition(current),
437
+ animated == true,
438
+ durationMs?.toInt() ?: 3000,
439
+ )
382
440
  }
383
441
 
384
442
  override fun setCameraToCoordinates(
@@ -436,11 +494,3 @@ class RNGoogleMapsPlusView(
436
494
 
437
495
  override fun isGooglePlayServicesAvailable(): Boolean = playServiceHandler.isPlayServicesAvailable()
438
496
  }
439
-
440
- private inline fun onUi(crossinline block: () -> Unit) {
441
- if (UiThreadUtil.isOnUiThread()) {
442
- block()
443
- } else {
444
- UiThreadUtil.runOnUiThread { block() }
445
- }
446
- }
@@ -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
+ )
@@ -0,0 +1,84 @@
1
+ import android.util.Log
2
+ import com.google.android.gms.maps.model.Circle
3
+ import com.google.android.gms.maps.model.Marker
4
+ import com.google.android.gms.maps.model.Polygon
5
+ import com.google.android.gms.maps.model.Polyline
6
+ import com.rngooglemapsplus.RNMarkerSvg
7
+
8
+ sealed class MapObjectTag(
9
+ open val id: String,
10
+ )
11
+
12
+ data class MarkerTag(
13
+ override val id: String,
14
+ val iconSvg: RNMarkerSvg? = null,
15
+ ) : MapObjectTag(id)
16
+
17
+ data class PolylineTag(
18
+ override val id: String,
19
+ ) : MapObjectTag(id)
20
+
21
+ data class PolygonTag(
22
+ override val id: String,
23
+ ) : MapObjectTag(id)
24
+
25
+ data class CircleTag(
26
+ override val id: String,
27
+ ) : MapObjectTag(id)
28
+
29
+ val Marker.tagData: MarkerTag
30
+ get() =
31
+ (tag as? MarkerTag) ?: run {
32
+ Log.w("MapTag", "Marker without tag detected at $position")
33
+ val fallback = MarkerTag(id = "unknown")
34
+ tag = fallback
35
+ fallback
36
+ }
37
+
38
+ val Marker.idTag: String
39
+ get() = tagData.id
40
+
41
+ var Polyline.tagData: PolylineTag
42
+ get() =
43
+ (tag as? PolylineTag) ?: run {
44
+ Log.w("MapTag", "Polyline without tag detected")
45
+ val fallback = PolylineTag(id = "unknown")
46
+ tag = fallback
47
+ fallback
48
+ }
49
+ set(value) {
50
+ tag = value
51
+ }
52
+
53
+ val Polyline.idTag: String
54
+ get() = tagData.id
55
+
56
+ var Polygon.tagData: PolygonTag
57
+ get() =
58
+ (tag as? PolygonTag) ?: run {
59
+ Log.w("MapTag", "Polygon without tag detected")
60
+ val fallback = PolygonTag(id = "unknown")
61
+ tag = fallback
62
+ fallback
63
+ }
64
+ set(value) {
65
+ tag = value
66
+ }
67
+
68
+ val Polygon.idTag: String
69
+ get() = tagData.id
70
+
71
+ var Circle.tagData: CircleTag
72
+ get() =
73
+ (tag as? CircleTag) ?: run {
74
+ Log.w("MapTag", "Circle without tag detected")
75
+ val fallback = CircleTag(id = "unknown")
76
+ tag = fallback
77
+ fallback
78
+ }
79
+ set(value) {
80
+ tag = value
81
+ }
82
+
83
+ val Circle.idTag: String
84
+ get() = tagData.id
@@ -6,12 +6,6 @@ import com.rngooglemapsplus.RNLatLngBounds
6
6
 
7
7
  fun RNLatLngBounds.toLatLngBounds(): LatLngBounds =
8
8
  LatLngBounds(
9
- LatLng(
10
- southWest.latitude,
11
- southWest.longitude,
12
- ),
13
- LatLng(
14
- northEast.latitude,
15
- northEast.longitude,
16
- ),
9
+ southwest.toLatLng(),
10
+ northeast.toLatLng(),
17
11
  )