also looking at this
feat(maps): add key-free native Android maps and shared map controls
#363
28 files
+1857
-481
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -10,6 +10,9 @@ internal class CraftNativeMapView(context: Context) : FrameLayout(context), OnMa | ||
| 10 | 10 | private var styleVersion = 0 |
| 11 | 11 | private var readyStyle: Style? = null |
| 12 | 12 | private var initialCameraKey: String? = null |
| 13 | private var reportedRegion: LatLngBounds? = null | |
| 14 | private var reportedCamera: CameraPosition? = null | |
| 15 | private var reportedViewport: Pair<Int, Int>? = null | |
| 13 | 16 | private var userChangingCamera = false |
| 14 | 17 | private var geometryPoints = emptyList<LatLng>() |
| 15 | 18 | private val markerHandlers = mutableMapOf<String, String>() |
| @@ -73,10 +76,16 @@ internal class CraftNativeMapView(context: Context) : FrameLayout(context), OnMa | ||
| 73 | 76 | val bounds = nativeMap.projection.visibleRegion.latLngBounds |
| 74 | 77 | val camera = nativeMap.cameraPosition |
| 75 | 78 | val center = camera.target |
| 76 | if (center != null) onRegionChangeComplete?.invoke(JSONObject() | |
| 77 | .put("center", JSONObject().put("latitude", center.latitude).put("longitude", center.longitude)) | |
| 78 | .put("span", JSONObject().put("latitudeDelta", bounds.latitudeNorth - bounds.latitudeSouth).put("longitudeDelta", bounds.longitudeEast - bounds.longitudeWest)) | |
| 79 | .put("heading", camera.bearing).put("pitch", camera.tilt)) | |
| 79 | if (center != null) { | |
| 80 | val event = JSONObject() | |
| 81 | .put("center", JSONObject().put("latitude", center.latitude).put("longitude", center.longitude)) | |
| 82 | .put("span", JSONObject().put("latitudeDelta", bounds.latitudeNorth - bounds.latitudeSouth).put("longitudeDelta", bounds.longitudeEast - bounds.longitudeWest)) | |
| 83 | .put("heading", camera.bearing).put("pitch", camera.tilt) | |
| 84 | reportedRegion = region(event) | |
| 85 | reportedCamera = camera | |
| 86 | reportedViewport = width to height | |
| 87 | onRegionChangeComplete?.invoke(event) | |
| 88 | } | |
| 80 | 89 | } |
| 81 | 90 | } |
| 82 | 91 | applyPending() |
| @@ -123,7 +132,10 @@ internal class CraftNativeMapView(context: Context) : FrameLayout(context), OnMa | ||
| 123 | 132 | val explicit = region(pendingProps.optJSONObject("region")) |
| 124 | 133 | val initial = region(pendingProps.optJSONObject("initialRegion")) |
| 125 | 134 | if (explicit != null) { |
| 126 | moveCamera(explicit, 0) | |
| 135 | // A measured region is a bounding envelope, especially with | |
| 136 | // padding or rotation. Refitting its unchanged echo would zoom | |
| 137 | // out after every gesture. New requests still move the camera. | |
| 138 | if (!isCurrentReportedRegion(explicit)) moveCamera(explicit, 0) | |
| 127 | 139 | initialCameraKey = null |
| 128 | 140 | } else if (initial != null) { |
| 129 | 141 | val key = "region:${pendingProps.optJSONObject("initialRegion")}" |
| @@ -298,6 +310,20 @@ internal class CraftNativeMapView(context: Context) : FrameLayout(context), OnMa | ||
| 298 | 310 | } |
| 299 | 311 | } |
| 300 | 312 | |
| 313 | private fun isCurrentReportedRegion(requested: LatLngBounds): Boolean { | |
| 314 | val reported = reportedRegion ?: return false | |
| 315 | val measured = reportedCamera ?: return false | |
| 316 | val current = map?.cameraPosition ?: return false | |
| 317 | val measuredTarget = measured.target ?: return false | |
| 318 | val currentTarget = current.target ?: return false | |
| 319 | fun same(a: Double, b: Double): Boolean = abs(a - b) < 0.000000001 | |
| 320 | return reportedViewport == (width to height) && | |
| 321 | same(requested.latitudeNorth, reported.latitudeNorth) && same(requested.latitudeSouth, reported.latitudeSouth) && | |
| 322 | same(requested.longitudeEast, reported.longitudeEast) && same(requested.longitudeWest, reported.longitudeWest) && | |
| 323 | abs(current.zoom - measured.zoom) < 0.000001 && | |
| 324 | same(currentTarget.latitude, measuredTarget.latitude) && same(currentTarget.longitude, measuredTarget.longitude) | |
| 325 | } | |
| 326 | ||
| 301 | 327 | private fun applyOrientation() { |
| 302 | 328 | val nativeMap = map ?: return |
| 303 | 329 | val camera = nativeMap.cameraPosition |
| @@ -351,6 +377,7 @@ internal class CraftNativeMapView(context: Context) : FrameLayout(context), OnMa | ||
| 351 | 377 | if (lifecycleStarted) { mapView.onPause(); mapView.onStop(); lifecycleStarted = false } |
| 352 | 378 | mapView.onDestroy() |
| 353 | 379 | readyStyle = null; map = null |
| 380 | reportedRegion = null; reportedCamera = null; reportedViewport = null | |
| 354 | 381 | } |
| 355 | 382 | |
| 356 | 383 | private fun coordinates(value: JSONArray?): List<LatLng> { |