diff --git a/app/src/main/java/com/kouros/navigation/MainActivity.kt b/app/src/main/java/com/kouros/navigation/MainActivity.kt index ba09ff0..f69ebda 100644 --- a/app/src/main/java/com/kouros/navigation/MainActivity.kt +++ b/app/src/main/java/com/kouros/navigation/MainActivity.kt @@ -18,7 +18,6 @@ package com.kouros.navigation import android.Manifest import android.annotation.SuppressLint -import android.content.pm.PackageManager import android.location.Location import android.location.LocationManager import android.os.Bundle @@ -34,23 +33,37 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.ExtendedFloatingActionButton +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalDrawerSheet +import androidx.compose.material3.ModalNavigationDrawer +import androidx.compose.material3.NavigationDrawerItem import androidx.compose.material3.Scaffold +import androidx.compose.material3.SegmentedButtonDefaults.Icon +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.core.location.LocationListenerCompat +import androidx.compose.ui.unit.sp import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Observer import com.example.places.ui.theme.PlacesTheme @@ -59,10 +72,12 @@ import com.google.accompanist.permissions.rememberMultiplePermissionsState import com.kouros.navigation.data.Category import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants.TAG -import com.kouros.navigation.data.Constants.homeLocation import com.kouros.navigation.data.NavigationRepository +import com.kouros.navigation.data.StepData import com.kouros.navigation.model.RouteModel import com.kouros.navigation.model.ViewModel +import com.kouros.navigation.utils.NavigationUtils +import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.rememberCameraState @@ -85,18 +100,24 @@ import org.maplibre.spatialk.geojson.Position import kotlin.time.Duration.Companion.seconds -val geojson = MutableLiveData("") +val routeData = MutableLiveData("") class MainActivity : ComponentActivity() { val vieModel = ViewModel(NavigationRepository()) val routeModel = RouteModel() + var tilt = 0.0 + + val curLocation = Location(LocationManager.GPS_PROVIDER) + + val instruction: MutableLiveData by lazy { + MutableLiveData() + } + val observer = Observer { newRoute -> - routeModel.createNavigationRoute(newRoute) - geojson.value = routeModel.geoJson - homeLocation.latitude = 48.155782 - homeLocation.longitude = 11.607921 + routeModel.startNavigation(newRoute) + routeData.value = routeModel.route } val cameraPosition = MutableLiveData( @@ -108,38 +129,19 @@ class MainActivity : ComponentActivity() { init { vieModel.route.observe(this, observer) - vieModel.loadRoute( - homeLocation, - Constants.home2Location - ) } - var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? -> - updateLocation(location) - } - - - @SuppressLint("MissingPermission") - fun requestLocationUpdates() { - val locationManager = - getSystemService(LOCATION_SERVICE) as LocationManager - val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) - updateLocation(location) - locationManager.requestLocationUpdates( - LocationManager.GPS_PROVIDER, - /* minTimeMs= */ 100, - /* minDistanceM= */ 0f, - mLocationListener - ) - } - - fun updateLocation(location: Location?) { + fun updateLocation(location: org.maplibre.compose.location.Location?) { if (location != null) { + if (routeModel.isNavigating()) { + instruction.value = routeModel.currentStep() + } + val zoom = NavigationUtils().calculateZoom(location.speed) cameraPosition.postValue( cameraPosition.value!!.copy( - zoom = 15.0, - target = Position(location.longitude, location.latitude), - ) + zoom = zoom, + target = location.position + ), ) } } @@ -164,23 +166,64 @@ class MainActivity : ComponentActivity() { enableEdgeToEdge() setContent { + val scope = rememberCoroutineScope() + val snackbarHostState = remember { SnackbarHostState() } + PlacesTheme { - Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> - Column(modifier = Modifier.padding(innerPadding)) { - CheckPermission() + ModalNavigationDrawer( + drawerContent = { + ModalDrawerSheet { + Text("Drawer title", modifier = Modifier.padding(16.dp)) + HorizontalDivider() + NavigationDrawerItem( + label = { Text(text = "Drawer Item") }, + selected = false, + onClick = { /*TODO*/ } + ) + } + }, + gesturesEnabled = false + ) { + Scaffold( + modifier = Modifier.fillMaxSize(), + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + floatingActionButton = { + ExtendedFloatingActionButton( + text = { + Text("Navigate") + }, + icon = { Icon(true) }, + onClick = { + scope.launch { + snackbarHostState.showSnackbar("Starte Navigation") + } + if (!routeModel.isNavigating()) { + tilt = 60.0 + vieModel.loadRoute( + curLocation, + Constants.home2Location + ) + } else { + tilt = 0.0 + routeModel.stopNavigation() + routeData.value = "" + } + + } + ) + } + ) { innerPadding -> + Column(modifier = Modifier.padding(innerPadding)) { + CheckPermission() + } } } } } } - override fun onPause() { - super.onPause() - val locationManager = - getSystemService(LOCATION_SERVICE) as LocationManager - locationManager.removeUpdates(mLocationListener) - } - @SuppressLint("PermissionLaunchedDuringComposition") @OptIn(ExperimentalPermissionsApi::class) @Composable @@ -224,11 +267,40 @@ class MainActivity : ComponentActivity() { } } + @Composable + fun NavigationInfo(step: StepData?) { + Card { + Column { + Icon( + painter = painterResource(com.kouros.android.cars.carappservice.R.drawable.ic_turn_normal_right), + contentDescription = stringResource(id = com.kouros.android.cars.carappservice.R.string.accept_action_title) + ) + if (step != null) { + Text(text = step.bearing.toString(), fontSize = 25.sp) + Text(text = step.instruction, fontSize = 25.sp) + } + } + } + } + @Composable fun Map() { - requestLocationUpdates() + val step: StepData? by instruction.observeAsState() + Column { + if (step != null) { + NavigationInfo(step) + } + MapView() + } + } + + @Composable + fun MapView() { + val locationProvider = rememberDefaultLocationProvider() + val locationState = rememberUserLocationState(locationProvider) + updateLocation(locationState.location) val position: CameraPosition? by cameraPosition.observeAsState() - val geoJsonData: String? by geojson.observeAsState() + val route: String? by routeData.observeAsState() val cameraState = rememberCameraState( firstPosition = @@ -241,9 +313,10 @@ class MainActivity : ComponentActivity() { ) ) - val locationProvider = rememberDefaultLocationProvider() - val locationState = rememberUserLocationState(locationProvider) - + if (locationState.location != null) { + curLocation.latitude = locationState.location?.position!!.latitude + curLocation.longitude = locationState.location?.position!!.longitude + } MaplibreMap( cameraState = cameraState, //baseStyle = BaseStyle.Uri("https://tiles.openfreemap.org/styles/liberty"), @@ -270,7 +343,7 @@ class MainActivity : ComponentActivity() { ) getBaseSource(id = "openmaptiles")?.let { tiles -> FillLayer(id = "example", visible = false, source = tiles, sourceLayer = "building") - RouteLayer(geoJsonData) + RouteLayer(route) } } @@ -280,6 +353,7 @@ class MainActivity : ComponentActivity() { bearing = position!!.bearing, zoom = position!!.zoom, target = position!!.target, + tilt = tilt ), duration = 3.seconds ) @@ -287,21 +361,23 @@ class MainActivity : ComponentActivity() { } @Composable - fun RouteLayer(geoJsonData: String?) { - val routes = - rememberGeoJsonSource(GeoJsonData.JsonString(geoJsonData!!)) - LineLayer( - id = "routes-casing", - source = routes, - color = const(Color.White), - width = const(6.dp), - ) - LineLayer( - id = "routes", - source = routes, - color = const(Color.Blue), - width = const(4.dp), - ) + fun RouteLayer(routeData: String?) { + if (routeData!!.isNotEmpty()) { + val routes = + rememberGeoJsonSource(GeoJsonData.JsonString(routeData!!)) + LineLayer( + id = "routes-casing", + source = routes, + color = const(Color.White), + width = const(6.dp), + ) + LineLayer( + id = "routes", + source = routes, + color = const(Color.Blue), + width = const(4.dp), + ) + } } @Composable diff --git a/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt b/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt index bc81849..62295ba 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt @@ -12,7 +12,6 @@ import androidx.car.app.CarContext import androidx.car.app.Screen import androidx.car.app.ScreenManager import androidx.car.app.Session -import androidx.car.app.navigation.model.Maneuver import androidx.core.location.LocationListenerCompat import androidx.core.net.toUri import androidx.lifecycle.DefaultLifecycleObserver @@ -25,19 +24,18 @@ import com.kouros.navigation.car.screen.RequestPermissionScreen import com.kouros.navigation.car.screen.SearchScreen import com.kouros.navigation.data.Constants.TAG import com.kouros.navigation.data.ObjectBox -import com.kouros.navigation.model.RouteModel class NavigationSession : Session() { val uriScheme = "samples"; val uriHost = "navigation"; - lateinit var route: RouteCarModel; + lateinit var routeModel: RouteCarModel; lateinit var navigationScreen: NavigationScreen lateinit var surfaceRenderer: SurfaceRenderer var locationIndex = 0 - val test = true + val test = false var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? -> updateLocation(location) @@ -75,12 +73,12 @@ class NavigationSession : Session() { } override fun onCreateScreen(intent: Intent): Screen { - route = RouteCarModel() + routeModel = RouteCarModel() ObjectBox.init(carContext); - surfaceRenderer = SurfaceRenderer(carContext, lifecycle, route) + surfaceRenderer = SurfaceRenderer(carContext, lifecycle, routeModel) - navigationScreen = NavigationScreen(carContext, surfaceRenderer, route) + navigationScreen = NavigationScreen(carContext, surfaceRenderer, routeModel) if (carContext.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED @@ -152,7 +150,7 @@ class NavigationSession : Session() { updateLocation(location) locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, - /* minTimeMs= */ 100, + /* minTimeMs= */ 1000, /* minDistanceM= */ 0f, mLocationListener ) @@ -169,14 +167,14 @@ class NavigationSession : Session() { } fun test(location: Location?) { - if (route.isNavigating() && locationIndex < route.polylineLocations.size) { - val loc = route.polylineLocations[locationIndex] + if (routeModel.isNavigating() && locationIndex < routeModel.polylineLocations.size) { + val loc = routeModel.polylineLocations[locationIndex] val curLocation = Location(LocationManager.GPS_PROVIDER) curLocation.longitude = loc[0] curLocation.latitude = loc[1] update(curLocation) locationIndex += 1 - if (locationIndex > route.polylineLocations.size) { + if (locationIndex > routeModel.polylineLocations.size) { val locationManager = carContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager locationManager.removeUpdates(mLocationListener) @@ -188,12 +186,12 @@ class NavigationSession : Session() { fun update(location: Location) { surfaceRenderer.updateLocation(location) - if (route.isNavigating()) { - route.findManeuver(location) -// if (routingModel.distanceToRoute > 50) { -// routingModel.stopNavigating() + if (routeModel.isNavigating()) { + routeModel.findManeuver(location) +// if (routeModel.distanceToRoute > 50) { +// routeModel.stopNavigation() // locationIndex = 0 -// surfaceRenderer.setGeoJson() +// surfaceRenderer.setRouteData() // navigationScreen.reRoute() // } navigationScreen.updateTrip() diff --git a/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt b/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt index 3a4ecf8..65473bb 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.graphics.Color @@ -27,11 +28,11 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.setViewTreeLifecycleOwner import androidx.savedstate.setViewTreeSavedStateRegistryOwner import com.kouros.navigation.car.navigation.RouteCarModel -import com.kouros.navigation.utils.NavigationUtils.Utils.createGeoJson +import com.kouros.navigation.utils.NavigationUtils +import kotlinx.coroutines.flow.onSubscription import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.rememberCameraState import org.maplibre.compose.expressions.dsl.const -import org.maplibre.compose.layers.CircleLayer import org.maplibre.compose.layers.FillLayer import org.maplibre.compose.layers.LineLayer import org.maplibre.compose.location.LocationPuck @@ -45,13 +46,13 @@ import org.maplibre.compose.sources.rememberGeoJsonSource import org.maplibre.compose.style.BaseStyle import org.maplibre.spatialk.geojson.Position import kotlin.time.Duration.Companion.seconds -import androidx.compose.runtime.collectAsState -class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle, - private var routeModel: RouteCarModel) : DefaultLifecycleObserver { - var mVisibleArea: Rect? = null - var mStableArea: Rect? = null +class SurfaceRenderer( + carContext: CarContext, lifecycle: Lifecycle, + private var routeModel: RouteCarModel +) : DefaultLifecycleObserver { + private val mCarContext: CarContext = carContext var lastLocation = Location(LocationManager.GPS_PROVIDER) val cameraPosition = MutableLiveData( @@ -60,15 +61,15 @@ class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle, target = Position(latitude = 48.1857475, longitude = 11.5793627) ) ) - val geojson = MutableLiveData("") + val routeData = MutableLiveData("") - val previewGeojson = MutableLiveData("") + val previewRouteData = MutableLiveData("") var preview = false lateinit var mapView: ComposeView - val tilt = 60.0 + val tilt = 55.0 val padding = PaddingValues(start = 150.dp, top = 250.dp) val prePadding = PaddingValues(start = 150.dp, bottom = 300.dp) @@ -114,15 +115,14 @@ class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle, presentation.show() } } + override fun onVisibleAreaChanged(visibleArea: Rect) { synchronized(this@SurfaceRenderer) { - mVisibleArea = visibleArea } } override fun onStableAreaChanged(stableArea: Rect) { synchronized(this@SurfaceRenderer) { - mStableArea = stableArea } } @@ -155,10 +155,9 @@ class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle, @Composable fun Map() { - val position: CameraPosition? by cameraPosition.observeAsState() - val geoJsonData: String? by geojson.observeAsState() - val previewGeoJsonData: String? by previewGeojson.observeAsState() + val route: String? by routeData.observeAsState() + val previewRoute: String? by previewRouteData.observeAsState() val cameraState = rememberCameraState( firstPosition = @@ -172,15 +171,17 @@ class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle, padding = getPaddingValues() ) ) - val variant = if (isSystemInDarkTheme()) "dark" else "light" val locationProvider = rememberDefaultLocationProvider() val locationState = rememberUserLocationState(locationProvider) - MaplibreMap( cameraState = cameraState, //baseStyle = BaseStyle.Uri("https://tiles.openfreemap.org/styles/liberty"), baseStyle = BaseStyle.Uri("https://kouros-online.de/liberty"), ) { + getBaseSource(id = "openmaptiles")?.let { tiles -> + FillLayer(id = "example", visible = false, source = tiles, sourceLayer = "building") + RouteLayer(route, previewRoute) + } LocationPuck( idPrefix = "user-location", locationState = locationState, @@ -188,18 +189,6 @@ class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle, accuracyThreshold = 10f, colors = LocationPuckColors(accuracyStrokeColor = Color.Green) ) - getBaseSource(id = "openmaptiles")?.let { tiles -> - FillLayer(id = "example", visible = false, source = tiles, sourceLayer = "building") - val coordinates = mutableListOf>() - coordinates.add(listOf(position!!.target.longitude, position!!.target.latitude)) - coordinates.add( - listOf( - position!!.target.longitude + 0.00001, - position!!.target.latitude + 0.00001 - ) - ) - RouteLayer(geoJsonData, previewGeoJsonData) - } } LaunchedEffect(position) { @@ -217,26 +206,26 @@ class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle, } @Composable - fun RouteLayer(geoJsonData: String?, previewGeoJsonData: String?) { - if (geoJsonData!!.isNotEmpty()) { + fun RouteLayer(routeData: String?, previewRoute: String?) { + if (routeData!!.isNotEmpty()) { val routes = - rememberGeoJsonSource(GeoJsonData.JsonString(geoJsonData!!)) + rememberGeoJsonSource(GeoJsonData.JsonString(routeData)) LineLayer( id = "routes-casing", source = routes, color = const(Color.White), - width = const(12.dp), + width = const(16.dp), ) LineLayer( id = "routes", source = routes, color = const(Color.Blue), - width = const(10.dp), + width = const(14.dp), ) } - if (previewGeoJsonData!!.isNotEmpty()) { + if (previewRoute!!.isNotEmpty()) { val routes = - rememberGeoJsonSource(GeoJsonData.JsonString(previewGeoJsonData!!)) + rememberGeoJsonSource(GeoJsonData.JsonString(previewRoute)) LineLayer( id = "routes-casing-pre", source = routes, @@ -251,6 +240,7 @@ class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle, ) } } + override fun onCreate(owner: LifecycleOwner) { Log.i(TAG, "SurfaceRenderer created") mCarContext.getCarService(AppManager::class.java) @@ -276,16 +266,22 @@ class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle, fun updateLocation(location: Location) { synchronized(this) { - var bearing = cameraPosition.value!!.bearing - if (lastLocation.latitude != location.latitude) { - if (lastLocation.distanceTo(location) > 10) { - bearing = lastLocation.bearingTo(location).toDouble() + var bearing: Double + if (routeModel.isNavigating()) { + bearing = routeModel.currentStep().bearing + } else { + bearing = cameraPosition.value!!.bearing + if (lastLocation.latitude != location.latitude) { + if (lastLocation.distanceTo(location) > 5) { + bearing = lastLocation.bearingTo(location).toDouble() + } } } + var zoom = NavigationUtils().calculateZoom(location.speed.toDouble()) if (preview) { bearing = 0.0 + zoom = 11.0 } - val zoom = calculateZoom(location) cameraPosition.postValue( cameraPosition.value!!.copy( bearing = bearing, @@ -298,30 +294,13 @@ class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle, } } - private fun calculateZoom(location: Location): Double { - if (preview) { - return 11.0 - } - //var zoom = cameraPosition.value!!.zoom - val zoom = when (location.speed.toInt()) { - in 0..10 -> 17.0 - in 11..20 -> 16.0 - in 21..30 -> 15.0 - in 31..40 -> 14.0 - in 41..50 -> 13.0 - in 51..60 -> 12.0 - else -> 11 - } - return zoom.toDouble() - } - - fun setGeoJson() { - geojson.value = routeModel.geoJson + fun setRouteData() { + routeData.value = routeModel.route preview = false } - fun setPreviewGeoJson(geoRoute: String) { - previewGeojson.value = geoRoute + fun setPreviewRouteData(route: String) { + previewRouteData.value = route preview = true } @@ -332,6 +311,7 @@ class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle, padding } } + companion object { private const val TAG = "MapRenderer" diff --git a/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt b/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt index a993388..479ff8d 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt @@ -15,7 +15,6 @@ */ package com.kouros.navigation.car.navigation -import android.net.Uri import android.text.SpannableString import androidx.annotation.DrawableRes import androidx.annotation.StringRes @@ -43,34 +42,27 @@ class RouteCarModel() : RouteModel() { fun currentStep(carContext: CarContext): Step { val maneuver = (maneuvers[maneuverIndex] as JSONObject) val maneuverType = maneuver.getInt("type") - val distanceStepLeft = leftStepDistance() * 1000 - var text = "" + + val stepData = currentStep() + var routing: (Pair) routing = if (hasArrived(maneuverType)) { routingData(maneuverType, carContext) } else { routingData(ManeuverType.None.value, carContext) } - when (distanceStepLeft) { + when (stepData.leftDistance) { in 0.0..100.0 -> { if (maneuverIndex < maneuvers.length()) { val maneuver = (maneuvers[maneuverIndex + 1] as JSONObject) - if (maneuver.optJSONArray("street_names") != null) { - text = maneuver.getJSONArray("street_names").get(0) as String - } val maneuverType = maneuver.getInt("type") routing = routingData(maneuverType, carContext) } } - else -> { - if (maneuver.optJSONArray("street_names") != null) { - text = maneuver.getJSONArray("street_names").get(0) as String - } - } } val currentStepCueWithImage: SpannableString = - createString(text) + createString(stepData.instruction) val step = Step.Builder(currentStepCueWithImage) .setManeuver( @@ -88,8 +80,8 @@ class RouteCarModel() : RouteModel() { val maneuver = (maneuvers[maneuverIndex + 1] as JSONObject) val maneuverType = maneuver.getInt("type") val routing = routingData(maneuverType, carContext) - val distanceLeft = leftStepDistance() * 1000 var text = "" + val distanceLeft = leftStepDistance() * 1000 when (distanceLeft) { in 0.0..100.0 -> { diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt index 0bc3a7a..322b1e2 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt @@ -24,7 +24,6 @@ import androidx.lifecycle.Observer import com.kouros.android.cars.carappservice.R import com.kouros.navigation.car.NavigationCarAppService import com.kouros.navigation.car.SurfaceRenderer -import com.kouros.navigation.car.navigation.NavigationMessage import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.Place @@ -41,8 +40,8 @@ class NavigationScreen( val vieModel = ViewModel(NavigationRepository()) val observer = Observer { route -> if (route.isNotEmpty()) { - routeModel.createNavigationRoute(route) - surfaceRenderer.setGeoJson() + routeModel.startNavigation(route) + surfaceRenderer.setRouteData() invalidate() } } @@ -84,8 +83,8 @@ class NavigationScreen( .build() ) .setOnClickListener { - surfaceRenderer.geojson.postValue("") - routeModel.stopNavigating() + surfaceRenderer.routeData.postValue("") + routeModel.stopNavigation() invalidate() } .build() @@ -241,7 +240,7 @@ class NavigationScreen( fun updateTrip() { if (routeModel.maneuverType == Maneuver.TYPE_DESTINATION && routeModel.leftStepDistance() * 1000 < 25.0) { routeModel.arrived = true - routeModel.stopNavigating() + routeModel.stopNavigation() } invalidate() } diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt index 130a5b6..a42072e 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt @@ -67,8 +67,8 @@ class RoutePreviewScreen( val navigationMessage = NavigationMessage(carContext) val observer = Observer { route -> if (route.isNotEmpty()) { - routeModel.createNavigationRoute(route) - surfaceRenderer.setPreviewGeoJson(routeModel.geoJson) + routeModel.startNavigation(route) + surfaceRenderer.setPreviewRouteData(routeModel.route) val geocoder = Geocoder(carContext) geocoder.getFromLocation(destination.latitude, destination.longitude, 1) { for (address in it) { diff --git a/common/car/src/main/res/values-de/strings.xml b/common/car/src/main/res/values-de/strings.xml index 5d39c18..a22d14e 100644 --- a/common/car/src/main/res/values-de/strings.xml +++ b/common/car/src/main/res/values-de/strings.xml @@ -47,26 +47,17 @@ "Nein" "Alle Zeilen deaktivieren" "Alle Zeilen aktivieren" - "Fehler wurde gemeldet!" "Herangezoomt" "Herausgezoomt" "Ausgelöst" - "Primäre Schaltfläche gedrückt" - "Schaltfläche „Suchen“ gedrückt" - "Optionsschaltfläche gedrückt" "Favorit!" "Kein Favorit!" "Navigation angefragt" "Ausgewählte Route" "Sichtbare Routen" - "Zweiter Eintrag angeklickt" - "Dritter Eintrag aktiviert" - "Fünfter Eintrag aktiviert" - "Sechster Eintrag angeklickt" "Einstellungen angeklickt" "Aktion „Geparkt“" "„Mehr“ angeklickt" - "Schaltfläche für Arbeitsweg gedrückt" "Standortermittlung erlauben, um aktuellen Standort anzuzeigen" "Über Google anmelden beginnt hier" "Auswahl auf Index geändert" diff --git a/common/car/src/main/res/values/strings.xml b/common/car/src/main/res/values/strings.xml index 0f9557f..873dd7a 100644 --- a/common/car/src/main/res/values/strings.xml +++ b/common/car/src/main/res/values/strings.xml @@ -15,7 +15,7 @@ limitations under the License. --> - Showcase + Navigation BACK @@ -50,27 +50,18 @@ Enable All Rows - Bug reported! - Zoomed in + Zoomed in Zoomed out Triggered - Primary button pressed - Search button pressed - Options button pressed - Favorite! + Favorite! Not a favorite! Navigation Requested Selected route Visible routes - Clicked second item - Third item checked - Fifth item checked - Clicked sixth item - Clicked Settings + Clicked Settings Parked action Clicked More - Commute button pressed - Grant location Permission to see current location + Grant location Permission to see current location Sign-in with Google starts here Changed selection to index Yes button pressed! diff --git a/common/car/src/test/java/com/kouros/navigation/car/Route.json b/common/car/src/test/java/com/kouros/navigation/car/Route.json new file mode 100644 index 0000000..82d80ff --- /dev/null +++ b/common/car/src/test/java/com/kouros/navigation/car/Route.json @@ -0,0 +1,255 @@ +{ + "trip": { + "locations": [ + { + "type": "break", + "lat": 48.185749, + "lon": 11.579374, + "side_of_street": "right", + "original_index": 0 + }, + { + "type": "break", + "lat": 48.116481, + "lon": 11.594322, + "street": "Hohenwaldeckstr. 27", + "side_of_street": "left", + "original_index": 1 + } + ], + "legs": [ + { + "maneuvers": [ + { + "type": 2, + "instruction": "Auf Vogelhartstraße Richtung Westen fahren.", + "verbal_succinct_transition_instruction": "Richtung Westen fahren. Dann Rechts auf Silcherstraße abbiegen.", + "verbal_pre_transition_instruction": "Auf Vogelhartstraße Richtung Westen fahren. Dann Rechts auf Silcherstraße abbiegen.", + "verbal_post_transition_instruction": "70 Meter weiter der Route folgen.", + "street_names": [ + "Vogelhartstraße" + ], + "bearing_after": 273, + "time": 16.965, + "length": 0.07, + "cost": 34.428, + "begin_shape_index": 0, + "end_shape_index": 6, + "verbal_multi_cue": true, + "travel_mode": "drive", + "travel_type": "car" + }, + { + "type": 10, + "instruction": "Rechts auf Silcherstraße abbiegen.", + "verbal_transition_alert_instruction": "Rechts auf Silcherstraße abbiegen.", + "verbal_succinct_transition_instruction": "Rechts abbiegen.", + "verbal_pre_transition_instruction": "Rechts auf Silcherstraße abbiegen.", + "verbal_post_transition_instruction": "200 Meter weiter der Route folgen.", + "street_names": [ + "Silcherstraße" + ], + "bearing_before": 273, + "bearing_after": 5, + "time": 43.25, + "length": 0.156, + "cost": 89.306, + "begin_shape_index": 6, + "end_shape_index": 13, + "travel_mode": "drive", + "travel_type": "car" + }, + { + "type": 10, + "instruction": "Rechts auf Schmalkaldener Straße abbiegen.", + "verbal_transition_alert_instruction": "Rechts auf Schmalkaldener Straße abbiegen.", + "verbal_succinct_transition_instruction": "Rechts abbiegen.", + "verbal_pre_transition_instruction": "Rechts auf Schmalkaldener Straße abbiegen.", + "verbal_post_transition_instruction": "400 Meter weiter der Route folgen.", + "street_names": [ + "Schmalkaldener Straße" + ], + "bearing_before": 2, + "bearing_after": 93, + "time": 108.947, + "length": 0.43, + "cost": 217.43, + "begin_shape_index": 13, + "end_shape_index": 29, + "travel_mode": "drive", + "travel_type": "car" + }, + { + "type": 10, + "instruction": "Rechts auf Ingolstädter Straße/B 13 abbiegen.", + "verbal_transition_alert_instruction": "Rechts auf Ingolstädter Straße abbiegen.", + "verbal_succinct_transition_instruction": "Rechts abbiegen.", + "verbal_pre_transition_instruction": "Rechts auf Ingolstädter Straße, B 13 abbiegen.", + "verbal_post_transition_instruction": "einen Kilometer weiter der Route folgen.", + "street_names": [ + "B 13" + ], + "begin_street_names": [ + "Ingolstädter Straße", + "B 13" + ], + "bearing_before": 88, + "bearing_after": 178, + "time": 147.528, + "length": 1.064, + "cost": 230.646, + "begin_shape_index": 29, + "end_shape_index": 65, + "travel_mode": "drive", + "travel_type": "car" + }, + { + "type": 19, + "instruction": "Auf die Auffahrt nach links abbiegen.", + "verbal_transition_alert_instruction": "Auf die Auffahrt nach links abbiegen.", + "verbal_pre_transition_instruction": "Auf die Auffahrt nach links abbiegen.", + "street_names": [ + "Schenkendorfstraße" + ], + "bearing_before": 188, + "bearing_after": 98, + "time": 61.597, + "length": 0.374, + "cost": 117.338, + "begin_shape_index": 65, + "end_shape_index": 84, + "travel_mode": "drive", + "travel_type": "car" + }, + { + "type": 24, + "instruction": "Links halten auf B 2R.", + "verbal_transition_alert_instruction": "Links halten auf B 2R.", + "verbal_pre_transition_instruction": "Links halten auf B 2R.", + "verbal_post_transition_instruction": "6 Kilometer weiter der Route folgen.", + "street_names": [ + "B 2R" + ], + "bearing_before": 117, + "bearing_after": 118, + "time": 509.658, + "length": 6.37, + "cost": 580.602, + "begin_shape_index": 84, + "end_shape_index": 240, + "travel_mode": "drive", + "travel_type": "car" + }, + { + "type": 20, + "instruction": "An der Ausfahrt rechts abfahren.", + "verbal_transition_alert_instruction": "An der Ausfahrt rechts abfahren.", + "verbal_pre_transition_instruction": "An der Ausfahrt rechts abfahren.", + "verbal_post_transition_instruction": "einen Kilometer weiter der Route folgen.", + "street_names": [ + "Ampfingstraße" + ], + "bearing_before": 191, + "bearing_after": 206, + "time": 133.661, + "length": 1.031, + "cost": 226.661, + "begin_shape_index": 240, + "end_shape_index": 280, + "travel_mode": "drive", + "travel_type": "car" + }, + { + "type": 10, + "instruction": "Rechts auf Anzinger Straße abbiegen.", + "verbal_transition_alert_instruction": "Rechts auf Anzinger Straße abbiegen.", + "verbal_succinct_transition_instruction": "Rechts abbiegen.", + "verbal_pre_transition_instruction": "Rechts auf Anzinger Straße abbiegen.", + "verbal_post_transition_instruction": "1.5 Kilometer weiter der Route folgen.", + "street_names": [ + "Anzinger Straße" + ], + "bearing_before": 182, + "bearing_after": 277, + "time": 211.637, + "length": 1.444, + "cost": 450.654, + "begin_shape_index": 280, + "end_shape_index": 334, + "travel_mode": "drive", + "travel_type": "car" + }, + { + "type": 15, + "instruction": "Links auf Hohenwaldeckstraße abbiegen.", + "verbal_transition_alert_instruction": "Links auf Hohenwaldeckstraße abbiegen.", + "verbal_succinct_transition_instruction": "Links abbiegen.", + "verbal_pre_transition_instruction": "Links auf Hohenwaldeckstraße abbiegen.", + "verbal_post_transition_instruction": "200 Meter weiter der Route folgen.", + "street_names": [ + "Hohenwaldeckstraße" + ], + "bearing_before": 249, + "bearing_after": 170, + "time": 45.365, + "length": 0.183, + "cost": 84.344, + "begin_shape_index": 334, + "end_shape_index": 342, + "travel_mode": "drive", + "travel_type": "car" + }, + { + "type": 6, + "instruction": "Hohenwaldeckstr. 27 befindet sich auf der linken Seite.", + "verbal_transition_alert_instruction": "Hohenwaldeckstr. 27 befindet sich auf der linken Seite.", + "verbal_pre_transition_instruction": "Hohenwaldeckstr. 27 befindet sich auf der linken Seite.", + "bearing_before": 184, + "time": 0, + "length": 0, + "cost": 0, + "begin_shape_index": 342, + "end_shape_index": 342, + "travel_mode": "drive", + "travel_type": "car" + } + ], + "summary": { + "level_changes": [ + [220, -1] + ], + "has_time_restrictions": false, + "has_toll": false, + "has_highway": false, + "has_ferry": false, + "min_lat": 48.116486, + "min_lon": 11.578422, + "max_lat": 48.186957, + "max_lon": 11.616382, + "time": 1278.611, + "length": 11.123, + "cost": 2031.412 + }, + "shape": "mk_|zA_}vaUA^MzKKhKMrKMrLEbEeLs@kGa@yV}AmIa@cJ]g@AgQc@TgTn@ak@\\}Y`@u~@NiZRss@Ekc@AcGAwE?iB@yN@mH@_L?sAOiVEiGrISbH[|s@kC`KY~Qw@dk@mBdBErH]bIa@pNk@pAGxgA}ErQw@f`@eB`AAhEOjDO~Kg@bh@cCpTcAtEUlBKtFMbk@cBpt@eDfScAlH]hHY`HTdATbBl@rAd@|Bz@xBr@|F`AzD\\l@mHHsCAeDcAkImBiLs@}Ii@wOh@a]vAu[bB{VjCmXjCuUtDoU~A}JjBmIvDmOvDgOfCiJdB}HvAsG|FwSzGaV`IgWdC_K\\cG~Pii@pUcr@dYaz@lEkMdDsPpMm]|Tqj@tQwc@jQsb@nVwm@vEmL`k@suAxHyPzFaKrBaD|AmBxCeDpC}BvDmCnEyBnDuAzFyAhDWdDW|D?~CPjFj@lHrB|QzI~O~Jb]lS`ZbR~NnIhCdBdDtBb`Azk@fhAdr@vN~I~l@|]vr@vVb]jElZw@xG{@jEw@`KiCfLiFrJ_GnPaNjJaJzJoNxMgUtU}g@d]_w@f_@ev@tO_YhRmYbHwIxG_I|NwN~AyAdTiP~b@iZ~J}GxScQ`JoIfGwGtEwFnCqDbEaG~CcFhHgMrGcNxHmR|FaQnCwIpAeEdCiIje@}}AnQil@pGySjCyIvSor@nJ{ZpHwVbQyk@zIkXlHkTrOcc@bPic@rUyk@vKoVnMaWfWed@rT_`@jQcZhBwCzCsEtCcElC}CzCiDrCiCnH{GzLwJlGwDfH_ElGeDhHwClHyBrG{BdK_CzMsBzJgAbIq@jI?nYGbSTfGDvEDnGRfWx@|i@lEvpBbUdRrBpLfAl_@jDr|Ghm@hu@jGrWrBpd@fAxG[raBgUl[{HhM}DzOeGdXiLpCuAzwAij@lEcAbF_AnEc@|DDzE[dAGrIh@|APfe@lLbc@lLpWbIbdAnYnKlBf]|Tzi@rZbl@|ZtSjJpOhG~HvB`AVvBl@hBf@vBl@`AXrJrCtZjHhRvCrKpAjAN|Gb@hLr@dLp@xYbB`CPlDNxBLlOv@n{@jE~F\\lDP|Ov@lSn@rGNrGPlHAxICnJCvJBhFBrQL~E?dC?zFJ[xIcB|_@}Add@kAvi@i@zg@AtGEd_@f@lq@lB`|@jApd@tA`l@XpFn@lHf@bFnAdMjA`HnDpQfEfSvElPfBdOvCrWjP|xANrA|@bH\\pC\\lCNnA~Hhn@dB|MnAtJrAlK`AzH~@hHvBvPj@pEl@zFx@zH^hD~BlQdEbZhF`_@rAbJ|AjK~AtKzBrNt@nFv@lFtB`OdCfQbMb_AlDnUrDvTvF|ZzIxh@jDm@zHgBhF{@lC[`L]jMr@bNj@~_@bB" + } + ], + "summary": { + "has_time_restrictions": false, + "has_toll": false, + "has_highway": false, + "has_ferry": false, + "min_lat": 48.116486, + "min_lon": 11.578422, + "max_lat": 48.186957, + "max_lon": 11.616382, + "time": 1278.611, + "length": 11.123, + "cost": 2031.412 + }, + "status_message": "Found route between points", + "status": 0, + "units": "kilometers", + "language": "de-DE" + }, + "id": "my_work_route" +} \ No newline at end of file diff --git a/common/car/src/test/java/com/kouros/navigation/car/UnitTest.kt b/common/car/src/test/java/com/kouros/navigation/car/UnitTest.kt index 04ab17f..75688ab 100644 --- a/common/car/src/test/java/com/kouros/navigation/car/UnitTest.kt +++ b/common/car/src/test/java/com/kouros/navigation/car/UnitTest.kt @@ -1,6 +1,12 @@ package com.kouros.navigation.car -import com.kouros.navigation.car.navigation.RoutingModel +import android.location.Location +import android.location.LocationManager +import com.kouros.navigation.data.Constants.home2Location +import com.kouros.navigation.data.Constants.homeLocation +import com.kouros.navigation.data.NavigationRepository +import com.kouros.navigation.model.RouteModel +import com.kouros.navigation.model.ViewModel import org.junit.Assert.assertEquals import org.junit.Test @@ -14,5 +20,18 @@ class ExampleUnitTest { @Test fun addition_isCorrect() { assertEquals(4, 2 + 2) + val model = RouteModel() + val repo = NavigationRepository() + val viewModel = ViewModel(repo) + val fromLocation = Location(LocationManager.GPS_PROVIDER) + fromLocation.latitude = homeLocation.latitude + fromLocation.longitude = homeLocation.longitude + val toLocation = Location(LocationManager.GPS_PROVIDER) + toLocation.latitude = home2Location.latitude + toLocation.longitude = home2Location.longitude + + val route = repo.getRoute(fromLocation, toLocation) + model.startNavigation(route) + println(route) } -} \ No newline at end of file +} diff --git a/common/data/src/main/java/com/kouros/navigation/data/Place.kt b/common/data/src/main/java/com/kouros/navigation/data/Data.kt similarity index 96% rename from common/data/src/main/java/com/kouros/navigation/data/Place.kt rename to common/data/src/main/java/com/kouros/navigation/data/Data.kt index 193671f..d39450e 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/Place.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/Data.kt @@ -21,7 +21,6 @@ import android.location.LocationManager import android.net.Uri import io.objectbox.annotation.Entity import io.objectbox.annotation.Id -import io.objectbox.annotation.Index import kotlinx.serialization.Serializable data class Category( @@ -52,6 +51,12 @@ data class ContactData( val avatar: Uri? ) +data class StepData ( + var instruction: String, + var leftDistance: Double, + var bearing: Double +) + //val places = mutableListOf() /* Place( diff --git a/common/data/src/main/java/com/kouros/navigation/model/Contacts.kt b/common/data/src/main/java/com/kouros/navigation/model/Contacts.kt index d45e604..3f12f7e 100644 --- a/common/data/src/main/java/com/kouros/navigation/model/Contacts.kt +++ b/common/data/src/main/java/com/kouros/navigation/model/Contacts.kt @@ -33,7 +33,9 @@ class Contacts(private var context: Context) { while (moveToNext()) { val contactId = getLong(getColumnIndex(ContactsContract.Data.CONTACT_ID)) val name = getString(getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)) - if (name.contains("Jola") || name.contains("Dominic") + if (name.contains("Jola") + || name.contains("Dominic") + || name.contains("Martha") || name.contains("Μεντή") || name.contains("David")) { val mimeType: String = getString(getColumnIndex(ContactsContract.Data.MIMETYPE)) diff --git a/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt b/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt index 633ad80..5896ce8 100644 --- a/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt +++ b/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt @@ -3,6 +3,7 @@ package com.kouros.navigation.model import android.location.Location import android.location.LocationManager import com.kouros.navigation.data.Place +import com.kouros.navigation.data.StepData import com.kouros.navigation.utils.NavigationUtils.Utils.createGeoJson import com.kouros.navigation.utils.NavigationUtils.Utils.decodePolyline import org.json.JSONArray @@ -10,23 +11,19 @@ import org.json.JSONObject import kotlin.math.roundToInt -open class RouteModel { - +// Source - https://stackoverflow.com/a +// Posted by Dmitrii Bychkov +// Retrieved 2025-11-14, License - CC BY-SA 4.0 +open class RouteModel () { var polylineLocations: List> = emptyList() - lateinit var maneuvers: JSONArray lateinit var locations: JSONArray lateinit var summary: JSONObject - lateinit var destination: Place var navigating = false - var arrived = false - var maneuverIndex = 0 - var maneuverType = 0 - var currentIndex = 0 var distanceToStepEnd = 0F @@ -38,13 +35,23 @@ open class RouteModel { var distanceToRoute = 0F - var geoJson = "" + var route = "" - private fun decodeValhallaRoute(route: String) { - if (route.isEmpty() || route == "[]") { + data class Builder( + var route: String? = null, + var fromLocation: Location? = null, + var toLocation: Location? = null) { + + fun route(route: String) = apply { this.route = route } + fun fromLocation(fromLocation: Location) = apply { this.fromLocation = fromLocation } + fun toLocation(toLocation: Location) = apply { this.toLocation = toLocation } + //fun build() = RouteModel(route!!, fromLocation!!, toLocation!!) + } + private fun decodeValhallaRoute(valhallaRoute: String) { + if (valhallaRoute.isEmpty() || valhallaRoute == "[]") { return; } - val jObject = JSONObject(route) + val jObject = JSONObject(valhallaRoute) val trip = jObject.getJSONObject("trip") locations = trip.getJSONArray("locations") val legs = trip.getJSONArray("legs") @@ -54,13 +61,13 @@ open class RouteModel { polylineLocations = decodePolyline(shape) } - fun createNavigationRoute(route: String) { - decodeValhallaRoute(route) + fun startNavigation(valhallaRoute: String) { + decodeValhallaRoute(valhallaRoute) for (i in 0.. { + if (maneuverIndex < maneuvers.length()) { + val maneuver = (maneuvers[maneuverIndex + 1] as JSONObject) + if (maneuver.optJSONArray("street_names") != null) { + text = maneuver.getJSONArray("street_names").get(0) as String + } + } + } + } + return StepData(text, distanceStepLeft, bearing.toDouble()) + + } + /** Calculates the index in a maneuver. */ private fun calculateCurrentIndex( @@ -159,8 +191,6 @@ open class RouteModel { val maneuver = routingManeuvers[maneuverIndex] var leftDistance = maneuver.getDouble("length") if (endIndex > 0) { - val percent = 100 * (endIndex - currentIndex) / (endIndex - beginIndex) - //leftDistance = leftDistance * percent / 100 leftDistance = (distanceToStepEnd / 1000).toDouble() } return leftDistance @@ -190,11 +220,11 @@ open class RouteModel { return arrived } - fun stopNavigating() { + fun stopNavigation() { navigating = false polylineLocations = mutableListOf() routingManeuvers = mutableListOf() - geoJson = "" + route = "" maneuverIndex = 0 currentIndex = 0 distanceToStepEnd = 0F diff --git a/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt b/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt index 26e8f2c..d3cc8b4 100644 --- a/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt +++ b/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt @@ -105,4 +105,20 @@ class NavigationUtils() { //return LatLng(toDegrees(asin(sinLat)), toDegrees(fromLng + dLng)) } } + + fun calculateZoom(speed: Double?): Double { + if (speed == null) { + return 18.0 + } + val zoom = when (speed.toInt()) { + in 0..10 -> 17.0 + in 11..20 -> 17.0 + in 21..30 -> 17.0 + in 31..40 -> 16.0 + in 41..50 -> 15.0 + in 51..60 -> 14.0 + else -> 11 + } + return zoom.toDouble() + } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8d021d3..8133e9b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,6 +17,7 @@ ui = "1.9.4" material3 = "1.4.0" runtimeLivedata = "1.9.4" foundation = "1.9.4" +maplibre-composeMaterial3 = "0.12.2" maplibre-compose = "0.12.1" playServicesLocation = "21.3.0" runtime = "1.9.4" @@ -38,7 +39,7 @@ androidx-car-app = { group = "androidx.car.app", name = "app", version.ref = "ca #objectbox-kotlin = { module = "io.objectbox:objectbox-kotlin", version.ref = "objectboxKotlin" } ui = { group = "androidx.compose.ui", name = "ui", version.ref = "ui" } maplibre-compose = { module = "org.maplibre.compose:maplibre-compose", version.ref = "maplibre-compose" } -maplibre-composeMaterial3 = { module = "org.maplibre.compose:maplibre-compose-material3", version = "maplibre-compose" } +maplibre-composeMaterial3 = { module = "org.maplibre.compose:maplibre-compose-material3", version = "maplibre-composeMaterial3" } androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" } androidx-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata", version.ref = "runtimeLivedata" } androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "foundation" }