diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/AppContent.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/AppContent.kt
index b6f893e1c53ee631727d3efeb32d139735f3c133..648024b0afd34decdc9f562980818e9118a7225e 100644
--- a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/AppContent.kt
+++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/core/AppContent.kt
@@ -110,7 +110,7 @@ import earth.maps.cardinal.routing.RouteRepository
import earth.maps.cardinal.ui.directions.DirectionsScreen
import earth.maps.cardinal.ui.directions.DirectionsViewModel
import earth.maps.cardinal.ui.directions.RouteDisplayHandler
-import earth.maps.cardinal.ui.directions.TurnByTurnNavigationScreen
+import earth.maps.cardinal.ui.navigation.TurnByTurnNavigationScreen
import earth.maps.cardinal.ui.home.HomeScreen
import earth.maps.cardinal.ui.home.HomeViewModel
import earth.maps.cardinal.ui.home.NearbyScreenContent
diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/navigation/NavigationChrome.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/navigation/NavigationChrome.kt
new file mode 100644
index 0000000000000000000000000000000000000000..27b2c8aa01e04e60169cb90b148008c1e9246655
--- /dev/null
+++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/navigation/NavigationChrome.kt
@@ -0,0 +1,150 @@
+package earth.maps.cardinal.ui.navigation
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+import com.stadiamaps.ferrostar.composeui.config.NavigationViewComponentBuilder
+import com.stadiamaps.ferrostar.composeui.models.CameraControlState
+import com.stadiamaps.ferrostar.composeui.theme.DefaultInstructionRowTheme
+import com.stadiamaps.ferrostar.composeui.theme.DefaultRoadNameViewTheme
+import com.stadiamaps.ferrostar.composeui.theme.InstructionRowTheme
+import com.stadiamaps.ferrostar.composeui.theme.NavigationUITheme
+import com.stadiamaps.ferrostar.composeui.theme.RoadNameViewTheme
+import com.stadiamaps.ferrostar.composeui.theme.TripProgressViewStyle
+import com.stadiamaps.ferrostar.composeui.theme.TripProgressViewTheme
+import com.stadiamaps.ferrostar.composeui.views.components.CurrentRoadNameView
+import com.stadiamaps.ferrostar.composeui.views.components.InstructionsView
+import com.stadiamaps.ferrostar.composeui.views.components.TripProgressView
+import com.stadiamaps.ferrostar.core.NavigationUiState
+import kotlin.time.ExperimentalTime
+
+object CardinalNavigationUITheme : NavigationUITheme {
+ override val instructionRowTheme: InstructionRowTheme
+ @Composable get() = DefaultInstructionRowTheme
+
+ override val roadNameViewTheme: RoadNameViewTheme
+ @Composable get() = DefaultRoadNameViewTheme
+
+ override val tripProgressViewTheme: TripProgressViewTheme
+ @Composable get() = CardinalTripProgressViewTheme
+
+ override val buttonSize: DpSize
+ @Composable get() = DpSize(56.dp, 56.dp)
+}
+
+object CardinalTripProgressViewTheme : TripProgressViewTheme {
+ override val style: TripProgressViewStyle
+ @Composable get() = TripProgressViewStyle.SIMPLIFIED
+
+ override val measurementTextStyle: TextStyle
+ @Composable
+ get() =
+ MaterialTheme.typography.titleLarge.copy(
+ color = MaterialTheme.colorScheme.onSurface, fontWeight = FontWeight.Normal)
+
+ override val secondaryTextStyle: TextStyle
+ @Composable
+ get() =
+ MaterialTheme.typography.labelSmall.copy(color = MaterialTheme.colorScheme.onSurfaceVariant)
+
+ override val exitIconColor: Color
+ @Composable get() = MaterialTheme.colorScheme.onSecondary
+
+ override val exitButtonBackgroundColor: Color
+ @Composable get() = MaterialTheme.colorScheme.secondary
+
+ override val backgroundColor: Color
+ @Composable get() = MaterialTheme.colorScheme.surface
+}
+
+
+@Composable
+fun CardinalInstructionsView(modifier: Modifier, uiState: NavigationUiState) {
+ uiState.visualInstruction?.let { instructions ->
+ InstructionsView(
+ modifier = modifier,
+ instructions = instructions,
+ theme = CardinalNavigationUITheme.instructionRowTheme,
+ remainingSteps = uiState.remainingSteps,
+ distanceToNextManeuver = uiState.progress?.distanceToNextManeuver
+ )
+ }
+}
+
+@OptIn(ExperimentalTime::class)
+@Composable
+fun CardinalProgressView(
+ modifier: Modifier,
+ uiState: NavigationUiState,
+ onTapExit: (() -> Unit)?
+) {
+ uiState.progress?.let { progress ->
+ TripProgressView(
+ modifier = modifier,
+ theme = CardinalNavigationUITheme.tripProgressViewTheme,
+ progress = progress,
+ onTapExit = onTapExit
+ )
+ }
+}
+
+@Composable
+fun CardinalRoadNameView(
+ modifier: Modifier,
+ roadName: String?,
+ cameraControlState: CameraControlState
+) {
+ if (cameraControlState is CameraControlState.ShowRouteOverview) {
+ roadName?.let { roadName ->
+ Row(
+ modifier.fillMaxWidth(),
+ verticalAlignment = Alignment.Bottom,
+ horizontalArrangement = Arrangement.Center
+ ) {
+ CurrentRoadNameView(
+ modifier = modifier,
+ theme = CardinalNavigationUITheme.roadNameViewTheme,
+ currentRoadName = roadName
+ )
+
+ Spacer(modifier = Modifier.height(8.dp))
+ }
+ }
+ }
+}
+
+fun navigationViewComponentBuilder(): NavigationViewComponentBuilder {
+ return NavigationViewComponentBuilder(
+ instructionsView = @Composable { modifier, navigationUiState ->
+ CardinalInstructionsView(
+ modifier,
+ navigationUiState
+ )
+ },
+ progressView = @Composable { modifier, navigationUiState, onTapExit ->
+ CardinalProgressView(
+ modifier,
+ navigationUiState,
+ onTapExit
+ )
+ },
+ roadNameView = @Composable { modifier, roadName, cameraControlState ->
+ CardinalRoadNameView(
+ modifier,
+ roadName,
+ cameraControlState
+ )
+ },
+ )
+}
diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/TurnByTurnNavigationScreen.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/navigation/TurnByTurnNavigationScreen.kt
similarity index 95%
rename from cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/TurnByTurnNavigationScreen.kt
rename to cardinal-android/app/src/main/java/earth/maps/cardinal/ui/navigation/TurnByTurnNavigationScreen.kt
index 6c107ba0823afdf330ba0953804d4c99e8ff2506..02b1ec0027368cf0daabf388c2af2a60f26609ee 100644
--- a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/TurnByTurnNavigationScreen.kt
+++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/navigation/TurnByTurnNavigationScreen.kt
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-package earth.maps.cardinal.ui.directions
+package earth.maps.cardinal.ui.navigation
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
@@ -107,7 +107,10 @@ fun TurnByTurnNavigationScreen(
// Only display the navigation view if we have a route
if (route != null) {
DynamicallyOrientingNavigationView(
- styleUrl = styleUrl, modifier = Modifier, viewModel = viewModel
+ styleUrl = styleUrl,
+ modifier = Modifier,
+ viewModel = viewModel,
+ views = navigationViewComponentBuilder()
)
} else {
// Show a placeholder or loading state when no route is available
diff --git a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/TurnByTurnNavigationViewModel.kt b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/navigation/TurnByTurnNavigationViewModel.kt
similarity index 96%
rename from cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/TurnByTurnNavigationViewModel.kt
rename to cardinal-android/app/src/main/java/earth/maps/cardinal/ui/navigation/TurnByTurnNavigationViewModel.kt
index 65462f649ac465e3f1d259c2c5add5416d296358..5cb8f7b653e7b07d6cc903f064ff6177e8d59265 100644
--- a/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/directions/TurnByTurnNavigationViewModel.kt
+++ b/cardinal-android/app/src/main/java/earth/maps/cardinal/ui/navigation/TurnByTurnNavigationViewModel.kt
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
-package earth.maps.cardinal.ui.directions
+package earth.maps.cardinal.ui.navigation
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
diff --git a/cardinal-android/app/src/test/java/earth/maps/cardinal/ui/directions/TurnByTurnNavigationViewModelTest.kt b/cardinal-android/app/src/test/java/earth/maps/cardinal/ui/directions/TurnByTurnNavigationViewModelTest.kt
index 962f027bdf8f37f629519dad42ce755427d7a352..265cc88d602aac37f155ba18a8c7ce5007fb1ffc 100644
--- a/cardinal-android/app/src/test/java/earth/maps/cardinal/ui/directions/TurnByTurnNavigationViewModelTest.kt
+++ b/cardinal-android/app/src/test/java/earth/maps/cardinal/ui/directions/TurnByTurnNavigationViewModelTest.kt
@@ -19,6 +19,7 @@
package earth.maps.cardinal.ui.directions
import earth.maps.cardinal.routing.FerrostarWrapperRepository
+import earth.maps.cardinal.ui.navigation.TurnByTurnNavigationViewModel
import io.mockk.mockk
import org.junit.Assert.assertEquals
import org.junit.Before