Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/android/view refactor #356

Merged
merged 10 commits into from
Nov 13, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.stadiamaps.ferrostar.composeui.config

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxScope
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.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.stadiamaps.ferrostar.composeui.models.CameraControlState
import com.stadiamaps.ferrostar.composeui.theme.DefaultNavigationUITheme
import com.stadiamaps.ferrostar.composeui.theme.NavigationUITheme
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

data class NavigationViewComponentBuilder(
val instructionsView: @Composable (modifier: Modifier, uiState: NavigationUiState) -> Unit,
val progressView:
@Composable
(modifier: Modifier, uiState: NavigationUiState, onTapExit: (() -> Unit)?) -> Unit,
val streetNameView:
@Composable
(modifier: Modifier, roadName: String?, cameraControlState: CameraControlState) -> Unit,
val customOverlayView: @Composable (BoxScope.(Modifier) -> Unit)? = null,
// TODO: We may reasonably be able to add the NavigationMapView here. But not sure how much
// value that would add
// since most of the hard config already exists within the overlay views which are not
// maplibre specific.
) {
companion object {
fun Default(theme: NavigationUITheme = DefaultNavigationUITheme) =
NavigationViewComponentBuilder(
instructionsView = { modifier, uiState ->
uiState.visualInstruction?.let { instructions ->
InstructionsView(
modifier = modifier,
instructions = instructions,
theme = theme.instructionRowTheme,
remainingSteps = uiState.remainingSteps,
distanceToNextManeuver = uiState.progress?.distanceToNextManeuver)
}
},
progressView = { modifier, uiState, onTapExit ->
uiState.progress?.let { progress ->
TripProgressView(
modifier = modifier,
theme = theme.tripProgressViewTheme,
progress = progress,
onTapExit = onTapExit)
}
},
streetNameView = { modifier, roadName, cameraControlState ->
if (cameraControlState is CameraControlState.ShowRouteOverview) {
roadName?.let { roadName ->
Row(
modifier.fillMaxWidth(),
verticalAlignment = Alignment.Bottom,
horizontalArrangement = Arrangement.Center) {
CurrentRoadNameView(
modifier = modifier,
theme = theme.roadNameViewTheme,
currentRoadName = roadName)

Spacer(modifier = Modifier.height(8.dp))
}
}
}
})
}
}

fun NavigationViewComponentBuilder.withInstructionsView(
instructionsView: @Composable (modifier: Modifier, uiState: NavigationUiState) -> Unit
): NavigationViewComponentBuilder {
return copy(instructionsView = instructionsView)
}

fun NavigationViewComponentBuilder.withProgressView(
progressView:
@Composable
(modifier: Modifier, uiState: NavigationUiState, onTapExit: (() -> Unit)?) -> Unit
): NavigationViewComponentBuilder {
return copy(progressView = progressView)
}

fun NavigationViewComponentBuilder.withStreetNameView(
streetNameView:
@Composable
(modifier: Modifier, roadName: String?, cameraControlState: CameraControlState) -> Unit
): NavigationViewComponentBuilder {
return copy(streetNameView = streetNameView)
}

fun NavigationViewComponentBuilder.withCustomOverlayView(
customOverlayView: @Composable (BoxScope.(Modifier) -> Unit)
): NavigationViewComponentBuilder {
return copy(customOverlayView = customOverlayView)
}
Original file line number Diff line number Diff line change
@@ -1,40 +1,29 @@
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(
// Mute
var showMute: Boolean = false,
var onMute: (() -> Unit)? = null,

// Zoom
var showZoom: Boolean = false,
var buttonSize: DpSize = DpSize(56.dp, 56.dp)
var onZoomIn: (() -> Unit)? = null,
var onZoomOut: (() -> Unit)? = null,
) {
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
fun VisualNavigationViewConfig.useMuteButton(onMute: () -> Unit): VisualNavigationViewConfig {
return copy(showMute = true, onMute = onMute)
}

/** 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
fun VisualNavigationViewConfig.useZoomButton(
onZoomIn: () -> Unit,
onZoomOut: () -> Unit
): VisualNavigationViewConfig {
return copy(showZoom = true, onZoomIn = onZoomIn, onZoomOut = onZoomOut)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.stadiamaps.ferrostar.composeui.models

sealed class CameraControlState {
data object Hidden : CameraControlState()

data class ShowRecenter(val updateCamera: () -> Unit) : CameraControlState()

data class ShowRouteOverview(val updateCamera: () -> Unit) : CameraControlState()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.stadiamaps.ferrostar.composeui.models

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp

data class NavigationViewMetrics(
val progressViewSize: DpSize = DpSize(0.dp, 0.dp),
val instructionsViewSize: DpSize = DpSize(0.dp, 0.dp),
val buttonSize: DpSize,
) {

/**
* Returns the MapView's safe insets.
*
* @param start Optional additional start padding. Default is 0.dp.
* @param top Optional additional top padding. Default is instructionsViewSize.height.
* @param end Optional additional end padding. Default is 0.dp.
* @param bottom Optional additional bottom padding. Default is progressViewSize.height.
* @return The calculated padding insets.
*/
fun mapViewInsets(
start: Dp = 0.dp,
top: Dp = 0.dp,
end: Dp = 0.dp,
bottom: Dp = 0.dp,
): PaddingValues {
return PaddingValues(
start = start,
top = instructionsViewSize.height + top,
end = end,
bottom = progressViewSize.height + buttonSize.height + bottom,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import com.stadiamaps.ferrostar.composeui.formatting.DurationFormatter
import com.stadiamaps.ferrostar.composeui.formatting.EstimatedArrivalDateTimeFormatter
import com.stadiamaps.ferrostar.composeui.formatting.LocalizedDistanceFormatter
import com.stadiamaps.ferrostar.composeui.formatting.LocalizedDurationFormatter
import com.stadiamaps.ferrostar.composeui.views.maneuver.maneuverIcon
import com.stadiamaps.ferrostar.composeui.views.components.maneuver.maneuverIcon
import com.stadiamaps.ferrostar.core.extensions.estimatedArrivalTime
import com.stadiamaps.ferrostar.core.service.ForegroundNotificationBuilder
import uniffi.ferrostar.TripProgress
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ object DefaultInstructionRowTheme : InstructionRowTheme {
@Composable get() = MaterialTheme.colorScheme.onSurface

override val backgroundColor: Color
@Composable get() = MaterialTheme.colorScheme.surfaceContainerLow
@Composable get() = MaterialTheme.colorScheme.surface
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.stadiamaps.ferrostar.composeui.theme

import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp

interface NavigationUITheme {
@get:Composable val instructionRowTheme: InstructionRowTheme
@get:Composable val roadNameViewTheme: RoadNameViewTheme
@get:Composable val tripProgressViewTheme: TripProgressViewTheme
@get:Composable val buttonSize: DpSize
}

object DefaultNavigationUITheme : NavigationUITheme {
override val instructionRowTheme: InstructionRowTheme
@Composable get() = DefaultInstructionRowTheme

override val roadNameViewTheme: RoadNameViewTheme
@Composable get() = DefaultRoadNameViewTheme

override val tripProgressViewTheme: TripProgressViewTheme
@Composable get() = DefaultTripProgressViewTheme

override val buttonSize: DpSize
@Composable get() = DpSize(56.dp, 56.dp)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.stadiamaps.ferrostar.composeui.views
package com.stadiamaps.ferrostar.composeui.views.components

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.stadiamaps.ferrostar.composeui.views
package com.stadiamaps.ferrostar.composeui.views.components

import android.icu.util.ULocale
import androidx.compose.animation.animateContentSize
Expand All @@ -20,7 +20,6 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -36,9 +35,9 @@ import com.stadiamaps.ferrostar.composeui.formatting.DistanceFormatter
import com.stadiamaps.ferrostar.composeui.formatting.LocalizedDistanceFormatter
import com.stadiamaps.ferrostar.composeui.theme.DefaultInstructionRowTheme
import com.stadiamaps.ferrostar.composeui.theme.InstructionRowTheme
import com.stadiamaps.ferrostar.composeui.views.controls.PillDragHandle
import com.stadiamaps.ferrostar.composeui.views.maneuver.ManeuverImage
import com.stadiamaps.ferrostar.composeui.views.maneuver.ManeuverInstructionView
import com.stadiamaps.ferrostar.composeui.views.components.controls.PillDragHandle
import com.stadiamaps.ferrostar.composeui.views.components.maneuver.ManeuverImage
import com.stadiamaps.ferrostar.composeui.views.components.maneuver.ManeuverInstructionView
import uniffi.ferrostar.ManeuverModifier
import uniffi.ferrostar.ManeuverType
import uniffi.ferrostar.RouteStep
Expand All @@ -62,11 +61,12 @@ fun InstructionsView(
remainingSteps: List<RouteStep>? = null,
initExpanded: Boolean = false,
contentBuilder: @Composable (VisualInstruction) -> Unit = {
ManeuverImage(it.primaryContent, tint = MaterialTheme.colorScheme.primary)
ManeuverImage(it.primaryContent, tint = theme.iconTintColor)
}
) {
var isExpanded by remember { mutableStateOf(initExpanded) }
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
val remainingSteps: List<RouteStep> = remainingSteps?.drop(1) ?: emptyList()

Box(
modifier =
Expand All @@ -89,7 +89,7 @@ fun InstructionsView(
// TODO: Secondary content

// Expanded content
val showMultipleRows = isExpanded && remainingSteps != null && remainingSteps.count() > 1
val showMultipleRows = isExpanded && remainingSteps.count() > 1
if (showMultipleRows) {
Spacer(modifier = Modifier.height(8.dp))
HorizontalDivider(thickness = 1.dp)
Expand All @@ -101,19 +101,17 @@ fun InstructionsView(
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(8.dp)) {
if (remainingSteps != null) {
items(remainingSteps.drop(1)) { step ->
step.visualInstructions.firstOrNull()?.let { upcomingInstruction ->
ManeuverInstructionView(
text = upcomingInstruction.primaryContent.text,
distanceFormatter = distanceFormatter,
distanceToNextManeuver = step.distance,
theme = theme) {
contentBuilder(upcomingInstruction)
}
Spacer(modifier = Modifier.height(8.dp))
HorizontalDivider(thickness = 1.dp)
}
items(remainingSteps) { step ->
step.visualInstructions.firstOrNull()?.let { upcomingInstruction ->
ManeuverInstructionView(
text = upcomingInstruction.primaryContent.text,
distanceFormatter = distanceFormatter,
distanceToNextManeuver = step.distance,
theme = theme) {
contentBuilder(upcomingInstruction)
}
Spacer(modifier = Modifier.height(8.dp))
HorizontalDivider(thickness = 1.dp)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.stadiamaps.ferrostar.composeui.views
package com.stadiamaps.ferrostar.composeui.views.components

import android.icu.util.ULocale
import androidx.compose.foundation.background
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.stadiamaps.ferrostar.composeui.views.controls
package com.stadiamaps.ferrostar.composeui.views.components.controls

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.stadiamaps.ferrostar.composeui.views.controls
package com.stadiamaps.ferrostar.composeui.views.components.controls

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.stadiamaps.ferrostar.composeui.views.controls
package com.stadiamaps.ferrostar.composeui.views.components.controls

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
Expand Down Expand Up @@ -30,7 +30,7 @@ fun PillDragHandle(
toggle: () -> Unit = {}
) {
val handleHeight = if (isExpanded) 36.dp else 4.dp
Box(modifier = modifier.height(handleHeight).clickable(onClick = toggle)) {
Box(modifier = modifier.fillMaxWidth().height(handleHeight).clickable(onClick = toggle)) {
if (isExpanded) {
Icon(
Icons.Rounded.KeyboardArrowUp,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.stadiamaps.ferrostar.composeui.views.gridviews
package com.stadiamaps.ferrostar.composeui.views.components.gridviews

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
Expand Down
Loading
Loading