ReviewOS

also looking at this

craft-native/craft

feat(maps): add key-free native Android maps and shared map controls

#363
Merged chris wants to merge codex/wildloop-native-map-providers into main
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.

packages/android/src/index.tsmodified+2-0
Changes to packages/android/src/index.ts
@@ -11,6 +11,8 @@ import { androidMapHost, type AndroidMapProvider } from './native-map'
1111import { renderAndroidPromiseRuntime } from './promise-runtime'
1212
1313export type { AndroidMapProvider } from './native-map'
14/** Providers this published builder can generate as real Android map views. */
15export const nativeMapProviders = ['google', 'maplibre'] as const
1416export { runKotlinFixture } from './testing.js'
1517export { createAndroidEmulator } from './emulator.js'
1618export type { AndroidEmulatorOptions, AndroidEmulatorSession } from './emulator.js'
packages/android/templates/CraftNativeMapGoogle.kt.templatemodified+1-0
Changes to packages/android/templates/CraftNativeMapGoogle.kt.template
@@ -92,6 +92,7 @@ private class CraftNativeMapView(context: Context) : FrameLayout(context), OnMap
9292 map.uiSettings.isScrollGesturesEnabled = craftNativeBoolean(pendingProps.opt("scrollEnabled"), true)
9393 map.uiSettings.isZoomGesturesEnabled = craftNativeBoolean(pendingProps.opt("zoomEnabled"), true)
9494 map.uiSettings.isRotateGesturesEnabled = craftNativeBoolean(pendingProps.opt("rotateEnabled"))
95 map.uiSettings.isTiltGesturesEnabled = craftNativeBoolean(pendingProps.opt("pitchEnabled"), true)
9596 map.mapType = when (craftNativeOptionalString(pendingProps.opt("mapType")).orEmpty().lowercase()) {
9697 "satellite" -> GoogleMap.MAP_TYPE_SATELLITE
9798 "hybrid" -> GoogleMap.MAP_TYPE_HYBRID
packages/android/templates/CraftNativeMapLibre.kt.templatemodified+5-4
Changes to packages/android/templates/CraftNativeMapLibre.kt.template
@@ -97,7 +97,7 @@ internal class CraftNativeMapView(context: Context) : FrameLayout(context), OnMa
9797 nativeMap.uiSettings.isScrollGesturesEnabled = craftNativeBoolean(pendingProps.opt("scrollEnabled"), true)
9898 nativeMap.uiSettings.isZoomGesturesEnabled = craftNativeBoolean(pendingProps.opt("zoomEnabled"), true)
9999 nativeMap.uiSettings.isRotateGesturesEnabled = craftNativeBoolean(pendingProps.opt("rotateEnabled"))
100 nativeMap.uiSettings.isTiltGesturesEnabled = true
100 nativeMap.uiSettings.isTiltGesturesEnabled = craftNativeBoolean(pendingProps.opt("pitchEnabled"), true)
101101 // The authored attribution is kept visible rather than hidden in a menu.
102102 nativeMap.uiSettings.isAttributionEnabled = false
103103 nativeMap.uiSettings.isLogoEnabled = false
@@ -128,9 +128,10 @@ internal class CraftNativeMapView(context: Context) : FrameLayout(context), OnMa
128128 val key = "region:${pendingProps.optJSONObject("initialRegion")}"
129129 if (initialCameraKey != key) { moveCamera(initial, 0); initialCameraKey = key }
130130 } else if (craftNativeBoolean(pendingProps.opt("fitToBounds"))) {
131 val key = geometryPoints.joinToString(";") { "${it.latitude},${it.longitude}" }
131 val key = "$width,$height:${pendingProps.optJSONObject("edgePadding")}:" + geometryPoints.joinToString(";") { "${it.latitude},${it.longitude}" }
132132 if (initialCameraKey != key && geometryPoints.isNotEmpty() && width > 0 && height > 0) {
133 if (geometryPoints.size == 1) nativeMap.moveCamera(CameraUpdateFactory.newLatLngZoom(geometryPoints.first(), 15.0))
133 val distinct = geometryPoints.distinctBy { it.latitude to it.longitude }
134 if (distinct.size == 1) nativeMap.moveCamera(CameraUpdateFactory.newLatLngZoom(distinct.first(), 15.0))
134135 else moveCamera(LatLngBounds.Builder().includes(geometryPoints).build(), if (pendingProps.has("edgePadding")) 0 else (24 * resources.displayMetrics.density).roundToInt())
135136 initialCameraKey = key
136137 }
@@ -304,7 +305,7 @@ internal class CraftNativeMapView(context: Context) : FrameLayout(context), OnMa
304305
305306 override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
306307 super.onSizeChanged(width, height, oldWidth, oldHeight)
307 if (width > 0 && height > 0) { applyPadding(); updateScale(); if (initialCameraKey == null) applyPending() }
308 if (width > 0 && height > 0) applyPending()
308309 }
309310
310311 override fun onAttachedToWindow() {
packages/ios/templates/CraftNativeScreen.swiftmodified+1-0
Changes to packages/ios/templates/CraftNativeScreen.swift
@@ -1206,6 +1206,7 @@ private final class CraftNativeMapView: MKMapView, MKMapViewDelegate {
12061206 isScrollEnabled = props["scrollEnabled"] as? Bool ?? true
12071207 isZoomEnabled = props["zoomEnabled"] as? Bool ?? true
12081208 isRotateEnabled = props["rotateEnabled"] as? Bool ?? false
1209 isPitchEnabled = props["pitchEnabled"] as? Bool ?? true
12091210 mapType = Self.mapType(props["mapType"] as? String)
12101211 configureTiles(props["tileOverlay"] as? [String: Any])
12111212 showsCompass = props["showsCompass"] as? Bool ?? false