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

Upgrades to improved MapLibre Compose #156

Merged
merged 9 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion android/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ androidx-activity-compose = "1.9.0"
compose = "2024.06.00"
okhttp = "4.12.0"
moshi = "1.15.1"
maplibre-compose = "0.0.9"
maplibre-compose = "0.0.13"
junit = "4.13.2"
junitVersion = "1.2.1"
junitCompose = "1.6.8"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.maps.Style
import com.maplibre.compose.MapView
import com.maplibre.compose.StaticLocationEngine
import com.maplibre.compose.camera.MapViewCamera
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.NavigationCentered
import com.stadiamaps.ferrostar.maplibreui.extensions.NavigationDefault

/**
Expand All @@ -27,15 +30,19 @@ import com.stadiamaps.ferrostar.maplibreui.extensions.NavigationDefault
* @param viewModel The navigation view model provided by Ferrostar Core.
* @param locationRequestProperties The location request properties to use for the map's location
* engine.
* @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!
* @param content Any additional composable map symbol content to render.
*/
@Composable
fun NavigationMapView(
styleUrl: String,
mapControls: MapControls,
camera: MutableState<MapViewCamera>,
viewModel: NavigationViewModel,
locationRequestProperties: LocationRequestProperties =
LocationRequestProperties.NavigationDefault(),
onMapReadyCallback: (Style) -> Unit = { camera.value = MapViewCamera.NavigationCentered() },
content: @Composable @MapLibreComposable() ((State<NavigationUiState>) -> Unit)? = null
) {
val uiState = viewModel.uiState.collectAsState()
Expand All @@ -46,16 +53,11 @@ fun NavigationMapView(
MapView(
modifier = Modifier.fillMaxSize(),
styleUrl = styleUrl,
mapControls = mapControls,
camera = camera,
locationRequestProperties = locationRequestProperties,
locationEngine = locationEngine,
onMapReadyCallback = {
// Set the camera to navigation on resume.
camera.value = MapViewCamera.NavigationDefault()

// Any additional map view related setup should happen here to ensure the map is ready
// (style is loaded).
},
onMapReadyCallback = onMapReadyCallback,
) {
BorderedPolyline(
points = uiState.value.routeGeometry.map { LatLng(it.lat, it.lng) }, zIndex = 0)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.stadiamaps.ferrostar.maplibreui.extensions

import com.maplibre.compose.camera.CameraPitch
import com.maplibre.compose.camera.MapViewCamera

/**
* The default camera configuration for navigation. This configuration sets the camera to track the
* The centered camera configuration for navigation. This configuration sets the camera to track the
* user, with a bearing of 18 degrees and a pitch of 45 degrees.
*
* @return The navigation MapViewCamera
*/
fun MapViewCamera.Companion.NavigationDefault(): MapViewCamera {
// FIXME: Pitch is not being propagated
return MapViewCamera.TrackingUserLocationWithBearing(18.0, CameraPitch.Fixed(45.0))
fun MapViewCamera.Companion.NavigationCentered(): MapViewCamera {
return MapViewCamera.TrackingUserLocationWithBearing(zoom = 18.0, pitch = 45.0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.stadiamaps.ferrostar.maplibreui.runtime

import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalConfiguration
import com.maplibre.compose.camera.MapViewCamera
import com.maplibre.compose.camera.cameraPaddingFractionOfScreen

/**
* The camera configuration for navigation. This configuration sets the camera to track the user,
* with a bearing of 18 degrees and a pitch of 45 degrees. It automatically adjusts the padding
* based on the screen size and orientation.
*
* @param zoom The zoom level of the camera.
* @param pitch The pitch of the camera.
* @return The recommended navigation MapViewCamera
*/
@Composable
fun navigationMapViewCamera(zoom: Double = 18.0, pitch: Double = 45.0): MapViewCamera {
val screenOrientation = LocalConfiguration.current.orientation
val start = if (screenOrientation == Configuration.ORIENTATION_LANDSCAPE) 0.5f else 0.0f

val cameraPadding = cameraPaddingFractionOfScreen(start = start, top = 0.7f)

return MapViewCamera.TrackingUserLocationWithBearing(
zoom = zoom, pitch = pitch, padding = cameraPadding)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.maplibre.compose.rememberSaveableMapViewCamera
import com.stadiamaps.ferrostar.core.NavigationUiState
import com.stadiamaps.ferrostar.core.NavigationViewModel
import com.stadiamaps.ferrostar.maplibreui.extensions.NavigationDefault
import com.stadiamaps.ferrostar.maplibreui.runtime.navigationMapViewCamera

/**
* A dynamically orienting navigation view that switches between portrait and landscape orientations
Expand All @@ -35,6 +36,7 @@ fun DynamicallyOrientingNavigationView(
orientation: Int = LocalConfiguration.current.orientation,
styleUrl: String,
camera: MutableState<MapViewCamera> = rememberSaveableMapViewCamera(),
navigationCamera: MapViewCamera = navigationMapViewCamera(),
viewModel: NavigationViewModel,
locationRequestProperties: LocationRequestProperties =
LocationRequestProperties.NavigationDefault(),
Expand All @@ -44,11 +46,25 @@ fun DynamicallyOrientingNavigationView(
when (orientation) {
Configuration.ORIENTATION_LANDSCAPE -> {
LandscapeNavigationView(
modifier, styleUrl, camera, viewModel, locationRequestProperties, onTapExit, content)
modifier,
styleUrl,
camera,
navigationCamera,
viewModel,
locationRequestProperties,
onTapExit,
content)
}
else -> {
PortraitNavigationView(
modifier, styleUrl, camera, viewModel, locationRequestProperties, onTapExit, content)
modifier,
styleUrl,
camera,
navigationCamera,
viewModel,
locationRequestProperties,
onTapExit,
content)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.stadiamaps.ferrostar.maplibreui.views

import android.view.Gravity
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
Expand All @@ -18,10 +19,15 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.maplibre.compose.camera.CameraState
import com.maplibre.compose.camera.MapViewCamera
import com.maplibre.compose.camera.incrementZoom
import com.maplibre.compose.camera.extensions.incrementZoom
import com.maplibre.compose.ramani.LocationRequestProperties
import com.maplibre.compose.ramani.MapLibreComposable
import com.maplibre.compose.rememberSaveableMapViewCamera
import com.maplibre.compose.settings.AttributionSettings
import com.maplibre.compose.settings.CompassSettings
import com.maplibre.compose.settings.LogoSettings
import com.maplibre.compose.settings.MapControls
import com.maplibre.compose.settings.MarginInsets
import com.stadiamaps.ferrostar.composeui.views.ArrivalView
import com.stadiamaps.ferrostar.composeui.views.InstructionsView
import com.stadiamaps.ferrostar.composeui.views.gridviews.NavigatingInnerGridView
Expand All @@ -31,6 +37,7 @@ import com.stadiamaps.ferrostar.core.NavigationViewModel
import com.stadiamaps.ferrostar.core.mock.pedestrianExample
import com.stadiamaps.ferrostar.maplibreui.NavigationMapView
import com.stadiamaps.ferrostar.maplibreui.extensions.NavigationDefault
import com.stadiamaps.ferrostar.maplibreui.runtime.navigationMapViewCamera
import kotlinx.coroutines.flow.MutableStateFlow
import uniffi.ferrostar.UserLocation

Expand All @@ -48,6 +55,7 @@ fun LandscapeNavigationView(
modifier: Modifier,
styleUrl: String,
camera: MutableState<MapViewCamera> = rememberSaveableMapViewCamera(),
navigationCamera: MapViewCamera = navigationMapViewCamera(),
viewModel: NavigationViewModel,
locationRequestProperties: LocationRequestProperties =
LocationRequestProperties.NavigationDefault(),
Expand All @@ -57,7 +65,23 @@ fun LandscapeNavigationView(
val uiState = viewModel.uiState.collectAsState()

Box(modifier) {
NavigationMapView(styleUrl, camera, viewModel, locationRequestProperties, content)
NavigationMapView(
styleUrl,
MapControls(
attribution =
AttributionSettings(
gravity = Gravity.BOTTOM or Gravity.END,
margins = MarginInsets(end = 270, bottom = 32)),
compass = CompassSettings(enabled = false),
logo =
LogoSettings(
gravity = Gravity.BOTTOM or Gravity.END,
margins = MarginInsets(end = 32, bottom = 32))),
camera,
viewModel,
locationRequestProperties,
onMapReadyCallback = { camera.value = navigationCamera },
content)

Row(modifier = Modifier.fillMaxSize().padding(16.dp)) {
Column(modifier = Modifier.fillMaxHeight().fillMaxWidth(0.5f)) {
Expand All @@ -80,8 +104,8 @@ fun LandscapeNavigationView(
modifier = Modifier.fillMaxSize(),
onClickZoomIn = { camera.value = camera.value.incrementZoom(1.0) },
onClickZoomOut = { camera.value = camera.value.incrementZoom(-1.0) },
showCentering = camera.value.state != CameraState.TrackingUserLocationWithBearing,
onClickCenter = { camera.value = MapViewCamera.NavigationDefault() })
showCentering = camera.value.state !is CameraState.TrackingUserLocationWithBearing,
onClickCenter = { camera.value = navigationCamera })
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.stadiamaps.ferrostar.maplibreui.views

import android.view.Gravity
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
Expand All @@ -14,10 +15,15 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.maplibre.compose.camera.CameraState
import com.maplibre.compose.camera.MapViewCamera
import com.maplibre.compose.camera.incrementZoom
import com.maplibre.compose.camera.extensions.incrementZoom
import com.maplibre.compose.ramani.LocationRequestProperties
import com.maplibre.compose.ramani.MapLibreComposable
import com.maplibre.compose.rememberSaveableMapViewCamera
import com.maplibre.compose.settings.AttributionSettings
import com.maplibre.compose.settings.CompassSettings
import com.maplibre.compose.settings.LogoSettings
import com.maplibre.compose.settings.MapControls
import com.maplibre.compose.settings.MarginInsets
import com.stadiamaps.ferrostar.composeui.views.ArrivalView
import com.stadiamaps.ferrostar.composeui.views.InstructionsView
import com.stadiamaps.ferrostar.composeui.views.gridviews.NavigatingInnerGridView
Expand All @@ -27,6 +33,7 @@ import com.stadiamaps.ferrostar.core.NavigationViewModel
import com.stadiamaps.ferrostar.core.mock.pedestrianExample
import com.stadiamaps.ferrostar.maplibreui.NavigationMapView
import com.stadiamaps.ferrostar.maplibreui.extensions.NavigationDefault
import com.stadiamaps.ferrostar.maplibreui.runtime.navigationMapViewCamera
import kotlinx.coroutines.flow.MutableStateFlow
import uniffi.ferrostar.UserLocation

Expand All @@ -44,6 +51,7 @@ fun PortraitNavigationView(
modifier: Modifier,
styleUrl: String,
camera: MutableState<MapViewCamera> = rememberSaveableMapViewCamera(),
navigationCamera: MapViewCamera = navigationMapViewCamera(),
viewModel: NavigationViewModel,
locationRequestProperties: LocationRequestProperties =
LocationRequestProperties.NavigationDefault(),
Expand All @@ -53,7 +61,23 @@ fun PortraitNavigationView(
val uiState = viewModel.uiState.collectAsState()

Box(modifier) {
NavigationMapView(styleUrl, camera, viewModel, locationRequestProperties, content)
NavigationMapView(
styleUrl,
MapControls(
attribution =
AttributionSettings(
gravity = Gravity.BOTTOM or Gravity.END,
margins = MarginInsets(end = 270, bottom = 200)),
compass = CompassSettings(enabled = false),
logo =
LogoSettings(
gravity = Gravity.BOTTOM or Gravity.END,
margins = MarginInsets(end = 32, bottom = 200))),
camera,
viewModel,
locationRequestProperties,
onMapReadyCallback = { camera.value = navigationCamera },
content)

Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
uiState.value.visualInstruction?.let { instructions ->
Expand All @@ -65,8 +89,8 @@ fun PortraitNavigationView(
modifier = Modifier.fillMaxSize().weight(1f).padding(bottom = 16.dp),
onClickZoomIn = { camera.value = camera.value.incrementZoom(1.0) },
onClickZoomOut = { camera.value = camera.value.incrementZoom(-1.0) },
showCentering = camera.value.state != CameraState.TrackingUserLocationWithBearing,
onClickCenter = { camera.value = MapViewCamera.NavigationDefault() })
showCentering = camera.value.state !is CameraState.TrackingUserLocationWithBearing,
onClickCenter = { camera.value = navigationCamera })

uiState.value.progress?.let { progress ->
ArrivalView(progress = progress, onTapExit = onTapExit)
Expand Down
Loading