diff --git a/.github/workflows/cargo-publish.yml b/.github/workflows/cargo-publish.yml index d8235875..27a53d68 100644 --- a/.github/workflows/cargo-publish.yml +++ b/.github/workflows/cargo-publish.yml @@ -9,7 +9,7 @@ env: jobs: publish_crate: - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 - name: Cargo Publish diff --git a/.github/workflows/gradle-publish.yml b/.github/workflows/gradle-publish.yml index 0f6f2bd8..1d81e053 100644 --- a/.github/workflows/gradle-publish.yml +++ b/.github/workflows/gradle-publish.yml @@ -9,7 +9,7 @@ on: jobs: build: - runs-on: macos-13 + runs-on: ubuntu-latest permissions: contents: read packages: read diff --git a/.github/workflows/ios-release.yml b/.github/workflows/ios-release.yml index cc440909..7de934d3 100644 --- a/.github/workflows/ios-release.yml +++ b/.github/workflows/ios-release.yml @@ -6,7 +6,7 @@ on: jobs: ios-release: - runs-on: macos-14 + runs-on: macos-15 permissions: contents: write diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 3b5228e5..81cc7e19 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -8,7 +8,7 @@ on: jobs: format-lint: - runs-on: macos-14 + runs-on: macos-15 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-ios-swiftformat cancel-in-progress: true @@ -24,7 +24,7 @@ jobs: run: swiftformat . --lint build-ferrostar: - runs-on: macos-14 + runs-on: macos-15 permissions: contents: write # To auto-commit Package.swift and binding changes @@ -68,7 +68,7 @@ jobs: retention-days: 5 build-demo: - runs-on: macos-14 + runs-on: macos-15 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-ios-build-demo cancel-in-progress: true @@ -119,7 +119,7 @@ jobs: retention-days: 5 test: - runs-on: macos-14 + runs-on: macos-15 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-ios-test cancel-in-progress: true @@ -131,7 +131,7 @@ jobs: ] destination: [ # TODO: Add more destinations - 'platform=iOS Simulator,name=iPhone 15,OS=17.2' + 'platform=iOS Simulator,name=iPhone 16 Pro,OS=18.1' ] steps: diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 2de73fad..3f4b450b 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -10,7 +10,7 @@ env: jobs: build: - runs-on: macos-13 + runs-on: macos-15 steps: - name: Checkout code diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b17d6f60..daca7a0f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -12,7 +12,7 @@ env: jobs: msrv: - runs-on: macos-14 + runs-on: macos-15 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-rust-msrv cancel-in-progress: true @@ -27,7 +27,7 @@ jobs: working-directory: common semver-checks: - runs-on: macos-14 + runs-on: macos-15 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-rust-semver cancel-in-progress: true @@ -41,7 +41,7 @@ jobs: feature-group: default-features rustfmt: - runs-on: macos-14 + runs-on: macos-15 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-rust-rustfmt cancel-in-progress: true @@ -53,7 +53,7 @@ jobs: working-directory: common build: - runs-on: macos-14 + runs-on: macos-15 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-rust-build cancel-in-progress: true diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index a299c1dd..3f9f93ec 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -6,7 +6,7 @@ on: jobs: typos: - runs-on: macos-14 + runs-on: macos-15 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-ios-swiftformat cancel-in-progress: true diff --git a/.github/workflows/wasm-js.yml b/.github/workflows/wasm-js.yml index fc4837b6..26dd8708 100644 --- a/.github/workflows/wasm-js.yml +++ b/.github/workflows/wasm-js.yml @@ -12,7 +12,7 @@ env: jobs: build: - runs-on: macos-14 + runs-on: macos-15 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-wasm-build cancel-in-progress: true diff --git a/android/composeui/build.gradle b/android/composeui/build.gradle index 8e971cf7..5aafd9e9 100644 --- a/android/composeui/build.gradle +++ b/android/composeui/build.gradle @@ -12,7 +12,7 @@ plugins { android { namespace 'com.stadiamaps.ferrostar.composeui' - compileSdk 34 + compileSdk 35 defaultConfig { minSdk 25 diff --git a/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/config/VisualNavigationViewConfig.kt b/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/config/VisualNavigationViewConfig.kt new file mode 100644 index 00000000..0ca3fb93 --- /dev/null +++ b/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/config/VisualNavigationViewConfig.kt @@ -0,0 +1,40 @@ +package com.stadiamaps.ferrostar.composeui.config + +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp + +sealed class CameraControlState { + data object Hidden : CameraControlState() + + data class ShowRecenter(val updateCamera: () -> Unit) : CameraControlState() + + data class ShowRouteOverview(val updateCamera: () -> Unit) : CameraControlState() +} + +data class VisualNavigationViewConfig( + var showMute: Boolean = false, + var showZoom: Boolean = false, + var buttonSize: DpSize = DpSize(56.dp, 56.dp) +) { + companion object { + fun Default() = VisualNavigationViewConfig(showMute = true, showZoom = true) + } +} + +/** Enables the mute button in the navigation view. */ +fun VisualNavigationViewConfig.useMuteButton(): VisualNavigationViewConfig { + showMute = true + return this +} + +/** Enables the zoom button in the navigation view. */ +fun VisualNavigationViewConfig.useZoomButton(): VisualNavigationViewConfig { + showZoom = true + return this +} + +/** Changes the size of navigation buttons. */ +fun VisualNavigationViewConfig.buttonSize(size: DpSize): VisualNavigationViewConfig { + buttonSize = size + return this +} diff --git a/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/InstructionsView.kt b/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/InstructionsView.kt index f57841d2..292574eb 100644 --- a/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/InstructionsView.kt +++ b/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/InstructionsView.kt @@ -56,6 +56,7 @@ import uniffi.ferrostar.VisualInstructionContent fun InstructionsView( instructions: VisualInstruction, distanceToNextManeuver: Double?, + modifier: Modifier = Modifier, distanceFormatter: DistanceFormatter = LocalizedDistanceFormatter(), theme: InstructionRowTheme = DefaultInstructionRowTheme, remainingSteps: List? = null, @@ -69,7 +70,8 @@ fun InstructionsView( Box( modifier = - Modifier.fillMaxWidth() + modifier + .fillMaxWidth() .heightIn(max = screenHeight) .animateContentSize(animationSpec = spring(stiffness = Spring.StiffnessHigh)) .background(theme.backgroundColor, RoundedCornerShape(10.dp)) diff --git a/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/controls/NavigationUIButton.kt b/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/controls/NavigationUIButton.kt index 50746f20..fcf8efa3 100644 --- a/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/controls/NavigationUIButton.kt +++ b/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/controls/NavigationUIButton.kt @@ -2,9 +2,8 @@ package com.stadiamaps.ferrostar.composeui.views.controls import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close @@ -18,6 +17,7 @@ import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import com.stadiamaps.ferrostar.composeui.R @@ -32,13 +32,14 @@ import com.stadiamaps.ferrostar.composeui.R @Composable fun NavigationUIButton( onClick: () -> Unit, + buttonSize: DpSize, containerColor: Color = FloatingActionButtonDefaults.containerColor, contentColor: Color = contentColorFor(containerColor), content: @Composable () -> Unit ) { FloatingActionButton( onClick, - modifier = Modifier.width(56.dp).height(56.dp).shadow(6.dp, shape = CircleShape), + modifier = Modifier.size(buttonSize).shadow(6.dp, shape = CircleShape), shape = CircleShape, containerColor, contentColor) { @@ -50,7 +51,7 @@ fun NavigationUIButton( @Composable fun NavigationUIButtonPreview() { Box(Modifier.background(Color.LightGray).padding(16.dp)) { - NavigationUIButton({}) { + NavigationUIButton({}, DpSize(56.dp, 56.dp)) { Icon(Icons.Filled.Close, contentDescription = stringResource(id = R.string.end_navigation)) } } diff --git a/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/controls/NavigationUIZoomButton.kt b/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/controls/NavigationUIZoomButton.kt index 37440102..cd3ee0a3 100644 --- a/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/controls/NavigationUIZoomButton.kt +++ b/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/controls/NavigationUIZoomButton.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons @@ -22,11 +23,13 @@ import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import com.stadiamaps.ferrostar.composeui.R @Composable fun NavigationUIZoomButton( + buttonSize: DpSize, onClickZoomIn: () -> Unit, onClickZoomOut: () -> Unit, containerColor: Color = FloatingActionButtonDefaults.containerColor, @@ -38,7 +41,7 @@ fun NavigationUIZoomButton( Column(modifier = Modifier.shadow(6.dp, shape = RoundedCornerShape(50))) { FloatingActionButton( onClick = onClickZoomIn, - modifier = Modifier.height(56.dp).width(56.dp), + modifier = Modifier.size(buttonSize), shape = RoundedCornerShape(topStartPercent = 50, topEndPercent = 50), containerColor = containerColor, contentColor = contentColor, @@ -48,13 +51,13 @@ fun NavigationUIZoomButton( contentDescription = stringResource(id = R.string.zoom_in)) } - Box(modifier = Modifier.height(1.dp).width(56.dp)) { + Box(modifier = Modifier.height(1.dp).width(buttonSize.width)) { HorizontalDivider(color = MaterialTheme.colorScheme.surfaceVariant) } FloatingActionButton( onClick = onClickZoomOut, - modifier = Modifier.height(56.dp).width(56.dp), + modifier = Modifier.size(buttonSize), shape = RoundedCornerShape(bottomStartPercent = 50, bottomEndPercent = 50), containerColor = containerColor, contentColor = contentColor, @@ -69,5 +72,8 @@ fun NavigationUIZoomButton( @Preview @Composable fun NavigationUIZoomButtonPreview() { - Box(Modifier.background(Color.LightGray).padding(16.dp)) { NavigationUIZoomButton({}, {}) } + Box(Modifier.background(Color.LightGray).padding(16.dp)) { + NavigationUIZoomButton( + buttonSize = DpSize(56.dp, 56.dp), onClickZoomIn = {}, onClickZoomOut = {}) + } } diff --git a/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/gridviews/NavigatingInnerGridView.kt b/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/gridviews/NavigatingInnerGridView.kt index aad7f8cb..aa9c7702 100644 --- a/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/gridviews/NavigatingInnerGridView.kt +++ b/android/composeui/src/main/java/com/stadiamaps/ferrostar/composeui/views/gridviews/NavigatingInnerGridView.kt @@ -1,5 +1,7 @@ package com.stadiamaps.ferrostar.composeui.views.gridviews +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.width @@ -7,15 +9,18 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.VolumeOff import androidx.compose.material.icons.automirrored.filled.VolumeUp import androidx.compose.material.icons.filled.Navigation -import androidx.compose.material.icons.filled.VolumeOff +import androidx.compose.material.icons.filled.Route import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import com.stadiamaps.ferrostar.composeui.R +import com.stadiamaps.ferrostar.composeui.config.CameraControlState import com.stadiamaps.ferrostar.composeui.views.controls.NavigationUIButton import com.stadiamaps.ferrostar.composeui.views.controls.NavigationUIZoomButton @@ -25,11 +30,11 @@ fun NavigatingInnerGridView( showMute: Boolean = true, isMuted: Boolean?, onClickMute: () -> Unit = {}, + buttonSize: DpSize, + cameraControlState: CameraControlState = CameraControlState.Hidden, showZoom: Boolean = true, onClickZoomIn: () -> Unit = {}, onClickZoomOut: () -> Unit = {}, - showCentering: Boolean = true, - onClickCenter: () -> Unit = {}, topCenter: @Composable () -> Unit = { Spacer(Modifier.width(12.dp)) }, centerStart: @Composable () -> Unit = { Spacer(Modifier.width(12.dp)) }, bottomEnd: @Composable () -> Unit = { Spacer(Modifier.width(12.dp)) } @@ -41,16 +46,39 @@ fun NavigatingInnerGridView( }, topCenter = topCenter, topEnd = { - if (showMute && isMuted != null) { - NavigationUIButton(onClick = onClickMute) { - if (isMuted) { - Icon( - Icons.AutoMirrored.Filled.VolumeOff, - contentDescription = stringResource(id = R.string.unmute_description)) - } else { - Icon( - Icons.AutoMirrored.Filled.VolumeUp, - contentDescription = stringResource(id = R.string.mute_description)) + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + when (cameraControlState) { + CameraControlState.Hidden -> { + // Nothing to draw here :) + } + is CameraControlState.ShowRecenter -> { + // We decided to put this in the bottom corner for now + } + is CameraControlState.ShowRouteOverview -> { + NavigationUIButton( + onClick = cameraControlState.updateCamera, buttonSize = buttonSize) { + Icon( + Icons.Default.Route, + modifier = Modifier.rotate(90.0f), + contentDescription = stringResource(id = R.string.route_overview)) + } + } + } + + // NOTE: Some controls hidden when the camera is not following the user + if (showMute && + isMuted != null && + cameraControlState !is CameraControlState.ShowRecenter) { + NavigationUIButton(onClick = onClickMute, buttonSize = buttonSize) { + if (isMuted) { + Icon( + Icons.AutoMirrored.Filled.VolumeOff, + contentDescription = stringResource(id = R.string.unmute_description)) + } else { + Icon( + Icons.AutoMirrored.Filled.VolumeUp, + contentDescription = stringResource(id = R.string.mute_description)) + } } } } @@ -58,12 +86,12 @@ fun NavigatingInnerGridView( centerStart = centerStart, centerEnd = { if (showZoom) { - NavigationUIZoomButton(onClickZoomIn, onClickZoomOut) + NavigationUIZoomButton(buttonSize, onClickZoomIn, onClickZoomOut) } }, bottomStart = { - if (showCentering) { - NavigationUIButton(onClick = onClickCenter) { + if (cameraControlState is CameraControlState.ShowRecenter) { + NavigationUIButton(onClick = cameraControlState.updateCamera, buttonSize = buttonSize) { Icon( Icons.Filled.Navigation, contentDescription = stringResource(id = R.string.recenter)) @@ -75,14 +103,56 @@ fun NavigatingInnerGridView( @Preview(device = Devices.PIXEL_5) @Composable -fun NavigatingInnerGridViewPreview() { - NavigatingInnerGridView(modifier = Modifier.fillMaxSize(), isMuted = false) +fun NavigatingInnerGridViewNonTrackingPreview() { + NavigatingInnerGridView( + modifier = Modifier.fillMaxSize(), + isMuted = false, + buttonSize = DpSize(56.dp, 56.dp), + cameraControlState = + CameraControlState.ShowRecenter { + // Do nothing + }) +} + +@Preview(device = Devices.PIXEL_5) +@Composable +fun NavigatingInnerGridViewTrackingPreview() { + NavigatingInnerGridView( + modifier = Modifier.fillMaxSize(), + isMuted = false, + buttonSize = DpSize(56.dp, 56.dp), + cameraControlState = + CameraControlState.ShowRouteOverview { + // Do nothing + }) +} + +@Preview( + device = + "spec:width=411dp,height=891dp,dpi=420,isRound=false,chinSize=0dp,orientation=landscape") +@Composable +fun NavigatingInnerGridViewLandscapeNonTrackingPreview() { + NavigatingInnerGridView( + modifier = Modifier.fillMaxSize(), + isMuted = true, + buttonSize = DpSize(56.dp, 56.dp), + cameraControlState = + CameraControlState.ShowRecenter { + // Do nothing + }) } @Preview( device = "spec:width=411dp,height=891dp,dpi=420,isRound=false,chinSize=0dp,orientation=landscape") @Composable -fun NavigatingInnerGridViewLandscapePreview() { - NavigatingInnerGridView(modifier = Modifier.fillMaxSize(), isMuted = true) +fun NavigatingInnerGridViewLandscapeTrackingPreview() { + NavigatingInnerGridView( + modifier = Modifier.fillMaxSize(), + isMuted = true, + buttonSize = DpSize(56.dp, 56.dp), + cameraControlState = + CameraControlState.ShowRouteOverview { + // Do nothing + }) } diff --git a/android/composeui/src/main/res/values/strings.xml b/android/composeui/src/main/res/values/strings.xml index 975da209..3112c6e6 100644 --- a/android/composeui/src/main/res/values/strings.xml +++ b/android/composeui/src/main/res/values/strings.xml @@ -17,4 +17,5 @@ Preparing... Arrived You have arrived at your destination. + Route Overview \ No newline at end of file diff --git a/android/composeui/src/test/java/com/stadiamaps/ferrostar/views/NavigatingInnerGridViewTest.kt b/android/composeui/src/test/java/com/stadiamaps/ferrostar/views/NavigatingInnerGridViewTest.kt index 5008ade9..d4ed607c 100644 --- a/android/composeui/src/test/java/com/stadiamaps/ferrostar/views/NavigatingInnerGridViewTest.kt +++ b/android/composeui/src/test/java/com/stadiamaps/ferrostar/views/NavigatingInnerGridViewTest.kt @@ -1,7 +1,9 @@ package com.stadiamaps.ferrostar.views -import com.stadiamaps.ferrostar.composeui.views.gridviews.NavigatingInnerGridViewLandscapePreview -import com.stadiamaps.ferrostar.composeui.views.gridviews.NavigatingInnerGridViewPreview +import com.stadiamaps.ferrostar.composeui.views.gridviews.NavigatingInnerGridViewLandscapeNonTrackingPreview +import com.stadiamaps.ferrostar.composeui.views.gridviews.NavigatingInnerGridViewLandscapeTrackingPreview +import com.stadiamaps.ferrostar.composeui.views.gridviews.NavigatingInnerGridViewNonTrackingPreview +import com.stadiamaps.ferrostar.composeui.views.gridviews.NavigatingInnerGridViewTrackingPreview import com.stadiamaps.ferrostar.support.paparazziDefault import com.stadiamaps.ferrostar.support.withSnapshotBackground import org.junit.Rule @@ -12,12 +14,26 @@ class NavigatingInnerGridViewTest { @get:Rule val paparazzi = paparazziDefault() @Test - fun testNavigatingInnerGridView() { - paparazzi.snapshot { withSnapshotBackground { NavigatingInnerGridViewPreview() } } + fun testNavigatingInnerGridViewTracking() { + paparazzi.snapshot { withSnapshotBackground { NavigatingInnerGridViewTrackingPreview() } } } @Test - fun testNavigatingInnerGridViewLandscape() { - paparazzi.snapshot { withSnapshotBackground { NavigatingInnerGridViewLandscapePreview() } } + fun testNavigatingInnerGridViewNonTracking() { + paparazzi.snapshot { withSnapshotBackground { NavigatingInnerGridViewNonTrackingPreview() } } + } + + @Test + fun testNavigatingInnerGridViewTrackingLandscape() { + paparazzi.snapshot { + withSnapshotBackground { NavigatingInnerGridViewLandscapeTrackingPreview() } + } + } + + @Test + fun testNavigatingInnerGridViewNonTrackingLandscape() { + paparazzi.snapshot { + withSnapshotBackground { NavigatingInnerGridViewLandscapeNonTrackingPreview() } + } } } diff --git a/android/composeui/src/test/java/com/stadiamaps/ferrostar/views/NavigationUIButtonTest.kt b/android/composeui/src/test/java/com/stadiamaps/ferrostar/views/NavigationUIButtonTest.kt index f576a684..ca2669c1 100644 --- a/android/composeui/src/test/java/com/stadiamaps/ferrostar/views/NavigationUIButtonTest.kt +++ b/android/composeui/src/test/java/com/stadiamaps/ferrostar/views/NavigationUIButtonTest.kt @@ -1,14 +1,14 @@ package com.stadiamaps.ferrostar.views import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Adb import androidx.compose.material3.Icon import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import com.stadiamaps.ferrostar.composeui.views.controls.NavigationUIButton import com.stadiamaps.ferrostar.composeui.views.controls.NavigationUIZoomButton @@ -20,11 +20,13 @@ class NavigationUIButtonTest { @get:Rule val paparazzi = paparazziDefault() + private val buttonSize = DpSize(56.dp, 56.dp) + @Test fun testNavigationUIButton() { paparazzi.snapshot { - Box(modifier = Modifier.width(56.dp).height(56.dp).padding(16.dp)) { - NavigationUIButton(onClick = { /* no action */ }) { + Box(modifier = Modifier.size(buttonSize).padding(16.dp)) { + NavigationUIButton(onClick = { /* no action */ }, buttonSize = buttonSize) { Icon(Icons.Filled.Adb, contentDescription = "ADB") } } @@ -34,9 +36,10 @@ class NavigationUIButtonTest { @Test fun testNavigationUIButtonCustomized() { paparazzi.snapshot { - Box(modifier = Modifier.width(56.dp).height(56.dp).padding(16.dp)) { + Box(modifier = Modifier.size(buttonSize).padding(16.dp)) { NavigationUIButton( onClick = { /* no action */ }, + buttonSize = buttonSize, containerColor = Color.Black, contentColor = Color.White) { Icon(Icons.Filled.Adb, contentDescription = "ADB") @@ -48,9 +51,11 @@ class NavigationUIButtonTest { @Test fun testNavigationUIZoomButton() { paparazzi.snapshot { - Box(modifier = Modifier.width(56.dp).height(56.dp).padding(16.dp)) { + Box(modifier = Modifier.size(buttonSize).padding(16.dp)) { NavigationUIZoomButton( - onClickZoomIn = { /* no action */ }, onClickZoomOut = { /* no action */ }) + onClickZoomIn = { /* no action */ }, + onClickZoomOut = { /* no action */ }, + buttonSize = buttonSize) } } } @@ -58,8 +63,9 @@ class NavigationUIButtonTest { @Test fun testNavigationUIZoomButtonCustomized() { paparazzi.snapshot { - Box(modifier = Modifier.width(56.dp).height(56.dp).padding(16.dp)) { + Box(modifier = Modifier.size(buttonSize).padding(16.dp)) { NavigationUIZoomButton( + buttonSize = buttonSize, onClickZoomIn = { /* no action */ }, onClickZoomOut = { /* no action */ }, containerColor = Color.Black, diff --git a/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridView.png b/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridView.png deleted file mode 100644 index fbd51cda..00000000 Binary files a/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridView.png and /dev/null differ diff --git a/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewLandscape.png b/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewLandscape.png deleted file mode 100644 index 6131454d..00000000 Binary files a/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewLandscape.png and /dev/null differ diff --git a/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewNonTracking.png b/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewNonTracking.png new file mode 100644 index 00000000..7e59d56d Binary files /dev/null and b/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewNonTracking.png differ diff --git a/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewNonTrackingLandscape.png b/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewNonTrackingLandscape.png new file mode 100644 index 00000000..7e59d56d Binary files /dev/null and b/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewNonTrackingLandscape.png differ diff --git a/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewTracking.png b/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewTracking.png new file mode 100644 index 00000000..82e5a057 Binary files /dev/null and b/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewTracking.png differ diff --git a/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewTrackingLandscape.png b/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewTrackingLandscape.png new file mode 100644 index 00000000..db8afdc0 Binary files /dev/null and b/android/composeui/src/test/snapshots/images/com.stadiamaps.ferrostar.views_NavigatingInnerGridViewTest_testNavigatingInnerGridViewTrackingLandscape.png differ diff --git a/android/core/build.gradle b/android/core/build.gradle index 2c948171..44416701 100644 --- a/android/core/build.gradle +++ b/android/core/build.gradle @@ -12,12 +12,12 @@ plugins { android { namespace 'com.stadiamaps.ferrostar.core' - compileSdk 34 + compileSdk 35 ndkVersion "26.2.11394342" defaultConfig { minSdk 25 - targetSdk 34 + targetSdk 35 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" diff --git a/android/core/src/main/java/com/stadiamaps/ferrostar/core/Extensions.kt b/android/core/src/main/java/com/stadiamaps/ferrostar/core/Extensions.kt index c5f73a17..71d66f2d 100644 --- a/android/core/src/main/java/com/stadiamaps/ferrostar/core/Extensions.kt +++ b/android/core/src/main/java/com/stadiamaps/ferrostar/core/Extensions.kt @@ -1,7 +1,10 @@ package com.stadiamaps.ferrostar.core +import kotlin.math.max +import kotlin.math.min import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody +import uniffi.ferrostar.GeographicCoordinate import uniffi.ferrostar.Route import uniffi.ferrostar.RouteRequest import uniffi.ferrostar.getRoutePolyline @@ -25,3 +28,26 @@ fun RouteRequest.toOkhttp3Request(): Request { .apply { headers.map { (name, value) -> header(name, value) } } .build() } + +/** A neutral bounding box type, which is not dependent on any particular map library. */ +data class BoundingBox( + val north: Double, + val east: Double, + val south: Double, + val west: Double, +) + +fun List.boundingBox(): BoundingBox? = + this.firstOrNull()?.let { start -> + val initial = + BoundingBox(north = start.lat, east = start.lng, south = start.lat, west = start.lng) + + fold(initial) { acc, current -> + BoundingBox( + north = max(acc.north, current.lat), + east = max(acc.east, current.lng), + south = min(acc.south, current.lat), + west = min(acc.west, current.lng), + ) + } + } diff --git a/android/core/src/main/java/com/stadiamaps/ferrostar/core/NavigationViewModel.kt b/android/core/src/main/java/com/stadiamaps/ferrostar/core/NavigationViewModel.kt index f381482a..86bb2e54 100644 --- a/android/core/src/main/java/com/stadiamaps/ferrostar/core/NavigationViewModel.kt +++ b/android/core/src/main/java/com/stadiamaps/ferrostar/core/NavigationViewModel.kt @@ -79,6 +79,8 @@ data class NavigationUiState( currentStepRoadName = coreState.tripState.currentRoadName(), remainingSteps = coreState.tripState.remainingSteps()) } + + fun isNavigating(): Boolean = progress != null } interface NavigationViewModel { @@ -88,8 +90,6 @@ interface NavigationViewModel { fun stopNavigation() - fun isNavigating(): Boolean = uiState.value.progress != null - // TODO: We think the camera may eventually need to be owned by the view model, but that's going // to be a very big refactor (maybe even crossing into the MapLibre Compose project) } diff --git a/android/demo-app/build.gradle b/android/demo-app/build.gradle index ffe78c66..b6a00a01 100644 --- a/android/demo-app/build.gradle +++ b/android/demo-app/build.gradle @@ -7,7 +7,7 @@ plugins { android { namespace 'com.stadiamaps.ferrostar' - compileSdk 34 + compileSdk 35 defaultConfig { applicationId "com.stadiamaps.ferrostar.demo" diff --git a/android/demo-app/src/main/java/com/stadiamaps/ferrostar/DemoNavigationScene.kt b/android/demo-app/src/main/java/com/stadiamaps/ferrostar/DemoNavigationScene.kt index 54a80cc6..b2fd92da 100644 --- a/android/demo-app/src/main/java/com/stadiamaps/ferrostar/DemoNavigationScene.kt +++ b/android/demo-app/src/main/java/com/stadiamaps/ferrostar/DemoNavigationScene.kt @@ -73,7 +73,7 @@ fun DemoNavigationScene( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION) } - val vmState = viewModel.uiState.collectAsState(scope.coroutineContext) + val vmState by viewModel.uiState.collectAsState(scope.coroutineContext) val permissionsLauncher = rememberLauncherForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { @@ -104,7 +104,7 @@ fun DemoNavigationScene( } // For smart casting - val loc = vmState.value.location + val loc = vmState.location if (loc == null) { Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> Text("Waiting to acquire your GPS location...", modifier = Modifier.padding(innerPadding)) @@ -130,7 +130,7 @@ fun DemoNavigationScene( vm.startLocationUpdates(locationProvider) }, userContent = { modifier -> - if (!viewModel.isNavigating()) { + if (!vmState.isNavigating()) { InnerGridView( modifier = modifier.fillMaxSize().padding(bottom = 16.dp, top = 16.dp), topCenter = { @@ -167,7 +167,7 @@ fun DemoNavigationScene( // Trivial, if silly example of how to add your own overlay layers. // (Also incidentally highlights the lag inherent in MapLibre location tracking // as-is.) - uiState.value.location?.let { location -> + uiState.location?.let { location -> Circle( center = LatLng(location.coordinates.lat, location.coordinates.lng), radius = 10f, diff --git a/android/google-play-services/build.gradle b/android/google-play-services/build.gradle index 17c765e6..4be1751f 100644 --- a/android/google-play-services/build.gradle +++ b/android/google-play-services/build.gradle @@ -10,7 +10,7 @@ plugins { android { namespace 'com.stadiamaps.ferrostar.googleplayservices' - compileSdk 34 + compileSdk 35 defaultConfig { minSdk 25 diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 2deebe99..6b5df06d 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -14,7 +14,7 @@ androidx-activity-compose = "1.9.3" compose = "2024.10.00" okhttp = "4.12.0" moshi = "1.15.1" -maplibre-compose = "0.2.3" +maplibre-compose = "0.3.0" playServicesLocation = "21.3.0" junit = "4.13.2" junitVersion = "1.2.1" diff --git a/android/maplibreui/build.gradle b/android/maplibreui/build.gradle index 0dd79f3b..e16e46fa 100644 --- a/android/maplibreui/build.gradle +++ b/android/maplibreui/build.gradle @@ -12,7 +12,7 @@ plugins { android { namespace 'com.stadiamaps.ferrostar.maplibreui' - compileSdk 34 + compileSdk 35 defaultConfig { minSdk 25 diff --git a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/NavigationMapView.kt b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/NavigationMapView.kt index 9954d4cd..6b8e6990 100644 --- a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/NavigationMapView.kt +++ b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/NavigationMapView.kt @@ -4,8 +4,10 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.State -import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.maps.Style @@ -16,7 +18,6 @@ import com.maplibre.compose.ramani.LocationRequestProperties import com.maplibre.compose.ramani.MapLibreComposable import com.maplibre.compose.settings.MapControls import com.stadiamaps.ferrostar.core.NavigationUiState -import com.stadiamaps.ferrostar.core.NavigationViewModel import com.stadiamaps.ferrostar.core.toAndroidLocation import com.stadiamaps.ferrostar.maplibreui.extensions.NavigationDefault import com.stadiamaps.ferrostar.maplibreui.runtime.navigationMapViewCamera @@ -30,13 +31,13 @@ import com.stadiamaps.ferrostar.maplibreui.runtime.navigationMapViewCamera * approach and later verified that Google Maps does the same thing in their compose SDK. * @param navigationCamera The default camera settings to use when navigation starts. This will be * re-applied to the camera any time that navigation is started. - * @param viewModel The navigation view model provided by Ferrostar Core. + * @param uiState The navigation UI state. * @param locationRequestProperties The location request properties to use for the map's location * engine. * @param snapUserLocationToRoute If true, the user's displayed location will be snapped to the * route line. * @param onMapReadyCallback A callback that is invoked when the map is ready to be interacted with. - * You must set your desired MapViewCamera tracking mode here! + * If unspecified, the camera will change to `navigationCamera` if navigation is in progress. * @param content Any additional composable map symbol content to render. */ @Composable @@ -44,23 +45,17 @@ fun NavigationMapView( styleUrl: String, camera: MutableState, navigationCamera: MapViewCamera = navigationMapViewCamera(), - viewModel: NavigationViewModel, + uiState: NavigationUiState, mapControls: State, locationRequestProperties: LocationRequestProperties = LocationRequestProperties.NavigationDefault(), snapUserLocationToRoute: Boolean = true, - onMapReadyCallback: (Style) -> Unit = { - if (viewModel.isNavigating()) camera.value = navigationCamera - }, - content: @Composable @MapLibreComposable ((State) -> Unit)? = null + onMapReadyCallback: ((Style) -> Unit)? = null, + content: @Composable @MapLibreComposable ((NavigationUiState) -> Unit)? = null ) { - val uiState = viewModel.uiState.collectAsState() - - // TODO: This works for now, but in the end, the view model may need to "own" the camera. - // We can move this code if we do such a refactor. - var isNavigating = remember { viewModel.isNavigating() } - if (viewModel.isNavigating() != isNavigating) { - isNavigating = viewModel.isNavigating() + var isNavigating by remember { mutableStateOf(uiState.isNavigating()) } + if (uiState.isNavigating() != isNavigating) { + isNavigating = uiState.isNavigating() if (isNavigating) { camera.value = navigationCamera @@ -69,12 +64,10 @@ fun NavigationMapView( val locationEngine = remember { StaticLocationEngine() } locationEngine.lastLocation = - uiState.value.let { state -> - if (snapUserLocationToRoute) { - state.snappedLocation?.toAndroidLocation() - } else { - state.location?.toAndroidLocation() - } + if (snapUserLocationToRoute) { + uiState.snappedLocation?.toAndroidLocation() + } else { + uiState.location?.toAndroidLocation() } MapView( @@ -84,9 +77,10 @@ fun NavigationMapView( mapControls, locationRequestProperties = locationRequestProperties, locationEngine = locationEngine, - onMapReadyCallback = onMapReadyCallback, + onMapReadyCallback = + onMapReadyCallback ?: { if (isNavigating) camera.value = navigationCamera }, ) { - val geometry = uiState.value.routeGeometry + val geometry = uiState.routeGeometry if (geometry != null) BorderedPolyline(points = geometry.map { LatLng(it.lat, it.lng) }, zIndex = 0) diff --git a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/NavigationViewMetrics.kt b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/NavigationViewMetrics.kt new file mode 100644 index 00000000..f9a55802 --- /dev/null +++ b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/NavigationViewMetrics.kt @@ -0,0 +1,8 @@ +package com.stadiamaps.ferrostar.maplibreui + +import androidx.compose.ui.unit.DpSize + +data class NavigationViewMetrics( + val progressViewSize: DpSize, + val instructionsViewSize: DpSize, +) diff --git a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/config/VisualNavigationViewConfig.kt b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/config/VisualNavigationViewConfig.kt deleted file mode 100644 index a59f8af6..00000000 --- a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/config/VisualNavigationViewConfig.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.stadiamaps.ferrostar.maplibreui.config - -data class VisualNavigationViewConfig( - var showMute: Boolean = false, - var showZoom: Boolean = false -) { - companion object { - fun Default() = VisualNavigationViewConfig(showMute = true, showZoom = true) - } -} - -/** Enables the mute button in the navigation view. */ -fun VisualNavigationViewConfig.useMuteButton(): VisualNavigationViewConfig { - showMute = true - return this -} - -/** Enables the zoom button in the navigation view. */ -fun VisualNavigationViewConfig.useZoomButton(): VisualNavigationViewConfig { - showZoom = true - return this -} diff --git a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/extensions/VisualNavigationViewConfig.kt b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/extensions/VisualNavigationViewConfig.kt new file mode 100644 index 00000000..0821f916 --- /dev/null +++ b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/extensions/VisualNavigationViewConfig.kt @@ -0,0 +1,65 @@ +package com.stadiamaps.ferrostar.maplibreui.extensions + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.LayoutDirection +import com.mapbox.mapboxsdk.geometry.LatLngBounds +import com.maplibre.compose.camera.CameraState +import com.maplibre.compose.camera.MapViewCamera +import com.maplibre.compose.camera.models.CameraPadding +import com.stadiamaps.ferrostar.composeui.config.CameraControlState +import com.stadiamaps.ferrostar.composeui.config.VisualNavigationViewConfig +import com.stadiamaps.ferrostar.core.NavigationUiState +import com.stadiamaps.ferrostar.core.boundingBox +import com.stadiamaps.ferrostar.maplibreui.NavigationViewMetrics + +@Composable +fun VisualNavigationViewConfig.cameraControlState( + camera: MutableState, + navigationCamera: MapViewCamera, + uiState: NavigationUiState, + navigationViewMetrics: NavigationViewMetrics +): CameraControlState { + val cameraIsTrackingLocation = camera.value.state is CameraState.TrackingUserLocationWithBearing + val cameraControlState = + if (!cameraIsTrackingLocation) { + CameraControlState.ShowRecenter { camera.value = navigationCamera } + } else { + val bbox = uiState.routeGeometry?.boundingBox() + if (bbox != null) { + val scale = LocalDensity.current.density + val progressViewHeight = navigationViewMetrics.progressViewSize.height.value.toDouble() + val instructionsViewHeight = + navigationViewMetrics.instructionsViewSize.height.value.toDouble() + val layoutDirection = LocalLayoutDirection.current + + // Bottom padding must take the recenter button into account + val bottomPadding = (progressViewHeight + this.buttonSize.height.value + 50) * scale + // The top padding needs to take the puck into account + val topPadding = (instructionsViewHeight + 75) * scale + val (startPadding, endPadding) = + when (layoutDirection) { + LayoutDirection.Ltr -> 20.0 * scale to (this.buttonSize.width.value + 50) * scale + + LayoutDirection.Rtl -> (this.buttonSize.width.value + 50) * scale to 20.0 * scale + } + + CameraControlState.ShowRouteOverview { + camera.value = + MapViewCamera.BoundingBox( + LatLngBounds.from(bbox.north, bbox.east, bbox.south, bbox.west), + padding = + CameraPadding( + startPadding.toDouble(), + topPadding, + endPadding.toDouble(), + bottomPadding)) + } + } else { + CameraControlState.Hidden + } + } + return cameraControlState +} diff --git a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/DynamicallyOrientingNavigationView.kt b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/DynamicallyOrientingNavigationView.kt index e9a37c82..b51f9e42 100644 --- a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/DynamicallyOrientingNavigationView.kt +++ b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/DynamicallyOrientingNavigationView.kt @@ -11,7 +11,7 @@ import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.State +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -23,12 +23,12 @@ import com.maplibre.compose.camera.MapViewCamera import com.maplibre.compose.ramani.LocationRequestProperties import com.maplibre.compose.ramani.MapLibreComposable import com.maplibre.compose.rememberSaveableMapViewCamera +import com.stadiamaps.ferrostar.composeui.config.VisualNavigationViewConfig import com.stadiamaps.ferrostar.composeui.runtime.paddingForGridView import com.stadiamaps.ferrostar.composeui.views.CurrentRoadNameView import com.stadiamaps.ferrostar.core.NavigationUiState import com.stadiamaps.ferrostar.core.NavigationViewModel import com.stadiamaps.ferrostar.maplibreui.NavigationMapView -import com.stadiamaps.ferrostar.maplibreui.config.VisualNavigationViewConfig import com.stadiamaps.ferrostar.maplibreui.extensions.NavigationDefault import com.stadiamaps.ferrostar.maplibreui.runtime.navigationMapViewCamera import com.stadiamaps.ferrostar.maplibreui.runtime.rememberMapControlsForProgressViewHeight @@ -75,13 +75,14 @@ fun DynamicallyOrientingNavigationView( }, onTapExit: (() -> Unit)? = null, userContent: @Composable (BoxScope.(Modifier) -> Unit)? = null, - mapContent: @Composable @MapLibreComposable ((State) -> Unit)? = null, + mapContent: @Composable @MapLibreComposable ((NavigationUiState) -> Unit)? = null, ) { val orientation = LocalConfiguration.current.orientation - // Maintain the actual size of the progress view for MapControl layout purposes. + // Maintain the actual size of the progress view for dynamic layout purposes. val rememberProgressViewSize = remember { mutableStateOf(DpSize.Zero) } val progressViewSize by rememberProgressViewSize + val uiState by viewModel.uiState.collectAsState() // Get the correct padding based on edge-to-edge status. val gridPadding = paddingForGridView() @@ -91,28 +92,25 @@ fun DynamicallyOrientingNavigationView( Box(modifier) { NavigationMapView( - styleUrl, - camera, - navigationCamera, - viewModel, - mapControls, - locationRequestProperties, - snapUserLocationToRoute, - onMapReadyCallback = { - if (viewModel.isNavigating()) { - camera.value = navigationCamera - } - }, - mapContent) + styleUrl = styleUrl, + camera = camera, + navigationCamera = navigationCamera, + uiState = uiState, + mapControls = mapControls, + locationRequestProperties = locationRequestProperties, + snapUserLocationToRoute = snapUserLocationToRoute, + content = mapContent) - if (viewModel.isNavigating()) { + if (uiState.isNavigating()) { when (orientation) { Configuration.ORIENTATION_LANDSCAPE -> { LandscapeNavigationOverlayView( modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars).padding(gridPadding), camera = camera, + navigationCamera = navigationCamera, viewModel = viewModel, config = config, + progressViewSize = rememberProgressViewSize, onTapExit = onTapExit, currentRoadNameView = currentRoadNameView) } @@ -121,6 +119,7 @@ fun DynamicallyOrientingNavigationView( PortraitNavigationOverlayView( modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars).padding(gridPadding), camera = camera, + navigationCamera = navigationCamera, viewModel = viewModel, config = config, progressViewSize = rememberProgressViewSize, diff --git a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/LandscapeNavigationView.kt b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/LandscapeNavigationView.kt index 90c13661..baf6d6ff 100644 --- a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/LandscapeNavigationView.kt +++ b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/LandscapeNavigationView.kt @@ -10,7 +10,8 @@ import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.State +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -18,6 +19,7 @@ import com.maplibre.compose.camera.MapViewCamera import com.maplibre.compose.ramani.LocationRequestProperties import com.maplibre.compose.ramani.MapLibreComposable import com.maplibre.compose.rememberSaveableMapViewCamera +import com.stadiamaps.ferrostar.composeui.config.VisualNavigationViewConfig import com.stadiamaps.ferrostar.composeui.runtime.paddingForGridView import com.stadiamaps.ferrostar.composeui.views.CurrentRoadNameView import com.stadiamaps.ferrostar.core.NavigationUiState @@ -25,7 +27,6 @@ import com.stadiamaps.ferrostar.core.NavigationViewModel import com.stadiamaps.ferrostar.core.mock.MockNavigationViewModel import com.stadiamaps.ferrostar.core.mock.pedestrianExample import com.stadiamaps.ferrostar.maplibreui.NavigationMapView -import com.stadiamaps.ferrostar.maplibreui.config.VisualNavigationViewConfig import com.stadiamaps.ferrostar.maplibreui.extensions.NavigationDefault import com.stadiamaps.ferrostar.maplibreui.runtime.navigationMapViewCamera import com.stadiamaps.ferrostar.maplibreui.runtime.rememberMapControlsForProgressViewHeight @@ -70,8 +71,10 @@ fun LandscapeNavigationView( } }, onTapExit: (() -> Unit)? = null, - content: @Composable @MapLibreComposable() ((State) -> Unit)? = null, + content: @Composable @MapLibreComposable() ((NavigationUiState) -> Unit)? = null, ) { + val uiState by viewModel.uiState.collectAsState() + // Get the correct padding based on edge-to-edge status. val gridPadding = paddingForGridView() @@ -82,7 +85,7 @@ fun LandscapeNavigationView( styleUrl, camera, navigationCamera, - viewModel, + uiState, mapControls, locationRequestProperties, snapUserLocationToRoute, @@ -93,6 +96,7 @@ fun LandscapeNavigationView( modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars).padding(gridPadding), config = config, camera = camera, + navigationCamera = navigationCamera, viewModel = viewModel, onTapExit = onTapExit, currentRoadNameView = currentRoadNameView) diff --git a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/PortraitNavigationView.kt b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/PortraitNavigationView.kt index 8738fb5d..f7ba7ff5 100644 --- a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/PortraitNavigationView.kt +++ b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/PortraitNavigationView.kt @@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.State +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -23,6 +23,7 @@ import com.maplibre.compose.camera.MapViewCamera import com.maplibre.compose.ramani.LocationRequestProperties import com.maplibre.compose.ramani.MapLibreComposable import com.maplibre.compose.rememberSaveableMapViewCamera +import com.stadiamaps.ferrostar.composeui.config.VisualNavigationViewConfig import com.stadiamaps.ferrostar.composeui.runtime.paddingForGridView import com.stadiamaps.ferrostar.composeui.views.CurrentRoadNameView import com.stadiamaps.ferrostar.core.NavigationUiState @@ -30,7 +31,6 @@ import com.stadiamaps.ferrostar.core.NavigationViewModel import com.stadiamaps.ferrostar.core.mock.MockNavigationViewModel import com.stadiamaps.ferrostar.core.mock.pedestrianExample import com.stadiamaps.ferrostar.maplibreui.NavigationMapView -import com.stadiamaps.ferrostar.maplibreui.config.VisualNavigationViewConfig import com.stadiamaps.ferrostar.maplibreui.extensions.NavigationDefault import com.stadiamaps.ferrostar.maplibreui.runtime.navigationMapViewCamera import com.stadiamaps.ferrostar.maplibreui.runtime.rememberMapControlsForProgressViewHeight @@ -74,8 +74,10 @@ fun PortraitNavigationView( } }, onTapExit: (() -> Unit)? = null, - content: @Composable @MapLibreComposable() ((State) -> Unit)? = null, + content: @Composable @MapLibreComposable() ((NavigationUiState) -> Unit)? = null, ) { + val uiState by viewModel.uiState.collectAsState() + // Get the correct padding based on edge-to-edge status. val gridPadding = paddingForGridView() @@ -91,21 +93,24 @@ fun PortraitNavigationView( styleUrl, camera, navigationCamera, - viewModel, + uiState, mapControls, locationRequestProperties, snapUserLocationToRoute, onMapReadyCallback = { camera.value = navigationCamera }, content) - PortraitNavigationOverlayView( - modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars).padding(gridPadding), - config = config, - camera = camera, - viewModel = viewModel, - progressViewSize = rememberProgressViewSize, - onTapExit = onTapExit, - currentRoadNameView = currentRoadNameView) + if (uiState.isNavigating()) { + PortraitNavigationOverlayView( + modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars).padding(gridPadding), + config = config, + camera = camera, + navigationCamera = navigationCamera, + viewModel = viewModel, + progressViewSize = rememberProgressViewSize, + onTapExit = onTapExit, + currentRoadNameView = currentRoadNameView) + } } } @@ -113,8 +118,7 @@ fun PortraitNavigationView( @Composable private fun PortraitNavigationViewPreview() { val viewModel = - MockNavigationViewModel( - MutableStateFlow(NavigationUiState.pedestrianExample()).asStateFlow()) + MockNavigationViewModel(MutableStateFlow(NavigationUiState.pedestrianExample()).asStateFlow()) PortraitNavigationView( Modifier.fillMaxSize(), diff --git a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/overlays/LandscapeNavigationOverlayView.kt b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/overlays/LandscapeNavigationOverlayView.kt index 790f144e..a38fcb58 100644 --- a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/overlays/LandscapeNavigationOverlayView.kt +++ b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/overlays/LandscapeNavigationOverlayView.kt @@ -12,13 +12,19 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp -import com.maplibre.compose.camera.CameraState import com.maplibre.compose.camera.MapViewCamera import com.maplibre.compose.camera.extensions.incrementZoom import com.maplibre.compose.rememberSaveableMapViewCamera +import com.stadiamaps.ferrostar.composeui.config.VisualNavigationViewConfig import com.stadiamaps.ferrostar.composeui.views.CurrentRoadNameView import com.stadiamaps.ferrostar.composeui.views.InstructionsView import com.stadiamaps.ferrostar.composeui.views.TripProgressView @@ -27,7 +33,8 @@ import com.stadiamaps.ferrostar.core.NavigationUiState import com.stadiamaps.ferrostar.core.NavigationViewModel import com.stadiamaps.ferrostar.core.mock.MockNavigationViewModel import com.stadiamaps.ferrostar.core.mock.pedestrianExample -import com.stadiamaps.ferrostar.maplibreui.config.VisualNavigationViewConfig +import com.stadiamaps.ferrostar.maplibreui.NavigationViewMetrics +import com.stadiamaps.ferrostar.maplibreui.extensions.cameraControlState import com.stadiamaps.ferrostar.maplibreui.runtime.navigationMapViewCamera import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -36,9 +43,10 @@ import kotlinx.coroutines.flow.asStateFlow fun LandscapeNavigationOverlayView( modifier: Modifier, camera: MutableState, - navigationCamera: MapViewCamera = navigationMapViewCamera(), + navigationCamera: MapViewCamera, viewModel: NavigationViewModel, config: VisualNavigationViewConfig = VisualNavigationViewConfig.Default(), + progressViewSize: MutableState = remember { mutableStateOf(DpSize.Zero) }, currentRoadNameView: @Composable (String?) -> Unit = { roadName -> if (roadName != null) { CurrentRoadNameView(roadName) @@ -47,14 +55,19 @@ fun LandscapeNavigationOverlayView( }, onTapExit: (() -> Unit)? = null, ) { + val density = LocalDensity.current val uiState by viewModel.uiState.collectAsState() - val cameraIsTrackingLocation = camera.value.state is CameraState.TrackingUserLocationWithBearing + var instructionsViewSize by remember { mutableStateOf(DpSize.Zero) } Row(modifier) { Column(modifier = Modifier.fillMaxHeight().fillMaxWidth(0.5f)) { uiState.visualInstruction?.let { instructions -> InstructionsView( instructions, + modifier = + Modifier.onSizeChanged { + instructionsViewSize = density.run { DpSize(it.width.toDp(), it.height.toDp()) } + }, remainingSteps = uiState.remainingSteps, distanceToNextManeuver = uiState.progress?.distanceToNextManeuver) } @@ -62,7 +75,13 @@ fun LandscapeNavigationOverlayView( Spacer(modifier = Modifier.weight(1f)) uiState.progress?.let { progress -> - TripProgressView(progress = progress, onTapExit = onTapExit) + TripProgressView( + modifier = + Modifier.onSizeChanged { + progressViewSize.value = density.run { DpSize(it.width.toDp(), it.height.toDp()) } + }, + progress = progress, + onTapExit = onTapExit) } } @@ -74,11 +93,17 @@ fun LandscapeNavigationOverlayView( showMute = config.showMute, isMuted = uiState.isMuted, onClickMute = { viewModel.toggleMute() }, + buttonSize = config.buttonSize, + cameraControlState = + config.cameraControlState( + camera, + navigationCamera, + uiState, + NavigationViewMetrics(progressViewSize.value, instructionsViewSize), + ), showZoom = config.showZoom, onClickZoomIn = { camera.value = camera.value.incrementZoom(1.0) }, - onClickZoomOut = { camera.value = camera.value.incrementZoom(-1.0) }, - showCentering = !cameraIsTrackingLocation, - onClickCenter = { camera.value = navigationCamera }) + onClickZoomOut = { camera.value = camera.value.incrementZoom(-1.0) }) } } } @@ -95,6 +120,7 @@ fun LandscapeNavigationOverlayViewPreview() { LandscapeNavigationOverlayView( modifier = Modifier.fillMaxSize(), camera = rememberSaveableMapViewCamera(), + navigationCamera = navigationMapViewCamera(), viewModel = viewModel, onTapExit = {}) } diff --git a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/overlays/PortraitNavigationOverlayView.kt b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/overlays/PortraitNavigationOverlayView.kt index c2bf2fd8..596238a4 100644 --- a/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/overlays/PortraitNavigationOverlayView.kt +++ b/android/maplibreui/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/overlays/PortraitNavigationOverlayView.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.onSizeChanged @@ -22,6 +23,7 @@ import com.maplibre.compose.camera.CameraState import com.maplibre.compose.camera.MapViewCamera import com.maplibre.compose.camera.extensions.incrementZoom import com.maplibre.compose.rememberSaveableMapViewCamera +import com.stadiamaps.ferrostar.composeui.config.VisualNavigationViewConfig import com.stadiamaps.ferrostar.composeui.views.CurrentRoadNameView import com.stadiamaps.ferrostar.composeui.views.InstructionsView import com.stadiamaps.ferrostar.composeui.views.TripProgressView @@ -30,7 +32,8 @@ import com.stadiamaps.ferrostar.core.NavigationUiState import com.stadiamaps.ferrostar.core.NavigationViewModel import com.stadiamaps.ferrostar.core.mock.MockNavigationViewModel import com.stadiamaps.ferrostar.core.mock.pedestrianExample -import com.stadiamaps.ferrostar.maplibreui.config.VisualNavigationViewConfig +import com.stadiamaps.ferrostar.maplibreui.NavigationViewMetrics +import com.stadiamaps.ferrostar.maplibreui.extensions.cameraControlState import com.stadiamaps.ferrostar.maplibreui.runtime.navigationMapViewCamera import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -39,7 +42,7 @@ import kotlinx.coroutines.flow.asStateFlow fun PortraitNavigationOverlayView( modifier: Modifier, camera: MutableState, - navigationCamera: MapViewCamera = navigationMapViewCamera(), + navigationCamera: MapViewCamera, viewModel: NavigationViewModel, config: VisualNavigationViewConfig = VisualNavigationViewConfig.Default(), progressViewSize: MutableState = remember { mutableStateOf(DpSize.Zero) }, @@ -53,11 +56,16 @@ fun PortraitNavigationOverlayView( ) { val density = LocalDensity.current val uiState by viewModel.uiState.collectAsState() + var instructionsViewSize by remember { mutableStateOf(DpSize.Zero) } Column(modifier) { uiState.visualInstruction?.let { instructions -> InstructionsView( instructions, + modifier = + Modifier.onSizeChanged { + instructionsViewSize = density.run { DpSize(it.width.toDp(), it.height.toDp()) } + }, remainingSteps = uiState.remainingSteps, distanceToNextManeuver = uiState.progress?.distanceToNextManeuver) } @@ -69,11 +77,17 @@ fun PortraitNavigationOverlayView( showMute = config.showMute, isMuted = uiState.isMuted, onClickMute = { viewModel.toggleMute() }, + buttonSize = config.buttonSize, + cameraControlState = + config.cameraControlState( + camera, + navigationCamera, + uiState, + NavigationViewMetrics(progressViewSize.value, instructionsViewSize), + ), showZoom = config.showZoom, onClickZoomIn = { camera.value = camera.value.incrementZoom(1.0) }, onClickZoomOut = { camera.value = camera.value.incrementZoom(-1.0) }, - showCentering = !cameraIsTrackingLocation, - onClickCenter = { camera.value = navigationCamera }, ) uiState.progress?.let { progress -> @@ -82,6 +96,7 @@ fun PortraitNavigationOverlayView( if (cameraIsTrackingLocation) { uiState.currentStepRoadName } else { + // Hide the road name view if not tracking the user location null } currentRoadName?.let { roadName -> currentRoadNameView(roadName) } @@ -106,6 +121,7 @@ fun PortraitNavigationOverlayViewPreview() { PortraitNavigationOverlayView( modifier = Modifier.fillMaxSize(), camera = rememberSaveableMapViewCamera(), + navigationCamera = navigationMapViewCamera(), viewModel = viewModel, onTapExit = {}) } diff --git a/android/maplibreui/src/test/java/com/stadiamaps/ferrostar/maplibreui/config/VisualNavigationViewConfigTest.kt b/android/maplibreui/src/test/java/com/stadiamaps/ferrostar/maplibreui/config/VisualNavigationViewConfigTest.kt index 2e1d5f67..6d5c247d 100644 --- a/android/maplibreui/src/test/java/com/stadiamaps/ferrostar/maplibreui/config/VisualNavigationViewConfigTest.kt +++ b/android/maplibreui/src/test/java/com/stadiamaps/ferrostar/maplibreui/config/VisualNavigationViewConfigTest.kt @@ -1,5 +1,12 @@ package com.stadiamaps.ferrostar.maplibreui.config +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import com.stadiamaps.ferrostar.composeui.config.VisualNavigationViewConfig +import com.stadiamaps.ferrostar.composeui.config.buttonSize +import com.stadiamaps.ferrostar.composeui.config.useMuteButton +import com.stadiamaps.ferrostar.composeui.config.useZoomButton +import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Test @@ -37,4 +44,11 @@ class VisualNavigationViewConfigTest { assert(config.showMute) assert(config.showZoom) } + + @Test + fun testButtonSize() { + val newSize = DpSize(42.dp, 42.dp) + val config = VisualNavigationViewConfig().buttonSize(newSize) + assertEquals(newSize, config.buttonSize) + } } diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/CurrentRoadViewTests/testDefaultCurrentRoadView.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/CurrentRoadViewTests/testDefaultCurrentRoadView.1.png index cb80ba99..23273bfd 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/CurrentRoadViewTests/testDefaultCurrentRoadView.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/CurrentRoadViewTests/testDefaultCurrentRoadView.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/CurrentRoadViewTests/testDefaultCurrentRoadViewFunkyStyle.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/CurrentRoadViewTests/testDefaultCurrentRoadViewFunkyStyle.1.png index 056091fb..e4f85d23 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/CurrentRoadViewTests/testDefaultCurrentRoadViewFunkyStyle.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/CurrentRoadViewTests/testDefaultCurrentRoadViewFunkyStyle.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/DefaultManeuverInstructionViewTests/testDefaultManeuverInstructionViewDE.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/DefaultManeuverInstructionViewTests/testDefaultManeuverInstructionViewDE.1.png index 2dccfad1..1ce511ee 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/DefaultManeuverInstructionViewTests/testDefaultManeuverInstructionViewDE.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/DefaultManeuverInstructionViewTests/testDefaultManeuverInstructionViewDE.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/DefaultManeuverInstructionViewTests/testDefaultManeuverInstructionViewUS.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/DefaultManeuverInstructionViewTests/testDefaultManeuverInstructionViewUS.1.png index b4caa1d5..9154bb24 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/DefaultManeuverInstructionViewTests/testDefaultManeuverInstructionViewUS.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/DefaultManeuverInstructionViewTests/testDefaultManeuverInstructionViewUS.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testExpandedInstructionsView.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testExpandedInstructionsView.1.png index 6ade82fa..0631457e 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testExpandedInstructionsView.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testExpandedInstructionsView.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testExpandedInstructionsView_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testExpandedInstructionsView_darkMode.1.png index 889cda8e..d5fcf108 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testExpandedInstructionsView_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testExpandedInstructionsView_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testFormattingDE.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testFormattingDE.1.png index e3dee473..3c25ddfe 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testFormattingDE.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testFormattingDE.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testInstructionsView.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testInstructionsView.1.png index a85668d0..0b2798b3 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testInstructionsView.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testInstructionsView.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testInstructionsView_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testInstructionsView_darkMode.1.png index 3bb92c52..a9b4a78f 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testInstructionsView_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testInstructionsView_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsView.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsView.1.png index 50e5f02f..bb336de5 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsView.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsView.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsViewWithPill.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsViewWithPill.1.png index 9c05bb0b..f0428b3f 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsViewWithPill.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsViewWithPill.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsViewWithPill_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsViewWithPill_darkMode.1.png index 76e85c51..b538dd15 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsViewWithPill_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/InstructionsViewTests/testSingularInstructionsViewWithPill_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testCustomManeuverInstructionIcon.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testCustomManeuverInstructionIcon.1.png index 0806d156..0dbca39c 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testCustomManeuverInstructionIcon.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testCustomManeuverInstructionIcon.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testFerrostarInstruction.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testFerrostarInstruction.1.png index caa262a6..f189599c 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testFerrostarInstruction.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testFerrostarInstruction.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testFerrostarInstructionDE.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testFerrostarInstructionDE.1.png index ed38a236..bca80122 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testFerrostarInstructionDE.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testFerrostarInstructionDE.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testRightToLeftInstruction.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testRightToLeftInstruction.1.png index d8e8c85c..5593991f 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testRightToLeftInstruction.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/ManeuverInstructionViewTests/testRightToLeftInstruction.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_muted.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_muted.1.png index e37fa447..5ff54654 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_muted.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_muted.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_muted_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_muted_darkMode.1.png index b79f6187..c0bee653 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_muted_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_muted_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_unmuted.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_unmuted.1.png index f3d4d9c1..60560a24 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_unmuted.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_unmuted.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_unmuted_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_unmuted_darkMode.1.png index ebceb94d..1e82d2d6 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_unmuted_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/MuteButtonTests/test_unmuted_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_USStyle_speedLimit_inGridView.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_USStyle_speedLimit_inGridView.1.png index edee9464..7c53c4d8 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_USStyle_speedLimit_inGridView.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_USStyle_speedLimit_inGridView.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_ViennaConventionStyle_speedLimit_inGridView.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_ViennaConventionStyle_speedLimit_inGridView.1.png index 57e73e5c..03ab4071 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_ViennaConventionStyle_speedLimit_inGridView.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_ViennaConventionStyle_speedLimit_inGridView.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_muteIsHidden.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_muteIsHidden.1.png index 3aef3cea..4ad910cf 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_muteIsHidden.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigatingInnerGridViewTests/test_muteIsHidden.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testErrorBanner.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testErrorBanner.1.png index f30573f9..b09b254e 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testErrorBanner.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testErrorBanner.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testErrorBanner_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testErrorBanner_darkMode.1.png index f60c3f6f..0910dd85 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testErrorBanner_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testErrorBanner_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testInfoBanner.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testInfoBanner.1.png index 990b42ca..e2a2c638 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testInfoBanner.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testInfoBanner.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testInfoBanner_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testInfoBanner_darkMode.1.png index afa54567..2be77b9f 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testInfoBanner_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testInfoBanner_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testLoadingBanner.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testLoadingBanner.1.png index 0d999863..05dca644 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testLoadingBanner.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testLoadingBanner.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testLoadingBanner_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testLoadingBanner_darkMode.1.png index 90f935a2..d3560a2a 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testLoadingBanner_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIBannerViewTests/testLoadingBanner_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIButtonTests/testTextButton.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIButtonTests/testTextButton.1.png index 4c6077e5..f0209b9c 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIButtonTests/testTextButton.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIButtonTests/testTextButton.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIButtonTests/testTextButton_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIButtonTests/testTextButton_darkMode.1.png index c0ee0d71..e9afe499 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIButtonTests/testTextButton_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIButtonTests/testTextButton_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIZoomButtonTests/testNavigationUIZoomButton.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIZoomButtonTests/testNavigationUIZoomButton.1.png index c1a9c100..756c57cb 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIZoomButtonTests/testNavigationUIZoomButton.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIZoomButtonTests/testNavigationUIZoomButton.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIZoomButtonTests/testNavigationUIZoomButton_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIZoomButtonTests/testNavigationUIZoomButton_darkMode.1.png index ced1fd2b..5e27a8d0 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIZoomButtonTests/testNavigationUIZoomButton_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/NavigationUIZoomButtonTests/testNavigationUIZoomButton_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.1.png index 38d6a79b..68fc12f8 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.2.png index 0602b8a0..a8a3c82d 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.2.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.3.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.3.png index c485e9ae..a66ec7d8 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.3.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.3.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.4.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.4.png index 865c350a..671cfa8a 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.4.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews.4.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.1.png index 38d6a79b..68fc12f8 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.2.png index 0602b8a0..a8a3c82d 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.2.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.3.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.3.png index c485e9ae..a66ec7d8 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.3.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.3.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.4.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.4.png index 865c350a..671cfa8a 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.4.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testUSStyleSpeedLimitViews_darkMode.4.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.1.png index 80a33280..16e345e1 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.2.png index 241db65f..78954986 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.2.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.3.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.3.png index 73074b26..2da3abb6 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.3.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.3.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.4.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.4.png index 83f82b35..39eda591 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.4.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews.4.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.1.png index 80a33280..16e345e1 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.2.png index 241db65f..78954986 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.2.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.3.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.3.png index 73074b26..2da3abb6 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.3.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.3.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.4.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.4.png index 83f82b35..39eda591 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.4.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/SpeedLimitViewTests/testViennaConventionStyleSpeedLimitViews_darkMode.4.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewCompactTheme.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewCompactTheme.1.png index a4777ce8..c43a7998 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewCompactTheme.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewCompactTheme.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewCompactTheme_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewCompactTheme_darkMode.1.png index 43b3ad3f..199d7b23 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewCompactTheme_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewCompactTheme_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme.1.png index d6b73f01..283ba5ba 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme.2.png index ee64bc04..378d5592 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme.2.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme_darkMode.1.png index 1e1f68bd..f87223a0 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme_darkMode.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme_darkMode.2.png index f0bd93fa..58360402 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme_darkMode.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewDefaultTheme_darkMode.2.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters.1.png index c90c9808..57264769 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_darkMode.1.png index c04de7be..340283a5 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE.1.png index 5792ab05..a8d98eff 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE.2.png index 6a467443..a0b29133 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE.2.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE_darkMode.1.png index 79f874d7..0d59504e 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE_darkMode.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE_darkMode.2.png index 78c5daaf..c334da5e 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE_darkMode.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewTests/testTripProgressViewFormatters_de_DE_darkMode.2.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewCompactTheme.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewCompactTheme.1.png index 40828204..fb097661 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewCompactTheme.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewCompactTheme.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewCompactTheme_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewCompactTheme_darkMode.1.png index 18a8c889..64792650 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewCompactTheme_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewCompactTheme_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme.1.png index fe741353..6cf41a45 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme.2.png index 14d3ef1d..7f2addd8 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme.2.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme_darkMode.1.png index c7fadac2..c7c28d94 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme_darkMode.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme_darkMode.2.png index ca29158f..8451a35c 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme_darkMode.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewDefaultTheme_darkMode.2.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters.1.png index 4f1867f3..3f7680c3 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_darkMode.1.png index 840d4bf4..426a41fb 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE.1.png index 895eefc9..2a133506 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE.2.png index 3a13b472..2af97a6e 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE.2.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE_darkMode.1.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE_darkMode.1.png index 932f27ef..63442838 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE_darkMode.1.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE_darkMode.1.png differ diff --git a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE_darkMode.2.png b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE_darkMode.2.png index 8eabd4e2..28fef2fa 100644 Binary files a/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE_darkMode.2.png and b/apple/Tests/FerrostarSwiftUITests/Views/__Snapshots__/TripProgressViewWithButtonTests/testTripProgressViewFormatters_de_DE_darkMode.2.png differ