react-native-google-maps-plus 0.1.0 → 1.0.0
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.
- package/GoogleMapsNitro.podspec +34 -0
- package/LICENSE +20 -0
- package/README.md +40 -0
- package/android/CMakeLists.txt +32 -0
- package/android/build.gradle +135 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +8 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/cpp-adapter.cpp +6 -0
- package/android/src/main/java/com/googlemapsnitro/Color.kt +65 -0
- package/android/src/main/java/com/googlemapsnitro/GoogleMapsNitroPackage.kt +35 -0
- package/android/src/main/java/com/googlemapsnitro/GoogleMapsNitroViewImpl.kt +720 -0
- package/android/src/main/java/com/googlemapsnitro/HybridGoogleMapsNitroModule.kt +22 -0
- package/android/src/main/java/com/googlemapsnitro/HybridGoogleMapsNitroView.kt +337 -0
- package/android/src/main/java/com/googlemapsnitro/LocationHandler.kt +205 -0
- package/android/src/main/java/com/googlemapsnitro/MapMarker.kt +145 -0
- package/android/src/main/java/com/googlemapsnitro/MapPolygon.kt +36 -0
- package/android/src/main/java/com/googlemapsnitro/MapPolyline.kt +59 -0
- package/android/src/main/java/com/googlemapsnitro/PermissionHandler.kt +116 -0
- package/android/src/main/java/com/googlemapsnitro/PlayServicesHandler.kt +25 -0
- package/ios/Color.swift +109 -0
- package/ios/GoogleMapNitroViewImpl.swift +590 -0
- package/ios/HybridGoogleMapsNitroModule.swift +27 -0
- package/ios/HybridGoogleMapsNitroView.swift +348 -0
- package/ios/LocationHandler.swift +205 -0
- package/ios/MapHelper.swift +18 -0
- package/ios/MapMarker.swift +207 -0
- package/ios/MapPolygon.swift +55 -0
- package/ios/MapPolyline.swift +83 -0
- package/ios/PermissionHandler.swift +73 -0
- package/lib/module/GoogleMapsNitroModule.nitro.js +4 -0
- package/lib/module/GoogleMapsNitroModule.nitro.js.map +1 -0
- package/lib/module/GoogleMapsNitroView.nitro.js +4 -0
- package/lib/module/GoogleMapsNitroView.nitro.js.map +1 -0
- package/lib/module/index.js +8 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +78 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/GoogleMapsNitroModule.nitro.d.ts +12 -0
- package/lib/typescript/src/GoogleMapsNitroModule.nitro.d.ts.map +1 -0
- package/lib/typescript/src/GoogleMapsNitroView.nitro.d.ts +34 -0
- package/lib/typescript/src/GoogleMapsNitroView.nitro.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +7 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +113 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/nitro.json +28 -0
- package/package.json +13 -3
- package/src/GoogleMapsNitroModule.nitro.ts +13 -0
- package/src/GoogleMapsNitroView.nitro.ts +78 -0
- package/src/index.tsx +24 -0
- package/src/types.ts +174 -0
|
@@ -0,0 +1,720 @@
|
|
|
1
|
+
package com.googlemapsnitro
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.location.Location
|
|
5
|
+
import com.facebook.react.bridge.LifecycleEventListener
|
|
6
|
+
import com.facebook.react.bridge.UiThreadUtil
|
|
7
|
+
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
8
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
9
|
+
import com.google.android.gms.common.ConnectionResult
|
|
10
|
+
import com.google.android.gms.maps.CameraUpdateFactory
|
|
11
|
+
import com.google.android.gms.maps.GoogleMap
|
|
12
|
+
import com.google.android.gms.maps.MapView
|
|
13
|
+
import com.google.android.gms.maps.OnMapReadyCallback
|
|
14
|
+
import com.google.android.gms.maps.model.CameraPosition
|
|
15
|
+
import com.google.android.gms.maps.model.LatLng
|
|
16
|
+
import com.google.android.gms.maps.model.LatLngBounds
|
|
17
|
+
import com.google.android.gms.maps.model.MapColorScheme
|
|
18
|
+
import com.google.android.gms.maps.model.MapStyleOptions
|
|
19
|
+
import com.google.android.gms.maps.model.Marker
|
|
20
|
+
import com.google.android.gms.maps.model.MarkerOptions
|
|
21
|
+
import com.google.android.gms.maps.model.Polygon
|
|
22
|
+
import com.google.android.gms.maps.model.PolygonOptions
|
|
23
|
+
import com.google.android.gms.maps.model.Polyline
|
|
24
|
+
import com.google.android.gms.maps.model.PolylineOptions
|
|
25
|
+
|
|
26
|
+
class GoogleMapsNitroViewImpl(
|
|
27
|
+
val reactContext: ThemedReactContext,
|
|
28
|
+
val locationHandler: LocationHandler,
|
|
29
|
+
val playServiceHandler: PlayServicesHandler,
|
|
30
|
+
val markerOptions: com.googlemapsnitro.MarkerOptions,
|
|
31
|
+
) : MapView(reactContext),
|
|
32
|
+
GoogleMap.OnCameraMoveStartedListener,
|
|
33
|
+
GoogleMap.OnCameraMoveListener,
|
|
34
|
+
GoogleMap.OnCameraIdleListener,
|
|
35
|
+
GoogleMap.OnMapClickListener,
|
|
36
|
+
OnMapReadyCallback,
|
|
37
|
+
GoogleMap.OnMarkerClickListener,
|
|
38
|
+
LifecycleEventListener {
|
|
39
|
+
private var googleMap: GoogleMap? = null
|
|
40
|
+
|
|
41
|
+
private var pendingBuildingEnabled: Boolean = false
|
|
42
|
+
private var pendingTrafficEnabled: Boolean = false
|
|
43
|
+
private var pendingCustomMapStyle: MapStyleOptions? = null
|
|
44
|
+
private var pendingInitialCamera: CameraPosition =
|
|
45
|
+
CameraPosition
|
|
46
|
+
.builder()
|
|
47
|
+
.target(
|
|
48
|
+
LatLng(
|
|
49
|
+
0.0,
|
|
50
|
+
0.0,
|
|
51
|
+
),
|
|
52
|
+
).zoom(0f)
|
|
53
|
+
.bearing(0f)
|
|
54
|
+
.tilt(0f)
|
|
55
|
+
.build()
|
|
56
|
+
private var pendingUserInterfaceStyle: Int = MapColorScheme.FOLLOW_SYSTEM
|
|
57
|
+
private var pendingMinZoomLevel: Double = 0.0
|
|
58
|
+
private var pendingMaxZoomLevel: Double = 21.0
|
|
59
|
+
private var pendingMapPadding: RNMapPadding = RNMapPadding(0.0, 0.0, 0.0, 0.0)
|
|
60
|
+
private val pendingPolygons = mutableListOf<Pair<String, PolygonOptions>>()
|
|
61
|
+
private val pendingPolylines = mutableListOf<Pair<String, PolylineOptions>>()
|
|
62
|
+
private val pendingMarkers = mutableListOf<Pair<String, MarkerOptions>>()
|
|
63
|
+
private var cameraMoveReason = -1
|
|
64
|
+
|
|
65
|
+
private val polygonsById = mutableMapOf<String, Polygon>()
|
|
66
|
+
private val polylinesById = mutableMapOf<String, Polyline>()
|
|
67
|
+
private val markersById = mutableMapOf<String, Marker>()
|
|
68
|
+
|
|
69
|
+
private var lastSubmittedLocation: Location? = null
|
|
70
|
+
private var lastSubmittedCameraPosition: CameraPosition? = null
|
|
71
|
+
|
|
72
|
+
init {
|
|
73
|
+
reactContext.addLifecycleEventListener(this)
|
|
74
|
+
getMap()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private fun getMap() {
|
|
78
|
+
val result = playServiceHandler.playServicesAvailability()
|
|
79
|
+
|
|
80
|
+
when (result) {
|
|
81
|
+
ConnectionResult.SERVICE_MISSING -> {
|
|
82
|
+
onMapError?.invoke(RNMapErrorCode.PLAY_SERVICES_MISSING)
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
ConnectionResult.SERVICE_INVALID -> {
|
|
87
|
+
onMapError?.invoke(RNMapErrorCode.PLAY_SERVICES_INVALID)
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED ->
|
|
92
|
+
onMapError?.invoke(RNMapErrorCode.PLAY_SERVICES_OUTDATED)
|
|
93
|
+
|
|
94
|
+
ConnectionResult.SERVICE_UPDATING ->
|
|
95
|
+
onMapError?.invoke(RNMapErrorCode.PLAY_SERVICE_UPDATING)
|
|
96
|
+
|
|
97
|
+
ConnectionResult.SERVICE_DISABLED ->
|
|
98
|
+
onMapError?.invoke(RNMapErrorCode.PLAY_SERVICES_DISABLED)
|
|
99
|
+
|
|
100
|
+
ConnectionResult.SUCCESS -> {}
|
|
101
|
+
|
|
102
|
+
else ->
|
|
103
|
+
onMapError?.invoke(RNMapErrorCode.UNKNOWN)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
onCreate(null)
|
|
107
|
+
getMapAsync(this@GoogleMapsNitroViewImpl)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
override fun onCameraMoveStarted(reason: Int) {
|
|
111
|
+
lastSubmittedCameraPosition = null
|
|
112
|
+
cameraMoveReason = reason
|
|
113
|
+
val bounds = googleMap?.projection?.visibleRegion?.latLngBounds
|
|
114
|
+
val cameraPosition = googleMap?.cameraPosition
|
|
115
|
+
if (bounds == null || cameraPosition == null) {
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
val isGesture = GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE == reason
|
|
119
|
+
|
|
120
|
+
val latDelta = bounds.northeast.latitude - bounds.southwest.latitude
|
|
121
|
+
val lngDelta = bounds.northeast.longitude - bounds.southwest.longitude
|
|
122
|
+
|
|
123
|
+
onCameraChangeStart?.invoke(
|
|
124
|
+
RNRegion(
|
|
125
|
+
center = RNLatLng(bounds.center.latitude, bounds.center.longitude),
|
|
126
|
+
latitudeDelta = latDelta,
|
|
127
|
+
longitudeDelta = lngDelta,
|
|
128
|
+
),
|
|
129
|
+
RNCamera(
|
|
130
|
+
center = RNLatLng(cameraPosition.target.latitude, cameraPosition.target.longitude),
|
|
131
|
+
zoom = cameraPosition.zoom.toDouble(),
|
|
132
|
+
bearing = cameraPosition.bearing.toDouble(),
|
|
133
|
+
tilt = cameraPosition.tilt.toDouble(),
|
|
134
|
+
),
|
|
135
|
+
isGesture,
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
override fun onCameraMove() {
|
|
140
|
+
val bounds = googleMap?.projection?.visibleRegion?.latLngBounds
|
|
141
|
+
val cameraPosition = googleMap?.cameraPosition
|
|
142
|
+
if (bounds == null || cameraPosition == null) {
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
if (cameraPosition == lastSubmittedCameraPosition) {
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
val isGesture = GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE == cameraMoveReason
|
|
149
|
+
|
|
150
|
+
val latDelta = bounds.northeast.latitude - bounds.southwest.latitude
|
|
151
|
+
val lngDelta = bounds.northeast.longitude - bounds.southwest.longitude
|
|
152
|
+
|
|
153
|
+
onCameraChange?.invoke(
|
|
154
|
+
RNRegion(
|
|
155
|
+
center = RNLatLng(bounds.center.latitude, bounds.center.longitude),
|
|
156
|
+
latitudeDelta = latDelta,
|
|
157
|
+
longitudeDelta = lngDelta,
|
|
158
|
+
),
|
|
159
|
+
RNCamera(
|
|
160
|
+
center = RNLatLng(cameraPosition.target.latitude, cameraPosition.target.longitude),
|
|
161
|
+
zoom = cameraPosition.zoom.toDouble(),
|
|
162
|
+
bearing = cameraPosition.bearing.toDouble(),
|
|
163
|
+
tilt = cameraPosition.tilt.toDouble(),
|
|
164
|
+
),
|
|
165
|
+
isGesture,
|
|
166
|
+
)
|
|
167
|
+
lastSubmittedCameraPosition = cameraPosition
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
override fun onCameraIdle() {
|
|
171
|
+
val bounds = googleMap?.projection?.visibleRegion?.latLngBounds
|
|
172
|
+
val cameraPosition = googleMap?.cameraPosition
|
|
173
|
+
|
|
174
|
+
if (bounds == null || cameraPosition == null) {
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
val isGesture = GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE == cameraMoveReason
|
|
178
|
+
|
|
179
|
+
val latDelta = bounds.northeast.latitude - bounds.southwest.latitude
|
|
180
|
+
val lngDelta = bounds.northeast.longitude - bounds.southwest.longitude
|
|
181
|
+
|
|
182
|
+
onCameraChangeComplete?.invoke(
|
|
183
|
+
RNRegion(
|
|
184
|
+
center = RNLatLng(bounds.center.latitude, bounds.center.longitude),
|
|
185
|
+
latitudeDelta = latDelta,
|
|
186
|
+
longitudeDelta = lngDelta,
|
|
187
|
+
),
|
|
188
|
+
RNCamera(
|
|
189
|
+
center = RNLatLng(cameraPosition.target.latitude, cameraPosition.target.longitude),
|
|
190
|
+
zoom = cameraPosition.zoom.toDouble(),
|
|
191
|
+
bearing = cameraPosition.bearing.toDouble(),
|
|
192
|
+
tilt = cameraPosition.tilt.toDouble(),
|
|
193
|
+
),
|
|
194
|
+
isGesture,
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@SuppressLint("PotentialBehaviorOverride")
|
|
199
|
+
override fun onMapReady(map: GoogleMap) {
|
|
200
|
+
googleMap = map
|
|
201
|
+
googleMap?.setOnMapLoadedCallback {
|
|
202
|
+
googleMap?.setOnCameraMoveStartedListener(this)
|
|
203
|
+
googleMap?.setOnCameraMoveListener(this)
|
|
204
|
+
googleMap?.setOnCameraIdleListener(this)
|
|
205
|
+
googleMap?.setOnMarkerClickListener(this)
|
|
206
|
+
googleMap?.setOnMapClickListener(this)
|
|
207
|
+
}
|
|
208
|
+
initLocationCallbacks()
|
|
209
|
+
applyPending()
|
|
210
|
+
|
|
211
|
+
onMapReady?.invoke(true)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
fun initLocationCallbacks() {
|
|
215
|
+
locationHandler.onUpdate = { location ->
|
|
216
|
+
// / only the coordinated are relevant right now
|
|
217
|
+
if (lastSubmittedLocation?.latitude != location.latitude || lastSubmittedLocation?.longitude != location.longitude ||
|
|
218
|
+
lastSubmittedLocation?.bearing != location.bearing
|
|
219
|
+
) {
|
|
220
|
+
onLocationUpdate?.invoke(
|
|
221
|
+
RNLocation(
|
|
222
|
+
RNLatLng(location.latitude, location.longitude),
|
|
223
|
+
location.bearing.toDouble(),
|
|
224
|
+
),
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
lastSubmittedLocation = location
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
locationHandler.onError = { error ->
|
|
231
|
+
onLocationError?.invoke(error)
|
|
232
|
+
}
|
|
233
|
+
locationHandler.start()
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
fun applyPending() {
|
|
237
|
+
onUi {
|
|
238
|
+
googleMap?.setPadding(
|
|
239
|
+
pendingMapPadding.left.dpToPx().toInt(),
|
|
240
|
+
pendingMapPadding.top.dpToPx().toInt(),
|
|
241
|
+
pendingMapPadding.right.dpToPx().toInt(),
|
|
242
|
+
pendingMapPadding.bottom.dpToPx().toInt(),
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
pendingInitialCamera.let {
|
|
246
|
+
googleMap?.moveCamera(
|
|
247
|
+
CameraUpdateFactory.newCameraPosition(
|
|
248
|
+
it,
|
|
249
|
+
),
|
|
250
|
+
)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
googleMap?.isBuildingsEnabled = pendingBuildingEnabled
|
|
254
|
+
googleMap?.isTrafficEnabled = pendingTrafficEnabled
|
|
255
|
+
googleMap?.setMapStyle(pendingCustomMapStyle)
|
|
256
|
+
googleMap?.mapColorScheme = pendingUserInterfaceStyle
|
|
257
|
+
googleMap?.setMinZoomPreference(pendingMinZoomLevel.toFloat())
|
|
258
|
+
googleMap?.setMaxZoomPreference(pendingMaxZoomLevel.toFloat())
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (pendingMarkers.isNotEmpty()) {
|
|
262
|
+
pendingMarkers.forEach { (id, opts) ->
|
|
263
|
+
internalAddMarker(id, opts)
|
|
264
|
+
}
|
|
265
|
+
pendingMarkers.clear()
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (pendingPolylines.isNotEmpty()) {
|
|
269
|
+
pendingPolylines.forEach { (id, opts) ->
|
|
270
|
+
internalAddPolyline(id, opts)
|
|
271
|
+
}
|
|
272
|
+
pendingPolylines.clear()
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (pendingPolygons.isNotEmpty()) {
|
|
276
|
+
pendingPolygons.forEach { (id, opts) ->
|
|
277
|
+
internalAddPolygon(id, opts)
|
|
278
|
+
}
|
|
279
|
+
pendingPolygons.clear()
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
var buildingEnabled: Boolean
|
|
284
|
+
get() = googleMap?.isBuildingsEnabled ?: pendingBuildingEnabled
|
|
285
|
+
set(value) {
|
|
286
|
+
pendingBuildingEnabled = value
|
|
287
|
+
onUi {
|
|
288
|
+
googleMap?.isBuildingsEnabled = value
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
var trafficEnabled: Boolean
|
|
293
|
+
get() = googleMap?.isTrafficEnabled ?: pendingTrafficEnabled
|
|
294
|
+
set(value) {
|
|
295
|
+
pendingTrafficEnabled = value
|
|
296
|
+
onUi {
|
|
297
|
+
googleMap?.isTrafficEnabled = value
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
var customMapStyle: MapStyleOptions?
|
|
302
|
+
get() = pendingCustomMapStyle
|
|
303
|
+
set(value) {
|
|
304
|
+
pendingCustomMapStyle = value
|
|
305
|
+
onUi {
|
|
306
|
+
googleMap?.setMapStyle(value)
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
var initialCamera: CameraPosition
|
|
311
|
+
get() = pendingInitialCamera
|
|
312
|
+
set(value) {
|
|
313
|
+
pendingInitialCamera = value
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
var userInterfaceStyle: Int
|
|
317
|
+
get() = pendingUserInterfaceStyle
|
|
318
|
+
set(value) {
|
|
319
|
+
pendingUserInterfaceStyle = value
|
|
320
|
+
onUi {
|
|
321
|
+
googleMap?.mapColorScheme = value
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
var minZoomLevel: Double
|
|
326
|
+
get() = pendingMinZoomLevel
|
|
327
|
+
set(value) {
|
|
328
|
+
pendingMinZoomLevel = value
|
|
329
|
+
onUi {
|
|
330
|
+
googleMap?.setMinZoomPreference(value.toFloat())
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
var maxZoomLevel: Double
|
|
335
|
+
get() = pendingMaxZoomLevel
|
|
336
|
+
set(value) {
|
|
337
|
+
pendingMaxZoomLevel = value
|
|
338
|
+
onUi {
|
|
339
|
+
googleMap?.setMaxZoomPreference(value.toFloat())
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
var mapPadding: RNMapPadding
|
|
344
|
+
get() = pendingMapPadding
|
|
345
|
+
set(value) {
|
|
346
|
+
pendingMapPadding = value
|
|
347
|
+
onUi {
|
|
348
|
+
googleMap?.setPadding(
|
|
349
|
+
value.left.dpToPx().toInt(),
|
|
350
|
+
value.top.dpToPx().toInt(),
|
|
351
|
+
value.right.dpToPx().toInt(),
|
|
352
|
+
value.bottom.dpToPx().toInt(),
|
|
353
|
+
)
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
var onMapError: ((RNMapErrorCode) -> Unit)? = null
|
|
358
|
+
var onMapReady: ((Boolean) -> Unit)? = null
|
|
359
|
+
var onLocationUpdate: ((RNLocation) -> Unit)? = null
|
|
360
|
+
var onLocationError: ((RNLocationErrorCode) -> Unit)? = null
|
|
361
|
+
var onMapPress: ((RNLatLng) -> Unit)? = null
|
|
362
|
+
var onMarkerPress: ((String) -> Unit)? = null
|
|
363
|
+
var onCameraChangeStart: ((RNRegion, RNCamera, Boolean) -> Unit)? = null
|
|
364
|
+
var onCameraChange: ((RNRegion, RNCamera, Boolean) -> Unit)? = null
|
|
365
|
+
var onCameraChangeComplete: ((RNRegion, RNCamera, Boolean) -> Unit)? = null
|
|
366
|
+
|
|
367
|
+
fun setCamera(
|
|
368
|
+
camera: RNCamera,
|
|
369
|
+
animated: Boolean,
|
|
370
|
+
durationMS: Int,
|
|
371
|
+
) {
|
|
372
|
+
onUi {
|
|
373
|
+
val current = googleMap?.cameraPosition
|
|
374
|
+
if (current == null) {
|
|
375
|
+
return@onUi
|
|
376
|
+
}
|
|
377
|
+
val camPosBuilder =
|
|
378
|
+
CameraPosition.Builder(
|
|
379
|
+
current,
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
camera.center?.let {
|
|
383
|
+
camPosBuilder.target(
|
|
384
|
+
LatLng(
|
|
385
|
+
it.latitude,
|
|
386
|
+
it.longitude,
|
|
387
|
+
),
|
|
388
|
+
)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
camera.zoom?.let {
|
|
392
|
+
camPosBuilder.zoom(it.toFloat())
|
|
393
|
+
}
|
|
394
|
+
camera.bearing?.let {
|
|
395
|
+
camPosBuilder.bearing(it.toFloat())
|
|
396
|
+
}
|
|
397
|
+
camera.tilt?.let {
|
|
398
|
+
camPosBuilder.tilt(it.toFloat())
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
val camPos = camPosBuilder.build()
|
|
402
|
+
|
|
403
|
+
val update = CameraUpdateFactory.newCameraPosition(camPos)
|
|
404
|
+
|
|
405
|
+
if (animated) {
|
|
406
|
+
googleMap?.animateCamera(update, durationMS, null)
|
|
407
|
+
} else {
|
|
408
|
+
googleMap?.moveCamera(update)
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
fun setCameraToCoordinates(
|
|
414
|
+
coordinates: Array<RNLatLng>,
|
|
415
|
+
padding: RNMapPadding,
|
|
416
|
+
animated: Boolean,
|
|
417
|
+
durationMS: Int,
|
|
418
|
+
) {
|
|
419
|
+
if (coordinates.isEmpty()) {
|
|
420
|
+
return
|
|
421
|
+
}
|
|
422
|
+
onUi {
|
|
423
|
+
val builder = LatLngBounds.Builder()
|
|
424
|
+
coordinates.forEach { coord ->
|
|
425
|
+
builder.include(LatLng(coord.latitude, coord.longitude))
|
|
426
|
+
}
|
|
427
|
+
val bounds = builder.build()
|
|
428
|
+
|
|
429
|
+
val latSpan = bounds.northeast.latitude - bounds.southwest.latitude
|
|
430
|
+
val lngSpan = bounds.northeast.longitude - bounds.southwest.longitude
|
|
431
|
+
|
|
432
|
+
val latPerPixel = latSpan / height
|
|
433
|
+
val lngPerPixel = lngSpan / width
|
|
434
|
+
|
|
435
|
+
builder.include(
|
|
436
|
+
LatLng(
|
|
437
|
+
bounds.northeast.latitude + (padding.top.dpToPx() * latPerPixel),
|
|
438
|
+
bounds.northeast.longitude,
|
|
439
|
+
),
|
|
440
|
+
)
|
|
441
|
+
builder.include(
|
|
442
|
+
LatLng(
|
|
443
|
+
bounds.southwest.latitude - (padding.bottom.dpToPx() * latPerPixel),
|
|
444
|
+
bounds.southwest.longitude,
|
|
445
|
+
),
|
|
446
|
+
)
|
|
447
|
+
builder.include(
|
|
448
|
+
LatLng(
|
|
449
|
+
bounds.northeast.latitude,
|
|
450
|
+
bounds.northeast.longitude + (padding.right.dpToPx() * lngPerPixel),
|
|
451
|
+
),
|
|
452
|
+
)
|
|
453
|
+
builder.include(
|
|
454
|
+
LatLng(
|
|
455
|
+
bounds.southwest.latitude,
|
|
456
|
+
bounds.southwest.longitude - (padding.left.dpToPx() * lngPerPixel),
|
|
457
|
+
),
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
val paddedBounds = builder.build()
|
|
461
|
+
|
|
462
|
+
val adjustedWidth = (width - padding.left.dpToPx() - padding.right.dpToPx()).toInt()
|
|
463
|
+
val adjustedHeight = (height - padding.top.dpToPx() - padding.bottom.dpToPx()).toInt()
|
|
464
|
+
|
|
465
|
+
val update =
|
|
466
|
+
CameraUpdateFactory.newLatLngBounds(
|
|
467
|
+
paddedBounds,
|
|
468
|
+
adjustedWidth,
|
|
469
|
+
adjustedHeight,
|
|
470
|
+
0,
|
|
471
|
+
)
|
|
472
|
+
if (animated) {
|
|
473
|
+
googleMap?.animateCamera(update, durationMS, null)
|
|
474
|
+
} else {
|
|
475
|
+
googleMap?.moveCamera(update)
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
fun addMarker(
|
|
481
|
+
id: String,
|
|
482
|
+
opts: MarkerOptions,
|
|
483
|
+
) {
|
|
484
|
+
if (googleMap == null) {
|
|
485
|
+
pendingMarkers.add(id to opts)
|
|
486
|
+
return
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
onUi {
|
|
490
|
+
markersById.remove(id)?.remove()
|
|
491
|
+
}
|
|
492
|
+
internalAddMarker(id, opts)
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
private fun internalAddMarker(
|
|
496
|
+
id: String,
|
|
497
|
+
opts: MarkerOptions,
|
|
498
|
+
) {
|
|
499
|
+
onUi {
|
|
500
|
+
val marker =
|
|
501
|
+
googleMap?.addMarker(opts).also {
|
|
502
|
+
it?.tag = id
|
|
503
|
+
}
|
|
504
|
+
if (marker != null) {
|
|
505
|
+
markersById[id] = marker
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
fun updateMarker(
|
|
511
|
+
id: String,
|
|
512
|
+
block: (Marker) -> Unit,
|
|
513
|
+
) {
|
|
514
|
+
val marker = markersById[id] ?: return
|
|
515
|
+
onUi {
|
|
516
|
+
block(marker)
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
fun removeMarker(id: String) {
|
|
521
|
+
onUi {
|
|
522
|
+
val marker = markersById.remove(id)
|
|
523
|
+
marker?.remove()
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
fun clearMarkers() {
|
|
528
|
+
onUi {
|
|
529
|
+
markersById.values.forEach { it.remove() }
|
|
530
|
+
}
|
|
531
|
+
markersById.clear()
|
|
532
|
+
pendingMarkers.clear()
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
fun addPolyline(
|
|
536
|
+
id: String,
|
|
537
|
+
opts: PolylineOptions,
|
|
538
|
+
) {
|
|
539
|
+
if (googleMap == null) {
|
|
540
|
+
pendingPolylines.add(id to opts)
|
|
541
|
+
return
|
|
542
|
+
}
|
|
543
|
+
onUi {
|
|
544
|
+
polylinesById.remove(id)?.remove()
|
|
545
|
+
}
|
|
546
|
+
internalAddPolyline(id, opts)
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
private fun internalAddPolyline(
|
|
550
|
+
id: String,
|
|
551
|
+
opts: PolylineOptions,
|
|
552
|
+
) {
|
|
553
|
+
onUi {
|
|
554
|
+
val polyline =
|
|
555
|
+
googleMap?.addPolyline(opts).also {
|
|
556
|
+
it?.tag = id
|
|
557
|
+
}
|
|
558
|
+
if (polyline != null) {
|
|
559
|
+
polylinesById[id] = polyline
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
fun updatePolyline(
|
|
565
|
+
id: String,
|
|
566
|
+
block: (Polyline) -> Unit,
|
|
567
|
+
) {
|
|
568
|
+
val pl = polylinesById[id] ?: return
|
|
569
|
+
onUi {
|
|
570
|
+
block(pl)
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
fun removePolyline(id: String) {
|
|
575
|
+
onUi {
|
|
576
|
+
polylinesById.remove(id)?.remove()
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
fun clearPolylines() {
|
|
581
|
+
onUi {
|
|
582
|
+
polylinesById.values.forEach { it.remove() }
|
|
583
|
+
}
|
|
584
|
+
polylinesById.clear()
|
|
585
|
+
pendingPolylines.clear()
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
fun addPolygon(
|
|
589
|
+
id: String,
|
|
590
|
+
opts: PolygonOptions,
|
|
591
|
+
) {
|
|
592
|
+
if (googleMap == null) {
|
|
593
|
+
pendingPolygons.add(id to opts)
|
|
594
|
+
return
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
onUi {
|
|
598
|
+
polygonsById.remove(id)?.remove()
|
|
599
|
+
}
|
|
600
|
+
internalAddPolygon(id, opts)
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
private fun internalAddPolygon(
|
|
604
|
+
id: String,
|
|
605
|
+
opts: PolygonOptions,
|
|
606
|
+
) {
|
|
607
|
+
onUi {
|
|
608
|
+
val polygon =
|
|
609
|
+
googleMap?.addPolygon(opts).also {
|
|
610
|
+
it?.tag = id
|
|
611
|
+
}
|
|
612
|
+
if (polygon != null) {
|
|
613
|
+
polygonsById[id] = polygon
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
fun updatePolygon(
|
|
619
|
+
id: String,
|
|
620
|
+
block: (Polygon) -> Unit,
|
|
621
|
+
) {
|
|
622
|
+
val polygon = polygonsById[id] ?: return
|
|
623
|
+
onUi {
|
|
624
|
+
block(polygon)
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
fun removePolygon(id: String) {
|
|
629
|
+
onUi {
|
|
630
|
+
polygonsById.remove(id)?.remove()
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
fun clearPolygons() {
|
|
635
|
+
onUi {
|
|
636
|
+
polygonsById.values.forEach { it.remove() }
|
|
637
|
+
}
|
|
638
|
+
polygonsById.clear()
|
|
639
|
+
pendingPolygons.clear()
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
fun clearAll() {
|
|
643
|
+
onUi {
|
|
644
|
+
markerOptions.cancelAllJobs()
|
|
645
|
+
clearMarkers()
|
|
646
|
+
clearPolylines()
|
|
647
|
+
clearPolygons()
|
|
648
|
+
locationHandler.stop()
|
|
649
|
+
googleMap?.apply {
|
|
650
|
+
setOnCameraMoveStartedListener(null)
|
|
651
|
+
setOnCameraMoveListener(null)
|
|
652
|
+
setOnCameraIdleListener(null)
|
|
653
|
+
setOnMarkerClickListener(null)
|
|
654
|
+
setOnMapClickListener(null)
|
|
655
|
+
}
|
|
656
|
+
this@GoogleMapsNitroViewImpl.onDestroy()
|
|
657
|
+
googleMap = null
|
|
658
|
+
reactContext.removeLifecycleEventListener(this)
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
override fun requestLayout() {
|
|
663
|
+
super.requestLayout()
|
|
664
|
+
// / setPadding issue
|
|
665
|
+
post {
|
|
666
|
+
measure(
|
|
667
|
+
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
668
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY),
|
|
669
|
+
)
|
|
670
|
+
layout(left, top, right, bottom)
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
override fun onAttachedToWindow() {
|
|
675
|
+
super.onAttachedToWindow()
|
|
676
|
+
locationHandler.start()
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
override fun onDetachedFromWindow() {
|
|
680
|
+
super.onDetachedFromWindow()
|
|
681
|
+
locationHandler.stop()
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
override fun onHostResume() {
|
|
685
|
+
onUi {
|
|
686
|
+
locationHandler.start()
|
|
687
|
+
this@GoogleMapsNitroViewImpl.onResume()
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
override fun onHostPause() {
|
|
692
|
+
onUi {
|
|
693
|
+
locationHandler.stop()
|
|
694
|
+
this@GoogleMapsNitroViewImpl.onPause()
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
override fun onHostDestroy() {
|
|
699
|
+
clearAll()
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
override fun onMarkerClick(marker: Marker): Boolean {
|
|
703
|
+
onMarkerPress?.invoke(marker.tag?.toString() ?: "unknown")
|
|
704
|
+
return true
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
override fun onMapClick(coordinates: LatLng) {
|
|
708
|
+
onMapPress?.invoke(
|
|
709
|
+
RNLatLng(coordinates.latitude, coordinates.longitude),
|
|
710
|
+
)
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
private inline fun onUi(crossinline block: () -> Unit) {
|
|
715
|
+
if (UiThreadUtil.isOnUiThread()) {
|
|
716
|
+
block()
|
|
717
|
+
} else {
|
|
718
|
+
UiThreadUtil.runOnUiThread { block() }
|
|
719
|
+
}
|
|
720
|
+
}
|