Skip to content

Commit d1fa445

Browse files
authored
Android: Use dynamic screen-based padding again for navigation camera (#885)
* Use dynamic screen-based padding again for navigation camera (follow up to maplibre-compose migration #853) * Adjust navigation camera padding to account for bottom UI insets
1 parent d8d6e14 commit d1fa445

4 files changed

Lines changed: 97 additions & 7 deletions

File tree

android/ui-maplibre/src/main/java/com/stadiamaps/ferrostar/maplibreui/runtime/NavigationCamera.kt

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ package com.stadiamaps.ferrostar.maplibreui.runtime
22

33
import android.content.res.Configuration
44
import androidx.compose.foundation.layout.PaddingValues
5+
import androidx.compose.foundation.layout.calculateEndPadding
6+
import androidx.compose.foundation.layout.calculateStartPadding
57
import androidx.compose.runtime.Composable
68
import androidx.compose.ui.platform.LocalConfiguration
9+
import androidx.compose.ui.unit.Dp
10+
import androidx.compose.ui.unit.LayoutDirection
711
import androidx.compose.ui.unit.dp
812
import com.stadiamaps.ferrostar.core.BoundingBox
913
import org.maplibre.compose.camera.CameraPosition
@@ -64,18 +68,62 @@ data class NavigationCameraOptions(
6468
fun navigationCameraOptions(
6569
activity: NavigationActivity = NavigationActivity.Automotive,
6670
): NavigationCameraOptions {
67-
val screenOrientation = LocalConfiguration.current.orientation
68-
val start = if (screenOrientation == Configuration.ORIENTATION_LANDSCAPE) 180.dp else 0.dp
71+
val configuration = LocalConfiguration.current
6972

7073
return NavigationCameraOptions(
7174
browsingZoom = activity.zoom,
7275
navigationZoom = activity.zoom,
7376
navigationTilt = activity.tilt,
7477
browsingPadding = PaddingValues(0.dp),
75-
navigationPadding = PaddingValues(start = start, top = 240.dp),
78+
navigationPadding =
79+
navigationPaddingForScreen(
80+
orientation = configuration.orientation,
81+
screenWidthDp = configuration.screenWidthDp,
82+
screenHeightDp = configuration.screenHeightDp,
83+
),
7684
)
7785
}
7886

87+
internal fun navigationPaddingForScreen(
88+
orientation: Int,
89+
screenWidthDp: Int,
90+
screenHeightDp: Int,
91+
): PaddingValues =
92+
PaddingValues(
93+
start =
94+
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
95+
(screenWidthDp * 0.5f).dp
96+
} else {
97+
0.dp
98+
},
99+
top = (screenHeightDp * 0.5f).dp,
100+
)
101+
102+
internal fun NavigationCameraOptions.withNavigationBottomInset(
103+
bottomInset: Dp,
104+
screenHeight: Dp,
105+
layoutDirection: LayoutDirection,
106+
clearance: Dp = 24.dp,
107+
): NavigationCameraOptions =
108+
navigationPadding.calculateBottomPadding().let { baseBottomPadding ->
109+
val topPadding = navigationPadding.calculateTopPadding()
110+
val currentTargetY = (screenHeight + topPadding - baseBottomPadding) / 2
111+
val lowestVisibleTargetY = screenHeight - bottomInset - clearance
112+
// MapLibre centers the target in the padded viewport. Moving the bottom edge up by X only
113+
// moves the center by X / 2, so double the needed target shift when converting it to padding.
114+
val extraBottomPadding = maxOf(0.dp, (currentTargetY - lowestVisibleTargetY) * 2)
115+
116+
copy(
117+
navigationPadding =
118+
PaddingValues(
119+
start = navigationPadding.calculateStartPadding(layoutDirection),
120+
top = topPadding,
121+
end = navigationPadding.calculateEndPadding(layoutDirection),
122+
bottom = baseBottomPadding + extraBottomPadding,
123+
)
124+
)
125+
}
126+
79127
fun defaultNavigationCameraMode(isNavigating: Boolean): NavigationCameraMode =
80128
if (isNavigating) {
81129
NavigationCameraMode.FOLLOW_USER_WITH_BEARING

android/ui-maplibre/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/DynamicallyOrientingNavigationView.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import androidx.compose.runtime.remember
1616
import androidx.compose.runtime.setValue
1717
import androidx.compose.ui.Modifier
1818
import androidx.compose.ui.platform.LocalConfiguration
19+
import androidx.compose.ui.platform.LocalLayoutDirection
1920
import androidx.compose.ui.unit.dp
2021
import com.stadiamaps.ferrostar.composeui.config.NavigationViewComponentBuilder
2122
import com.stadiamaps.ferrostar.composeui.config.VisualNavigationViewConfig
@@ -38,6 +39,7 @@ import com.stadiamaps.ferrostar.maplibreui.runtime.NavigationMapState
3839
import com.stadiamaps.ferrostar.maplibreui.runtime.navigationCameraOptions
3940
import com.stadiamaps.ferrostar.maplibreui.runtime.rememberMapOptionsForProgressViewHeight
4041
import com.stadiamaps.ferrostar.maplibreui.runtime.rememberNavigationMapState
42+
import com.stadiamaps.ferrostar.maplibreui.runtime.withNavigationBottomInset
4143
import org.maplibre.compose.style.BaseStyle
4244
import org.maplibre.compose.util.MaplibreComposable
4345

@@ -72,7 +74,9 @@ fun DynamicallyOrientingNavigationView(
7274
onMapLongClick: NavigationMapClickHandler = { _, _ -> NavigationMapClickResult.Pass },
7375
mapContent: @Composable @MaplibreComposable ((NavigationUiState) -> Unit)? = null,
7476
) {
75-
val orientation = LocalConfiguration.current.orientation
77+
val configuration = LocalConfiguration.current
78+
val orientation = configuration.orientation
79+
val layoutDirection = LocalLayoutDirection.current
7680

7781
var progressViewHeight by remember { mutableStateOf(0.dp) }
7882
val uiState by viewModel.navigationUiState.collectAsState()
@@ -86,14 +90,24 @@ fun DynamicallyOrientingNavigationView(
8690
progressViewHeight = if (uiState.isNavigating()) progressViewHeight else 0.dp,
8791
contentPadding = resolvedOrnamentPadding,
8892
)
93+
val effectiveNavigationCameraOptions =
94+
if (uiState.isNavigating()) {
95+
navigationCameraOptions.withNavigationBottomInset(
96+
bottomInset = mapViewInsets.value.calculateBottomPadding(),
97+
screenHeight = configuration.screenHeightDp.dp,
98+
layoutDirection = layoutDirection,
99+
)
100+
} else {
101+
navigationCameraOptions
102+
}
89103

90104
Box(modifier) {
91105
NavigationMapView(
92106
baseStyle = baseStyle,
93107
navigationMapState = navigationMapState,
94108
uiState = uiState,
95109
mapOptions = mapOptions,
96-
navigationCameraOptions = navigationCameraOptions,
110+
navigationCameraOptions = effectiveNavigationCameraOptions,
97111
routeOverlayBuilder = routeOverlayBuilder,
98112
locationPuckStyle = locationPuckStyle,
99113
showDefaultPuck = showDefaultPuck,

android/ui-maplibre/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/LandscapeNavigationView.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import androidx.compose.runtime.getValue
1414
import androidx.compose.runtime.mutableStateOf
1515
import androidx.compose.runtime.remember
1616
import androidx.compose.ui.Modifier
17+
import androidx.compose.ui.platform.LocalLayoutDirection
1718
import androidx.compose.ui.tooling.preview.Preview
1819
import androidx.compose.ui.unit.dp
1920
import com.stadiamaps.ferrostar.composeui.config.NavigationViewComponentBuilder
@@ -38,6 +39,7 @@ import com.stadiamaps.ferrostar.maplibreui.runtime.NavigationMapState
3839
import com.stadiamaps.ferrostar.maplibreui.runtime.navigationCameraOptions
3940
import com.stadiamaps.ferrostar.maplibreui.runtime.rememberMapOptionsForProgressViewHeight
4041
import com.stadiamaps.ferrostar.maplibreui.runtime.rememberNavigationMapState
42+
import com.stadiamaps.ferrostar.maplibreui.runtime.withNavigationBottomInset
4143
import kotlinx.coroutines.flow.MutableStateFlow
4244
import kotlinx.coroutines.flow.asStateFlow
4345
import org.maplibre.compose.style.BaseStyle
@@ -63,16 +65,28 @@ fun LandscapeNavigationView(
6365
mapContent: @Composable @MaplibreComposable ((NavigationUiState) -> Unit)? = null,
6466
) {
6567
val uiState by viewModel.navigationUiState.collectAsState()
68+
val configuration = androidx.compose.ui.platform.LocalConfiguration.current
69+
val layoutDirection = LocalLayoutDirection.current
6670
val gridPadding = paddingForGridView()
6771
val mapOptions = rememberMapOptionsForProgressViewHeight()
72+
val effectiveNavigationCameraOptions =
73+
if (uiState.isNavigating()) {
74+
navigationCameraOptions.withNavigationBottomInset(
75+
bottomInset = mapViewInsets.value.calculateBottomPadding(),
76+
screenHeight = configuration.screenHeightDp.dp,
77+
layoutDirection = layoutDirection,
78+
)
79+
} else {
80+
navigationCameraOptions
81+
}
6882

6983
Box(modifier) {
7084
NavigationMapView(
7185
baseStyle = baseStyle,
7286
navigationMapState = navigationMapState,
7387
uiState = uiState,
7488
mapOptions = mapOptions,
75-
navigationCameraOptions = navigationCameraOptions,
89+
navigationCameraOptions = effectiveNavigationCameraOptions,
7690
routeOverlayBuilder = routeOverlayBuilder,
7791
showDefaultPuck = showDefaultPuck,
7892
locationPuckStyle = locationPuckStyle,

android/ui-maplibre/src/main/java/com/stadiamaps/ferrostar/maplibreui/views/PortraitNavigationView.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import androidx.compose.runtime.getValue
1414
import androidx.compose.runtime.mutableStateOf
1515
import androidx.compose.runtime.remember
1616
import androidx.compose.ui.Modifier
17+
import androidx.compose.ui.platform.LocalLayoutDirection
1718
import androidx.compose.ui.tooling.preview.Devices
1819
import androidx.compose.ui.tooling.preview.Preview
1920
import androidx.compose.ui.unit.dp
@@ -37,6 +38,7 @@ import com.stadiamaps.ferrostar.maplibreui.runtime.NavigationMapState
3738
import com.stadiamaps.ferrostar.maplibreui.runtime.navigationCameraOptions
3839
import com.stadiamaps.ferrostar.maplibreui.runtime.rememberMapOptionsForProgressViewHeight
3940
import com.stadiamaps.ferrostar.maplibreui.runtime.rememberNavigationMapState
41+
import com.stadiamaps.ferrostar.maplibreui.runtime.withNavigationBottomInset
4042
import org.maplibre.compose.style.BaseStyle
4143
import org.maplibre.compose.util.MaplibreComposable
4244

@@ -85,16 +87,28 @@ fun PortraitNavigationView(
8587
mapContent: @Composable @MaplibreComposable ((NavigationUiState) -> Unit)? = null,
8688
) {
8789
val uiState by viewModel.navigationUiState.collectAsState()
90+
val configuration = androidx.compose.ui.platform.LocalConfiguration.current
91+
val layoutDirection = LocalLayoutDirection.current
8892
val gridPadding = paddingForGridView()
8993
val mapOptions = rememberMapOptionsForProgressViewHeight()
94+
val effectiveNavigationCameraOptions =
95+
if (uiState.isNavigating()) {
96+
navigationCameraOptions.withNavigationBottomInset(
97+
bottomInset = mapViewInsets.value.calculateBottomPadding(),
98+
screenHeight = configuration.screenHeightDp.dp,
99+
layoutDirection = layoutDirection,
100+
)
101+
} else {
102+
navigationCameraOptions
103+
}
90104

91105
Box(modifier) {
92106
NavigationMapView(
93107
baseStyle = baseStyle,
94108
navigationMapState = navigationMapState,
95109
uiState = uiState,
96110
mapOptions = mapOptions,
97-
navigationCameraOptions = navigationCameraOptions,
111+
navigationCameraOptions = effectiveNavigationCameraOptions,
98112
routeOverlayBuilder = routeOverlayBuilder,
99113
locationPuckStyle = locationPuckStyle,
100114
showDefaultPuck = showDefaultPuck,

0 commit comments

Comments
 (0)