### Setup iOS Development Environment Source: https://stadiamaps.github.io/ferrostar/print.html Install Xcode command line tools and build the iOS core components. ```bash xcode-select --install ``` ```bash cd common ./build-ios.sh ``` ```bash ./build-ios.sh --ffi-only ``` -------------------------------- ### Setup Android Development Environment Source: https://stadiamaps.github.io/ferrostar/print.html Install cargo-ndk to enable Gradle to build the native libraries. ```bash cargo install cargo-ndk ``` ```bash ./gradlew publishToMavenLocal -Pskip.signing ``` -------------------------------- ### Install Web Dependencies Source: https://stadiamaps.github.io/ferrostar/dev-env-setup.html Install necessary project dependencies for the web application. ```bash npm install ``` -------------------------------- ### Build and Run Web Project Source: https://stadiamaps.github.io/ferrostar/print.html Commands to prepare the core, install dependencies, and run the development server or build for production. ```bash npm run prepare:core ``` ```bash npm install ``` ```bash # This will start a local web server for the demo app with hot reload npm run dev # Or you can do a release build (we test this in CI) npm run build ``` -------------------------------- ### Start navigation session Source: https://stadiamaps.github.io/ferrostar/android-getting-started.html Initiates a navigation session using a selected route. ```kotlin core.startNavigation( route = route // NOTE: You can also change your config here with an optional config parameter! ) ``` -------------------------------- ### Install cargo-ndk Source: https://stadiamaps.github.io/ferrostar/dev-env-setup.html Install cargo-ndk to enable Gradle to build local Android libraries. ```bash cargo install cargo-ndk ``` -------------------------------- ### Install Xcode Command Line Tools Source: https://stadiamaps.github.io/ferrostar/dev-env-setup.html Install the required Xcode command line tools for iOS development. ```bash xcode-select --install ``` -------------------------------- ### Run Web Development Server and Build Source: https://stadiamaps.github.io/ferrostar/dev-env-setup.html Commands to start the local development server with hot reload or perform a release build. ```bash # This will start a local web server for the demo app with hot reload npm run dev # Or you can do a release build (we test this in CI) npm run build ``` -------------------------------- ### Start Navigation with Ferrostar Source: https://stadiamaps.github.io/ferrostar/web-customization.html Initiate navigation using the `startNavigation` method on the `FerrostarCore` instance, providing the fetched route and configuration. ```javascript core.startNavigation(route, config); ``` -------------------------------- ### Start Navigation Configuration Source: https://stadiamaps.github.io/ferrostar/web-getting-started.html Configures navigation parameters including step advancement, arrival thresholds, and route deviation tracking. ```typescript ferrostarCore.startNavigation(route, { stepAdvanceCondition: { DistanceEntryExit: { minimumHorizontalAccuracy: 25, distanceToEndOfStep: 30, distanceAfterEndStep: 5, hasReachedEndOfCurrentStep: false, }, }, arrivalStepAdvanceCondition: { DistanceToEndOfStep: { distance: 30, minimumHorizontalAccuracy: 25, }, }, routeDeviationTracking: { StaticThreshold: { minimumHorizontalAccuracy: 25, maxAcceptableDeviation: 10.0, }, }, snappedLocationCourseFiltering: "Raw", waypointAdvance: { WaypointWithinRange: 100, }, }); ``` -------------------------------- ### Initialize and Start BrowserLocationProvider Source: https://stadiamaps.github.io/ferrostar/web-customization.html Utilize the `BrowserLocationProvider` to leverage the browser's geolocation API for location updates. This involves requesting permission and starting the provider. A loop is included to wait for the initial location acquisition. ```javascript // Request location permission and start location updates const locationProvider = new BrowserLocationProvider(); locationProvider.requestPermission(); locationProvider.start(); // TODO: This approach is not ideal, any better way to wait for the locationProvider to acquire the first location? while (!locationProvider.lastLocation) { await new Promise((resolve) => setTimeout(resolve, 100)); } ``` -------------------------------- ### Install wasm-pack Source: https://stadiamaps.github.io/ferrostar/dev-env-setup.html Install the wasm-pack tool required for building the core WASM package. ```bash cargo install wasm-pack ``` -------------------------------- ### Install Ferrostar Web Components Source: https://stadiamaps.github.io/ferrostar/web-getting-started.html Use npm to add the Ferrostar web components package to your project. ```bash npm install @stadiamaps/ferrostar-webcomponents ``` -------------------------------- ### Start Navigation Source: https://stadiamaps.github.io/ferrostar/ios-getting-started.html Initiate the navigation session using a selected route, which automatically triggers location updates and state publishing. ```swift // NOTE: You can also change your config here with an optional config parameter! try ferrostarCore.startNavigation(route: route) ``` -------------------------------- ### Manage AndroidTtsObserver lifecycle Source: https://stadiamaps.github.io/ferrostar/android-getting-started.html Handles the start and shutdown of the text-to-speech observer within the activity lifecycle. ```kotlin override fun onStart() { super.onStart() ttsObserver.start() } override fun onDestroy() { super.onDestroy() ttsObserver.shutdown() } ``` -------------------------------- ### Instantiate SimulatedLocationProvider Source: https://stadiamaps.github.io/ferrostar/android-getting-started.html Instantiate the SimulatedLocationProvider for simulating location within Ferrostar without external files or complex setup, ideal for testing and development. This is typically saved as an instance variable. ```kotlin private val locationProvider = SimulatedLocationProvider( warpFactor = 2u, initialLocation = initialSimulatedLocation ) ``` -------------------------------- ### Initialize FerrostarCore with Widget Provider Source: https://stadiamaps.github.io/ferrostar/ios-dynamic-island.html This code snippet shows how to initialize FerrostarCore, specifying the FerrostarWidgetProvider for widget functionality. Ensure this is part of your app's setup. ```swift FerrostarCore( ..., widgetProvider: FerrostarWidgetProvider() ) ``` -------------------------------- ### Configure Map Controls Source: https://stadiamaps.github.io/ferrostar/print.html Configure the visibility and style of map controls using the `config` parameter. This example shows how to control mute, zoom, and recenter buttons, and the speed limit sign style. ```kotlin DynamicallyOrientingNavigationView( modifier = Modifier.fillMaxSize(), styleUrl = AppModule.mapStyleUrl, camera = camera, viewModel = viewModel, config = VisualNavigationViewConfig(showMute = true, showZoom = false, showRecenter = true, speedLimitStyle = SignageStyle.MUTCD), // ... ) ``` -------------------------------- ### Configure MapView Camera Padding Source: https://stadiamaps.github.io/ferrostar/jetpack-compose-customization.html Customize the camera padding for the map view to adjust the position of the location puck. This example shows how to bring the puck closer to the center of the screen by setting top padding. ```kotlin val camera = rememberSaveableMapViewCamera(MapViewCamera.TrackingUserLocation()) val screenOrientation = LocalConfiguration.current.orientation val start = if (screenOrientation == Configuration.ORIENTATION_LANDSCAPE) 0.5f else 0.0f val cameraPadding = CameraPadding.fractionOfScreen(start = start, top = 0.25f) val navigationCamera = MapViewCamera.TrackingUserLocationWithBearing( zoom = NavigationActivity.Automotive.zoom, pitch = NavigationActivity.Automotive.pitch, padding = cameraPadding) DynamicallyOrientingNavigationView( modifier = Modifier.fillMaxSize(), styleUrl = AppModule.mapStyleUrl, camera = camera, navigationCamera = navigationCamera, // ... ) ``` -------------------------------- ### Initialize Location Providers Source: https://stadiamaps.github.io/ferrostar/print.html Configure location providers for live tracking or simulation. ```kotlin locationProvider = NavigationLocationProvider( liveProviding = FusedNavigationLocationProvider(appContext), simulatedProvider = SimulatedLocationProvider( warpFactor = 2u, initialLocation = initialSimulatedLocation.toAndroidLocation() ) ) ``` ```kotlin locationProvider = FusedNavigationLocationProvider(context = this) ``` -------------------------------- ### Android Testing and Formatting Source: https://stadiamaps.github.io/ferrostar/print.html Commands for formatting Kotlin code and running UI snapshot tests with Paparazzi. ```bash ktfmtFormat ``` ```bash ./gradlew verifyPaparazziDebug ``` ```bash ./gradlew recordPaparazziDebug ``` -------------------------------- ### Build iOS Framework Source: https://stadiamaps.github.io/ferrostar/dev-env-setup.html Execute the iOS build script to generate necessary frameworks and bindings. ```bash cd common ./build-ios.sh ``` -------------------------------- ### Initialize SimulatedLocationProvider Source: https://stadiamaps.github.io/ferrostar/ios-getting-started.html Instantiate the SimulatedLocationProvider to enable location simulation for development and testing. ```swift @StateObject private var locationProvider = SimulatedLocationProvider(location: initialLocation) ``` -------------------------------- ### Initialize Valhalla Annotation Publisher Source: https://stadiamaps.github.io/ferrostar/annotations.html Sets up an annotation publisher for Valhalla-based routing services like Stadia Maps and Mapbox. ```swift let annotationPublisher = AnnotationPublisher.valhallaExtendedOSRM() ``` -------------------------------- ### Fetch navigation routes Source: https://stadiamaps.github.io/ferrostar/android-getting-started.html Retrieves routes using a start location and a list of waypoints. This is a suspend function and should be called within a coroutine scope. ```kotlin val routes = core.getRoutes( userLocation, listOf( Waypoint( coordinate = GeographicCoordinate(37.807587, -122.428411), kind = WaypointKind.BREAK), )) ``` -------------------------------- ### Build Web Core Source: https://stadiamaps.github.io/ferrostar/dev-env-setup.html Prepare the core WASM package for the web environment. ```bash npm run prepare:core ``` -------------------------------- ### Customize Route Polyline Rendering Source: https://stadiamaps.github.io/ferrostar/print.html Use `routeOverlayBuilder` to customize or replace the built-in route polyline rendering. This example shows how to use `BorderedPolyline` for the route. ```kotlin DynamicallyOrientingNavigationView( modifier = Modifier.fillMaxSize(), styleUrl = AppModule.mapStyleUrl, camera = camera, viewModel = viewModel, routeOverlayBuilder = RouteOverlayBuilder( navigationPath = { uiState -> uiState.routeGeometry?.let { geometry -> // BorderedPolyline is part of Ferrostar's MapLibre UI package. // You can also drop down to the raw Polyline and build your own custom style. BorderedPolyline(points = geometry.map { LatLng(it.lat, it.lng) }, zIndex = 0, color = "#3583dd", opacity = 0.7f, borderOpacity = 0.3f) } }), // ... ) ``` -------------------------------- ### Initialize FerrostarCore instance Source: https://stadiamaps.github.io/ferrostar/android-getting-started.html Configures the FerrostarCore with a route provider, HTTP client, location provider, and navigation controller settings. ```kotlin var options = mapOf( "costing_options" to mapOf( "bicycle" to mapOf( "use_roads" to 0.2 )), "units" to "miles") private val core = FerrostarCore( wellKnownRouteProvider = WellKnownRouteProvider.Valhalla("https://api.stadiamaps.com/route/v1?api_key=YOUR-API-KEY", "bicycle") .withJsonOptions(options), httpClient = httpClient, locationProvider = locationProvider, foregroundServiceManager = foregroundServiceManager, navigationControllerConfig = NavigationControllerConfig( WaypointAdvanceMode.WaypointWithinRange(100.0), stepAdvanceDistanceEntryAndExit(30u, 5u, 32u), // This is a special condition used for the last two steps of the route. As we can't assume the // user continue moving past the step like the other conditions. stepAdvanceDistanceToEndOfStep(30u, 32u), RouteDeviationTracking.StaticThreshold(15U, 50.0), CourseFiltering.SNAP_TO_ROUTE), ) ``` -------------------------------- ### Implement a CustomRouteProvider in Kotlin Source: https://stadiamaps.github.io/ferrostar/route-providers.html Example of implementing the CustomRouteProvider interface to fetch routes from a custom client and convert them into Ferrostar Route objects using OSRM-formatted JSON. ```kotlin class MyCustomRouteProvider( private val client: MyClient ): CustomRouteProvider { private val moshi: Moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() override suspend fun getRoutes( userLocation: UserLocation, waypoints: List ): List { val myRequest = SomeRequestType(userLocation, waypoints) val myResponse = client.getRoute(myRequest) // Convert our response's waypoints into ferrostar waypoints. val outWaypoints = myResponse.waypoints.map { it.toFerrostarWaypoint() } val jsonAdapter = moshi.adapter(MyOsrmRoute::class.java) // Using the intermediate OSRM route JSON. We map our custom response // data into ferrostar waypoints. val routes = myResponse.routes { val osrmRoute = jsonAdapter.toJson(it.route).encodeToByteArray() createRouteFromOsrmRoute(osrmRoute, outWaypoints, MyCustomRouteProvider.POLYLINE_PRECISION) } return routes } companion object { const val POLYLINE_PRECISION: UInt = 6u } } ``` -------------------------------- ### Initialize Valhalla Extended OSRM Annotation Publisher (Android) Source: https://stadiamaps.github.io/ferrostar/print.html Import and initialize the publisher for Android, typically used within a ViewModel. ```kotlin import com.stadiamaps.ferrostar.core.annotation.valhalla.valhallaExtendedOSRMAnnotationPublisher // Elsewhere in your file... val annotationPublisher = valhallaExtendedOSRMAnnotationPublisher() ``` ```kotlin class DemoNavigationViewModel( // This is a simple example, but these would typically be dependency injected val ferrostarCore: FerrostarCore = AppModule.ferrostarCore, val locationProvider: LocationProvider = AppModule.locationProvider, annotationPublisher: AnnotationPublisher<*> = valhallaExtendedOSRMAnnotationPublisher() ) : DefaultNavigationViewModel(ferrostarCore, annotationPublisher), LocationUpdateListener { // ... } ``` -------------------------------- ### Configure FerrostarCore Instance Source: https://stadiamaps.github.io/ferrostar/print.html Initialize the FerrostarCore instance with various configurations including route provider, HTTP client, location provider, and navigation controller settings. ```kotlin var options = mapOf( "costing_options" to mapOf( "bicycle" to mapOf( "use_roads" to 0.2 )), "units" to "miles") private val core = FerrostarCore( wellKnownRouteProvider = WellKnownRouteProvider.Valhalla("https://api.stadiamaps.com/route/v1?api_key=YOUR-API-KEY", "bicycle") .withJsonOptions(options), httpClient = httpClient, locationProvider = locationProvider, foregroundServiceManager = foregroundServiceManager, navigationControllerConfig = NavigationControllerConfig( WaypointAdvanceMode.WaypointWithinRange(100.0), stepAdvanceDistanceEntryAndExit(30u, 5u, 32u), // This is a special condition used for the last two steps of the route. As we can't assume the // user continue moving past the step like the other conditions. stepAdvanceDistanceToEndOfStep(30u, 32u), RouteDeviationTracking.StaticThreshold(15U, 50.0), CourseFiltering.SNAP_TO_ROUTE), ) ``` -------------------------------- ### Geocode Destination using Nominatim API Source: https://stadiamaps.github.io/ferrostar/web-customization.html Retrieve latitude and longitude for a destination using the Nominatim API. Ensure compliance with Nominatim's usage policy before deployment. This example demonstrates fetching coordinates for 'One Apple Park Way'. ```javascript const destination = "One Apple Park Way"; const { lat, lon } = await fetch("https://nominatim.openstreetmap.org/search?q=" + destination + "&format=json") .then((response) => response.json()) .then((data) => data[0]); ``` -------------------------------- ### Initialize Navigation Screen Source: https://stadiamaps.github.io/ferrostar/print.html Parse incoming intents within the session to initialize the navigation screen with a destination. ```kotlin override fun onCreateScreen(intent: Intent): Screen { val destination = NavigationIntentParser().parse(intent) return MyNavigationScreen(carContext, initialDestination = destination) } ``` -------------------------------- ### Add Custom Overlay Layers to MapView Source: https://stadiamaps.github.io/ferrostar/jetpack-compose-customization.html Add custom overlay layers to the map view, such as custom shapes or markers. This example demonstrates adding a blue dot for the user's current location and a translucent circle to indicate GPS accuracy. ```kotlin DynamicallyOrientingNavigationView( modifier = Modifier.fillMaxSize(), styleUrl = AppModule.mapStyleUrl, // Other arguments elided... ) { // Trivial, if silly example of how to add your own overlay layers. uiState.location?.let { // Add a little blue dot where the user is now Circle( center = LatLng(it.coordinates.lat, it.coordinates.lng), radius = 10f, color = "Blue", zIndex = 3, ) // If the reported GPS accuracy is worse than 15m, // show a large blue translucent circle (this is an example; not to scale). if (it.horizontalAccuracy > 15) { Circle( center = LatLng(it.coordinates.lat, it.coordinates.lng), radius = min(it.horizontalAccuracy.toFloat(), 150f), color = "Blue", opacity = 0.2f, zIndex = 2, ) } } } ``` -------------------------------- ### Initialize FerrostarCore Source: https://stadiamaps.github.io/ferrostar/ios-getting-started.html Create a persistent FerrostarCore instance using a well-known route provider and required configuration components. ```swift let core = try FerrostarCore( wellKnownRouteProvider: .valhalla( endpointUrl: "https://api.stadiamaps.com/route/v1?api_key=\(sharedAPIKeys.stadiaMapsAPIKey)", profile: "bicycle" ) .withJsonOptions(options: ["costing_options": ["bicycle": ["use_roads": 0.2]]]), locationProvider: locationProvider, navigationControllerConfig: config, // This is how you can set up annotation publishing; // We provide "extended OSRM" support out of the box, // but this is fully extendable! annotation: AnnotationPublisher.valhallaExtendedOSRM(), widgetProvider: FerrostarWidgetProvider() ) ``` -------------------------------- ### Initialize Navigation State and Session Source: https://stadiamaps.github.io/ferrostar/print.html Store the navigation view model state and initiate the navigation session with a selected route. ```kotlin var navigationViewModel by remember { mutableStateOf(null) } ``` ```kotlin core.startNavigation( route = route // NOTE: You can also change your config here with an optional config parameter! ) ``` -------------------------------- ### Configure OkHttp Client Source: https://stadiamaps.github.io/ferrostar/android-getting-started.html Set up an OkHttp client with a global timeout, which can be stored as an instance variable. This client is used for network requests and can be configured as an HttpClientProvider for Ferrostar Core. ```kotlin private val httpClient = OkHttpClient.Builder() .callTimeout(Duration.ofSeconds(15)) .build() .toOkHttpClientProvider() ``` -------------------------------- ### Initialize Valhalla Annotation Publisher for Android Source: https://stadiamaps.github.io/ferrostar/annotations.html Imports and initializes the Valhalla extended OSRM annotation publisher for Android applications. ```kotlin import com.stadiamaps.ferrostar.core.annotation.valhalla.valhallaExtendedOSRMAnnotationPublisher // Elsewhere in your file... val annotationPublisher = valhallaExtendedOSRMAnnotationPublisher() ``` -------------------------------- ### Initialize CoreLocationProvider Source: https://stadiamaps.github.io/ferrostar/ios-getting-started.html Instantiate the CoreLocationProvider as a StateObject to handle real-time GNSS location updates. ```swift @StateObject private var locationProvider = CoreLocationProvider(activityType: .otherNavigation, allowBackgroundLocationUpdates: true) ``` -------------------------------- ### Initialize FerrostarCore with ForegroundServiceManager Source: https://stadiamaps.github.io/ferrostar/android-foreground-service.html Pass the ForegroundServiceManager instance when constructing FerrostarCore to enable automatic service management. ```kotlin val foregroundServiceManager: ForegroundServiceManager = FerrostarForegroundServiceManager(appContext, DefaultForegroundNotificationBuilder(appContext)) val core = FerrostarCore( ..., foregroundServiceManager, ...) ``` -------------------------------- ### Configure Navigation ViewModel for Android Source: https://stadiamaps.github.io/ferrostar/annotations.html Demonstrates injecting the annotation publisher into a custom navigation view model. ```kotlin class DemoNavigationViewModel( // This is a simple example, but these would typically be dependency injected val ferrostarCore: FerrostarCore = AppModule.ferrostarCore, val locationProvider: LocationProvider = AppModule.locationProvider, annotationPublisher: AnnotationPublisher<*> = valhallaExtendedOSRMAnnotationPublisher() ) : DefaultNavigationViewModel(ferrostarCore, annotationPublisher), LocationUpdateListener { // ... } ``` -------------------------------- ### Implement CarAppService and Session Source: https://stadiamaps.github.io/ferrostar/android-auto-car-app.html Extend CarAppService to manage host validation and session creation for the navigation app. ```kotlin class MyCarAppService : CarAppService() { override fun createHostValidator(): HostValidator = if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) { HostValidator.ALLOW_ALL_HOSTS_VALIDATOR } else { HostValidator.Builder(applicationContext) .addAllowedHosts(androidx.car.app.R.array.hosts_allowlist_sample) .build() } override fun onCreateSession(sessionInfo: SessionInfo): Session = MyCarAppSession() } class MyCarAppSession : Session() { override fun onCreateScreen(intent: Intent): Screen { AppModule.init(carContext) val destination = NavigationIntentParser().parse(intent) return MyNavigationScreen(carContext, initialDestination = destination) } } ``` -------------------------------- ### Create Valhalla Waypoint with Properties (Swift) Source: https://stadiamaps.github.io/ferrostar/route-providers.html Demonstrates how to create a waypoint with specific Valhalla properties, including disabling U-turns by setting `allowUturns` to false. This is useful for intermediate waypoints where U-turns are not desired. ```swift let waypoint = createWaypointWithValhallaProperties( coordinate: GeographicCoordinate(lat: 60.5349908, lng: -149.5485806), kind: .break, properties: ValhallaWaypointProperties(preferredSide: .same, allowUturns: false)) ``` -------------------------------- ### Format Apple Code Source: https://stadiamaps.github.io/ferrostar/print.html Run swiftformat in the apple directory to ensure consistent code style. ```bash swiftformat . ``` -------------------------------- ### Initialize DynamicallyOrientingNavigationView Source: https://stadiamaps.github.io/ferrostar/ios-getting-started.html Configures the navigation view with a map style, navigation state, and camera settings. ```swift // You can get a free Stadia Maps API key at https://client.stadiamaps.com // See https://stadiamaps.github.io/ferrostar/vendors.html for additional vendors let styleURL = URL(string: "https://tiles.stadiamaps.com/styles/outdoors.json?api_key=\(stadiaMapsAPIKey)")! DynamicallyOrientingNavigationView( styleURL: styleURL, navigationState: state, camera: $camera, snappedZoom: .constant(18), useSnappedCamera: .constant(true)) ``` -------------------------------- ### Format Web Code Source: https://stadiamaps.github.io/ferrostar/print.html Run formatting checks before committing changes in the web directory. ```bash npm run format:fix ``` -------------------------------- ### Initialize Spoken Instruction Observer Source: https://stadiamaps.github.io/ferrostar/ios-getting-started.html Store the spoken instruction observer as an instance variable to enable speech synthesis during navigation. ```swift @State private var spokenInstructionObserver = SpokenInstructionObserver.initAVSpeechSynthesizer() ``` -------------------------------- ### Define Ferrostar Versions in libs.versions.toml Source: https://stadiamaps.github.io/ferrostar/android-getting-started.html Add Ferrostar and OkHttp version information to your libs.versions.toml file for managing dependencies in a modern style. ```toml [versions] ferrostar = "X.Y.X" okhttp3 = "4.11.0" [libraries] ferrostar-core = { group = "com.stadiamaps.ferrostar", name = "core", version.ref = "ferrostar" } ferrostar-maplibreui = { group = "com.stadiamaps.ferrostar", name = "maplibreui", version.ref = "ferrostar" } okhttp3 = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp3" } ``` -------------------------------- ### Configure Simulated Route Playback Source: https://stadiamaps.github.io/ferrostar/ios-getting-started.html Adjust the simulation speed and assign a route to the simulated location provider. ```swift locationProvider.warpFactor = 2 locationProvider.setSimulatedRoute(route) ``` -------------------------------- ### Create SurfaceAreaTracker Source: https://stadiamaps.github.io/ferrostar/print.html Instantiate a SurfaceAreaTracker to manage surface area events and register it as the surface gesture callback. ```kotlin private val surfaceAreaTracker = SurfaceAreaTracker { surfaceGestureCallback = it } ``` -------------------------------- ### Enable Auto-Drive Simulation Source: https://stadiamaps.github.io/ferrostar/print.html Configure the NavigationManagerBridge to handle simulation requests from the Car App host. ```kotlin NavigationManagerBridge( ... onAutoDriveEnabled = { viewModel.enableAutoDriveSimulation() }, ) ```