diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e13da31..3396d4a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,8 +14,8 @@ android { applicationId = "com.kouros.navigation" minSdk = 33 targetSdk = 36 - versionCode = 11 - versionName = "0.1.3.11" + versionCode = 13 + versionName = "0.1.3.13" base.archivesName = "navi-$versionName" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/com/kouros/navigation/MainApplication.kt b/app/src/main/java/com/kouros/navigation/MainApplication.kt index 6ada8ad..640c37d 100644 --- a/app/src/main/java/com/kouros/navigation/MainApplication.kt +++ b/app/src/main/java/com/kouros/navigation/MainApplication.kt @@ -2,8 +2,12 @@ package com.kouros.navigation import android.app.Application import android.content.Context +import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.ObjectBox +import com.kouros.navigation.data.osrm.OsrmRepository +import com.kouros.navigation.data.valhalla.ValhallaRepository import com.kouros.navigation.di.appModule +import com.kouros.navigation.model.ViewModel import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.startKoin @@ -26,5 +30,7 @@ class MainApplication : Application() { private set var useContacts = false + + val navigationViewModel = ViewModel(ValhallaRepository()) } } \ No newline at end of file diff --git a/app/src/main/java/com/kouros/navigation/di/appModule.kt b/app/src/main/java/com/kouros/navigation/di/appModule.kt index 2e1800d..6be255b 100644 --- a/app/src/main/java/com/kouros/navigation/di/appModule.kt +++ b/app/src/main/java/com/kouros/navigation/di/appModule.kt @@ -1,6 +1,8 @@ package com.kouros.navigation.di import com.kouros.navigation.data.NavigationRepository +import com.kouros.navigation.data.osrm.OsrmRepository +import com.kouros.navigation.data.valhalla.ValhallaRepository import com.kouros.navigation.model.ViewModel import org.koin.core.module.dsl.singleOf import org.koin.core.module.dsl.viewModelOf @@ -8,5 +10,5 @@ import org.koin.dsl.module val appModule = module { viewModelOf(::ViewModel) - singleOf(::NavigationRepository) + singleOf(::ValhallaRepository) } \ No newline at end of file diff --git a/app/src/main/java/com/kouros/navigation/model/MockLocation.kt b/app/src/main/java/com/kouros/navigation/model/MockLocation.kt index fcc4724..1211e96 100644 --- a/app/src/main/java/com/kouros/navigation/model/MockLocation.kt +++ b/app/src/main/java/com/kouros/navigation/model/MockLocation.kt @@ -49,7 +49,7 @@ class MockLocation (private var locationManager: LocationManager) { this.longitude = longitude this.altitude = 0.0 this.accuracy = 1.0f - this.speed = 0f + this.speed = 10f this.time = System.currentTimeMillis() this.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos() @@ -72,7 +72,7 @@ class MockLocation (private var locationManager: LocationManager) { this.longitude = longitude this.altitude = 0.0 this.accuracy = 1.0f - this.speed = 0f + this.speed = 10f this.time = System.currentTimeMillis() this.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos() diff --git a/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt b/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt index 2f773b5..f01eea1 100644 --- a/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt +++ b/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt @@ -15,18 +15,13 @@ import androidx.annotation.RequiresPermission import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.material3.BottomSheetScaffold -import androidx.compose.material3.BottomSheetScaffoldState -import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.rememberBottomSheetScaffoldState 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 @@ -37,19 +32,18 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Observer import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.LocationServices -import com.kouros.data.R -import com.kouros.navigation.data.Constants +import com.kouros.navigation.MainApplication.Companion.navigationViewModel import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE import com.kouros.navigation.data.Constants.homeLocation import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.StepData +import com.kouros.navigation.data.valhalla.ValhallaRepository import com.kouros.navigation.model.MockLocation import com.kouros.navigation.model.RouteModel import com.kouros.navigation.model.ViewModel @@ -73,7 +67,7 @@ import kotlin.time.Duration.Companion.seconds class MainActivity : ComponentActivity() { val routeData = MutableLiveData("") - val viewModel = ViewModel(NavigationRepository()) + val routeModel = RouteModel() var tilt = 50.0 val useMock = true @@ -109,8 +103,7 @@ class MainActivity : ComponentActivity() { private var overpass = false init { - viewModel.route.observe(this, observer) - + navigationViewModel.route.observe(this, observer) } @RequiresPermission(allOf = [Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION]) @@ -221,7 +214,7 @@ class MainActivity : ComponentActivity() { closeSheet: () -> Unit ) { if (!routeModel.isNavigating()) { - SearchSheet(applicationContext, viewModel, lastLocation) { closeSheet() } + SearchSheet(applicationContext, navigationViewModel, lastLocation) { closeSheet() } } else { NavigationSheet( routeModel, step!!, nextStep!!, @@ -241,7 +234,7 @@ class MainActivity : ComponentActivity() { val currentLocation = location(location.position.longitude, location.position.latitude) with(routeModel) { if (isNavigating()) { - updateLocation(currentLocation) + updateLocation(currentLocation, navigationViewModel) stepData.value = currentStep() if (route.currentManeuverIndex + 1 <= route.maneuvers.size) { nextStepData.value = nextStep() @@ -266,7 +259,7 @@ class MainActivity : ComponentActivity() { ) lastLocation = currentLocation if (!loadRecentPlaces) { - viewModel.loadRecentPlaces(applicationContext, lastLocation) + navigationViewModel.loadRecentPlaces(applicationContext, lastLocation) loadRecentPlaces = true } } @@ -320,7 +313,7 @@ class MainActivity : ComponentActivity() { fun test() { for ((index, loc) in routeModel.route.waypoints.withIndex()) { if (index > 300) { - routeModel.updateLocation(location(loc[0], loc[1])) + routeModel.updateLocation(location(loc[0], loc[1]), navigationViewModel) routeModel.currentStep() if (routeModel.route.currentManeuverIndex + 1 <= routeModel.route.maneuvers.size) { nextStepData.value = routeModel.nextStep() diff --git a/app/src/main/java/com/kouros/navigation/ui/MapView.kt b/app/src/main/java/com/kouros/navigation/ui/MapView.kt index 3f283b0..ae8a67c 100644 --- a/app/src/main/java/com/kouros/navigation/ui/MapView.kt +++ b/app/src/main/java/com/kouros/navigation/ui/MapView.kt @@ -1,62 +1,28 @@ package com.kouros.navigation.ui -import android.R.attr.x -import android.R.attr.y import android.content.Context import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.absoluteOffset -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp import androidx.lifecycle.MutableLiveData import androidx.window.layout.WindowMetricsCalculator import com.kouros.navigation.car.ViewStyle -import com.kouros.navigation.car.map.BuildingLayer import com.kouros.navigation.car.map.DarkMode import com.kouros.navigation.car.map.MapLibre import com.kouros.navigation.car.map.NavigationImage import com.kouros.navigation.data.Constants -import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING -import com.kouros.navigation.data.RouteColor import com.kouros.navigation.data.StepData -import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue import org.maplibre.compose.camera.CameraPosition -import org.maplibre.compose.camera.CameraState import org.maplibre.compose.camera.rememberCameraState -import org.maplibre.compose.expressions.dsl.const -import org.maplibre.compose.expressions.dsl.exponential -import org.maplibre.compose.expressions.dsl.interpolate -import org.maplibre.compose.expressions.dsl.zoom -import org.maplibre.compose.layers.CircleLayer -import org.maplibre.compose.layers.LineLayer import org.maplibre.compose.location.LocationTrackingEffect import org.maplibre.compose.location.UserLocationState -import org.maplibre.compose.map.MapOptions -import org.maplibre.compose.map.MaplibreMap -import org.maplibre.compose.map.OrnamentOptions -import org.maplibre.compose.sources.GeoJsonData -import org.maplibre.compose.sources.GeoJsonSource -import org.maplibre.compose.sources.getBaseSource -import org.maplibre.compose.sources.rememberGeoJsonSource import org.maplibre.compose.style.BaseStyle import org.maplibre.spatialk.geojson.Position import kotlin.time.Duration.Companion.seconds 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 6f413f0..be58e6a 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 @@ -25,7 +25,9 @@ import com.kouros.navigation.car.screen.SearchScreen import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION import com.kouros.navigation.data.Constants.MAXIMAL_SNAP_CORRECTION import com.kouros.navigation.data.Constants.TAG -import com.kouros.navigation.data.ObjectBox +import com.kouros.navigation.data.NavigationRepository +import com.kouros.navigation.data.valhalla.ValhallaRepository +import com.kouros.navigation.model.ViewModel import com.kouros.navigation.utils.GeoUtils.snapLocation class NavigationSession : Session(), NavigationScreen.Listener { @@ -67,6 +69,7 @@ class NavigationSession : Session(), NavigationScreen.Listener { } } + val navigationViewModel = ViewModel(ValhallaRepository()) init { val lifecycle: Lifecycle = lifecycle @@ -78,7 +81,7 @@ class NavigationSession : Session(), NavigationScreen.Listener { surfaceRenderer = SurfaceRenderer(carContext, lifecycle, routeModel) - navigationScreen = NavigationScreen(carContext, surfaceRenderer, routeModel, this) + navigationScreen = NavigationScreen(carContext, surfaceRenderer, routeModel, this, navigationViewModel) if (carContext.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && !useContacts @@ -116,6 +119,7 @@ class NavigationSession : Session(), NavigationScreen.Listener { carContext, surfaceRenderer, location, + navigationViewModel, // TODO: Uri ) ) { obj: Any? -> 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 5e1ff71..4f11a5d 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 @@ -28,7 +28,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.setViewTreeLifecycleOwner import androidx.savedstate.setViewTreeSavedStateRegistryOwner import com.kouros.navigation.car.map.DarkMode -import com.kouros.navigation.car.map.DrawImage +import com.kouros.navigation.car.map.DrawNavigationImages import com.kouros.navigation.car.map.MapLibre import com.kouros.navigation.car.map.cameraState import com.kouros.navigation.car.map.getPaddingValues @@ -191,7 +191,7 @@ class SurfaceRenderer( duration(viewStyle == ViewStyle.PREVIEW, position!!.bearing, lastBearing) val currentSpeed: Float? by speed.observeAsState() if (viewStyle == ViewStyle.VIEW) { - DrawImage(paddingValues, currentSpeed, width, height) + DrawNavigationImages(paddingValues, currentSpeed, routeModel.routeState.maxSpeed, width, height) } LaunchedEffect(position, viewStyle) { cameraState.animateTo( diff --git a/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt b/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt index 28050ec..5cc062e 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.graphics.drawscope.scale import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.drawText +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -33,13 +34,10 @@ import com.kouros.navigation.data.RouteColor import com.kouros.navigation.data.SpeedColor import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.CameraState import org.maplibre.compose.camera.rememberCameraState import org.maplibre.compose.expressions.dsl.const -import org.maplibre.compose.expressions.dsl.contains import org.maplibre.compose.expressions.dsl.exponential import org.maplibre.compose.expressions.dsl.image import org.maplibre.compose.expressions.dsl.interpolate @@ -60,15 +58,7 @@ import org.maplibre.compose.sources.Source import org.maplibre.compose.sources.getBaseSource import org.maplibre.compose.sources.rememberGeoJsonSource import org.maplibre.compose.style.BaseStyle -import org.maplibre.geojson.FeatureCollection -import org.maplibre.spatialk.geojson.BoundingBox.Companion.serializer -import org.maplibre.spatialk.geojson.Feature -import org.maplibre.spatialk.geojson.GeoJson -import org.maplibre.spatialk.geojson.Geometry import org.maplibre.spatialk.geojson.Position -import org.maplibre.spatialk.geojson.dsl.FeatureBuilder -import org.maplibre.spatialk.geojson.dsl.FeatureCollectionBuilder -import org.maplibre.spatialk.geojson.dsl.buildFeatureCollection @Composable @@ -187,9 +177,12 @@ fun BuildingLayer(tiles: Source) { } @Composable -fun DrawImage(padding: PaddingValues, speed: Float?, width: Int, height: Int) { +fun DrawNavigationImages(padding: PaddingValues, speed: Float?, maxSpeed: Int, width: Int, height: Int) { NavigationImage(padding, width, height) - Speed(width, height, speed) + CurrentSpeed(width, height, speed) + if (speed != null && maxSpeed > 0 && (speed * 3.6) > maxSpeed) { + MaxSpeed(width, height, maxSpeed) + } } @Composable @@ -215,7 +208,7 @@ fun NavigationImage(padding: PaddingValues, width: Int, height: Int) { } @Composable -private fun Speed( +private fun CurrentSpeed( width: Int, height: Int, speed: Float? @@ -235,6 +228,7 @@ private fun Speed( val kmh = "km/h" val styleSpeed = TextStyle( fontSize = 22.sp, + fontWeight = FontWeight.Bold, color = Color.White, ) val styleKm = TextStyle( @@ -278,6 +272,61 @@ private fun Speed( } } +@Composable +private fun MaxSpeed( + width: Int, + height: Int, + maxSpeed: Int, +) { + val radius = 20 + Box( + modifier = Modifier + .padding( + start = width.dp - 350.dp, + top = height.dp - 80.dp + ), + contentAlignment = Alignment.Center + ) { + val textMeasurerSpeed = rememberTextMeasurer() + val speed = maxSpeed.toString() + val styleSpeed = TextStyle( + fontSize = 26.sp, + fontWeight = FontWeight.Bold, + color = Color.Black, + ) + val textLayoutSpeed = remember(speed) { + textMeasurerSpeed.measure(speed, styleSpeed) + } + Canvas(modifier = Modifier.fillMaxSize()) { + drawCircle( + center = Offset( + x = center.x, + y = center.y + ), + radius = radius * 1.3.toFloat(), + color = Color.Red, + ) + drawCircle( + center = Offset( + x = center.x, + y = center.y + ), + radius = radius.toFloat(), + color = Color.White, + ) + drawText( + textMeasurer = textMeasurerSpeed, + text = speed, + style = styleSpeed, + topLeft = Offset( + x = center.x - textLayoutSpeed.size.width / 2, + y = center.y - textLayoutSpeed.size.height / 2, + ) + ) + } + } +} + @Composable fun DarkMode(context: Context, baseStyle: MutableState) { val darkMode = getIntKeyValue(context, Constants.DARK_MODE_SETTINGS) 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 4001944..9fb8605 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 @@ -74,7 +74,7 @@ class RouteCarModel() : RouteModel() { return step } - fun travelEstimate(): TravelEstimate { + fun travelEstimate(carContext: CarContext): TravelEstimate { val timeLeft = travelLeftTime() val timeToDestinationMillis = TimeUnit.SECONDS.toMillis(timeLeft.toLong()) @@ -88,7 +88,7 @@ class RouteCarModel() : RouteModel() { arrivalTime(), TimeZone.getTimeZone("Europe/Berlin") ) - return TravelEstimate.Builder( // The estimated distance to the destination. + val travelBuilder = TravelEstimate.Builder( // The estimated distance to the destination. Distance.create( leftDistance, displayUnit @@ -102,9 +102,12 @@ class RouteCarModel() : RouteModel() { ) .setRemainingTimeColor(CarColor.YELLOW) .setRemainingDistanceColor(CarColor.RED) - //.setTripText(createCarText(carContext,R.string.navigate)) - //.setTripIcon(createCarIcon(carContext, R.drawable.navigation_48px)) - .build() + + if (routeState.travelMessage.isNotEmpty()) { + travelBuilder.setTripIcon(createCarIcon(carContext, R.drawable.warning_24px)) + travelBuilder.setTripText(CarText.create(routeState.travelMessage)) + } + return travelBuilder.build() } fun createString( @@ -123,12 +126,12 @@ class RouteCarModel() : RouteModel() { } fun showSpeedCamera(carContext: CarContext, distance: Double, maxSpeed: String?) { - carContext.getCarService(AppManager::class.java) - .showAlert(createAlert(carContext, distance, maxSpeed)) + carContext.getCarService(AppManager::class.java) + .showAlert(createAlert(carContext, distance, maxSpeed)) } fun createAlert(carContext: CarContext, distance: Double, maxSpeed: String?): Alert { - val title = createCarText(carContext,R.string.speed_camera) + val title = createCarText(carContext, R.string.speed_camera) val subtitle = CarText.create(maxSpeed!!) val icon = CarIcon.ALERT @@ -144,6 +147,7 @@ class RouteCarModel() : RouteModel() { .addAction(dismissAction).setCallback(object : AlertCallback { override fun onCancel(reason: Int) { } + override fun onDismiss() { } }).build() @@ -155,8 +159,8 @@ class RouteCarModel() : RouteModel() { flags: Int ): Action { return Action.Builder() - .setOnClickListener { } - .setTitle(createCarText(carContext,titleRes)) + .setOnClickListener { } + .setTitle(createCarText(carContext, titleRes)) .setFlags(flags) .build() } diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/CategoriesScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/CategoriesScreen.kt index 28ce1d3..4499695 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/CategoriesScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/CategoriesScreen.kt @@ -18,11 +18,13 @@ import com.kouros.navigation.data.Category import com.kouros.navigation.data.Constants.CHARGING_STATION import com.kouros.navigation.data.Constants.FUEL_STATION import com.kouros.navigation.data.Constants.PHARMACY +import com.kouros.navigation.model.ViewModel class CategoriesScreen( private val carContext: CarContext, private val surfaceRenderer: SurfaceRenderer, private val location: Location, + private val viewModel: ViewModel ) : Screen(carContext) { var categories: List = listOf( @@ -46,7 +48,8 @@ class CategoriesScreen( carContext, surfaceRenderer, location, - it.id + it.id, + viewModel ) ) { obj: Any? -> if (obj != null) { diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/CategoryScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/CategoryScreen.kt index 4966f08..3831baf 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/CategoryScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/CategoryScreen.kt @@ -33,9 +33,9 @@ class CategoryScreen( private val surfaceRenderer: SurfaceRenderer, location: Location, private val category: String, + private val viewModel: ViewModel ) : Screen(carContext) { - val viewModel = ViewModel(NavigationRepository()) var elements = listOf() val observer = Observer> { newElements -> @@ -113,7 +113,6 @@ class CategoryScreen( .setOnClickListener { val location = location(it.lon!!, it.lat!!) surfaceRenderer.setCategoryLocation(location, category) - println(it) } .setTitle(name) .setImage(carIcon(carContext, category)) 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 3da4d4f..eeb6870 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 @@ -11,6 +11,7 @@ import androidx.car.app.model.Action.FLAG_DEFAULT import androidx.car.app.model.ActionStrip import androidx.car.app.model.CarColor import androidx.car.app.model.CarIcon +import androidx.car.app.model.CarText import androidx.car.app.model.Distance import androidx.car.app.model.Header import androidx.car.app.model.MessageTemplate @@ -39,7 +40,8 @@ class NavigationScreen( carContext: CarContext, private var surfaceRenderer: SurfaceRenderer, private var routeModel: RouteCarModel, - private var listener: Listener + private var listener: Listener, + private val viewModel: ViewModel ) : Screen(carContext) { @@ -52,7 +54,7 @@ class NavigationScreen( var currentNavigationLocation = Location(LocationManager.GPS_PROVIDER) var recentPlace = Place() var navigationType = NavigationType.VIEW - val viewModel = ViewModel(NavigationRepository()) + val observer = Observer { route -> if (route.isNotEmpty()) { navigationType = NavigationType.NAVIGATION @@ -88,7 +90,6 @@ class NavigationScreen( var speedCameras = listOf() val speedObserver = Observer> { cameras -> speedCameras = cameras - println("Speed cameras ${speedCameras.size}") } init { @@ -118,7 +119,7 @@ class NavigationScreen( .setNavigationInfo( getRoutingInfo() ) - .setDestinationTravelEstimate(routeModel.travelEstimate()) + .setDestinationTravelEstimate(routeModel.travelEstimate(carContext)) .setActionStrip(actionStripBuilder.build()) .setMapActionStrip(mapActionStripBuilder().build()) .setBackgroundColor(CarColor.GREEN) @@ -301,7 +302,7 @@ class NavigationScreen( .setOnClickListener { val navigateTo = location(recentPlace.longitude, recentPlace.latitude) viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, navigateTo) - routeModel.routeState.destination = recentPlace + routeModel.routeState = routeModel.routeState.copy(destination = recentPlace) } .build() } @@ -394,7 +395,7 @@ class NavigationScreen( private fun startSearchScreen() { screenManager .pushForResult( - SearchScreen(carContext, surfaceRenderer, surfaceRenderer.lastLocation) + SearchScreen(carContext, surfaceRenderer, surfaceRenderer.lastLocation, viewModel) ) { obj: Any? -> if (obj != null) { val place = obj as Place @@ -417,7 +418,7 @@ class NavigationScreen( viewModel.saveRecent(place) currentNavigationLocation = location viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, location) - routeModel.routeState.destination = place + routeModel.routeState = routeModel.routeState.copy(destination = place) invalidate() } @@ -430,8 +431,8 @@ class NavigationScreen( } fun calculateNewRoute(destination: Place) { - navigationType = NavigationType.REROUTE stopNavigation() + navigationType = NavigationType.REROUTE invalidate() val mainThreadHandler = Handler(carContext.mainLooper) mainThreadHandler.post { @@ -451,14 +452,9 @@ class NavigationScreen( } fun updateTrip(location: Location) { - if (lastCameraSearch++ % 100 == 0) { - viewModel.getSpeedCameras(location) - } - if (speedCameras.isNotEmpty()) { - updateDistance(location) - } + updateSpeedCamera(location) with(routeModel) { - updateLocation(location) + updateLocation(location, viewModel) if (routeState.maneuverType == Maneuver.TYPE_DESTINATION && leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE ) { @@ -472,6 +468,15 @@ class NavigationScreen( invalidate() } + private fun updateSpeedCamera(location: Location) { + if (lastCameraSearch++ % 100 == 0) { + viewModel.getSpeedCameras(location) + } + if (speedCameras.isNotEmpty()) { + updateDistance(location) + } + } + private fun updateDistance( location: Location, ) { @@ -485,10 +490,9 @@ class NavigationScreen( } val sortedList = updatedCameras.sortedWith(compareBy { it.distance }) val camera = sortedList.first() - if (camera.distance < 100) { + if (camera.distance < 80) { routeModel.showSpeedCamera(carContext, camera.distance, camera.tags.maxspeed) } - } } diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/PlaceListScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/PlaceListScreen.kt index a06fdb3..dc454b3 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/PlaceListScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/PlaceListScreen.kt @@ -37,10 +37,10 @@ class PlaceListScreen( private val carContext: CarContext, private val surfaceRenderer: SurfaceRenderer, private val location: Location, - private val category: String + private val category: String, + private val viewModel: ViewModel ) : Screen(carContext) { - val viewModel = ViewModel(NavigationRepository()) var places = listOf() val observer = Observer> { newPlaces -> @@ -102,7 +102,8 @@ class PlaceListScreen( RoutePreviewScreen( carContext, surfaceRenderer, - place + place, + viewModel ) ) { obj: Any? -> if (obj != null) { 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 f0a8ef0..39a3267 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 @@ -41,13 +41,12 @@ import java.math.RoundingMode class RoutePreviewScreen( carContext: CarContext, private var surfaceRenderer: SurfaceRenderer, - private var destination: Place + private var destination: Place, + private val viewModel: ViewModel ) : Screen(carContext) { private var isFavorite = false - val vieModel = ViewModel(NavigationRepository()) - val routeModel = RouteCarModel() val navigationMessage = NavigationMessage(carContext) @@ -60,9 +59,9 @@ class RoutePreviewScreen( } init { - vieModel.previewRoute.observe(this, observer) + viewModel.previewRoute.observe(this, observer) val location = location(destination.longitude, destination.latitude) - vieModel.loadPreviewRoute(carContext, surfaceRenderer.lastLocation, location) + viewModel.loadPreviewRoute(carContext, surfaceRenderer.lastLocation, location) } override fun onGetTemplate(): Template { @@ -149,7 +148,7 @@ class RoutePreviewScreen( CarToast.LENGTH_SHORT ) .show() - vieModel.saveFavorite(destination) + viewModel.saveFavorite(destination) invalidate() } .build() @@ -157,7 +156,7 @@ class RoutePreviewScreen( private fun deleteFavoriteAction(): Action = Action.Builder() .setOnClickListener { if (isFavorite) { - vieModel.deleteFavorite(destination) + viewModel.deleteFavorite(destination) } isFavorite = !isFavorite finish() diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt index 42e3999..44f3e37 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt @@ -28,7 +28,8 @@ import com.kouros.navigation.model.ViewModel class SearchScreen( carContext: CarContext, private var surfaceRenderer: SurfaceRenderer, - private var location: Location + private var location: Location, + private val viewModel: ViewModel ) : Screen(carContext) { var isSearchComplete: Boolean = false @@ -47,8 +48,6 @@ class SearchScreen( invalidate() } - val viewModel = ViewModel(NavigationRepository()) - init { viewModel.searchPlaces.observe(this, observer) } @@ -75,6 +74,7 @@ class SearchScreen( carContext, surfaceRenderer, location, + viewModel ) ) { obj: Any? -> surfaceRenderer.viewStyle = ViewStyle.VIEW @@ -90,7 +90,8 @@ class SearchScreen( carContext, surfaceRenderer, location, - it.id + it.id, + viewModel ) ) { obj: Any? -> if (obj != null) { 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 cc2dca3..6c05bdc 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 @@ -34,6 +34,5 @@ class ViewModelTest { val route = repo.getRoute(fromLocation, toLocation, SearchFilter()) model.startNavigation(route) - println(route) } } diff --git a/common/data/src/main/java/com/kouros/navigation/data/Color.kt b/common/data/src/main/java/com/kouros/navigation/data/Color.kt index 16ad5dd..e318032 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/Color.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/Color.kt @@ -8,4 +8,6 @@ val RouteColor = Color(0xFF5582D0) val SpeedColor = Color(0xFF262525) +val MaxSpeedColor = Color(0xFF262525) + val PlaceColor = Color(0xFF868005) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt b/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt index 97a434e..af01e26 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt @@ -27,34 +27,14 @@ import java.net.URL import kotlinx.serialization.json.Json -class NavigationRepository { +abstract class NavigationRepository { private val placesUrl = "https://kouros-online.de/maps/placespwd"; - private val routeUrl = "https://kouros-online.de/valhalla/route?json=" - private val nominatimUrl = "https://nominatim.openstreetmap.org/" - // Road classes from highest to lowest are: - // motorway, trunk, primary, secondary, tertiary, unclassified, residential, service_other. - // exclude_toll - fun getRoute(currentLocation: Location, location: Location, searchFilter: SearchFilter): String { - SearchFilter - val vLocation = listOf( - Locations(lat = currentLocation.latitude, lon = currentLocation.longitude, search_filter = searchFilter), - Locations(lat = location.latitude, lon = location.longitude, search_filter = searchFilter) - ) - val valhallaLocation = ValhallaLocation( - locations = vLocation, - costing = "auto", - units = "km", - id = "my_work_route", - language = "de-DE" - ) - val routeLocation = Json.encodeToString(valhallaLocation) - return fetchUrl(routeUrl + routeLocation, true) - } + abstract fun getRoute(currentLocation: Location, location: Location, searchFilter: SearchFilter): String fun getRouteDistance(currentLocation: Location, location: Location, searchFilter: SearchFilter): Double { val route = getRoute(currentLocation, location, searchFilter) @@ -98,7 +78,7 @@ class NavigationRepository { return places } - private fun fetchUrl(url: String, authenticator : Boolean): String { + fun fetchUrl(url: String, authenticator : Boolean): String { try { if (authenticator) { Authenticator.setDefault(object : Authenticator() { diff --git a/common/data/src/main/java/com/kouros/navigation/data/Route.kt b/common/data/src/main/java/com/kouros/navigation/data/Route.kt index 657d92c..1d31742 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/Route.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/Route.kt @@ -75,8 +75,8 @@ data class Route( fun route(route: String) = apply { if (route.isNotEmpty() && route != "[]") { val gson = GsonBuilder().serializeNulls().create() - val valhalla = gson.fromJson(route, ValhallaJson::class.java) - trip = valhalla.trip + val routeJson = gson.fromJson(route, ValhallaJson::class.java) + trip = routeJson.trip } } diff --git a/common/data/src/main/java/com/kouros/navigation/data/osrm/Intersections.kt b/common/data/src/main/java/com/kouros/navigation/data/osrm/Intersections.kt new file mode 100644 index 0000000..024ebe2 --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/osrm/Intersections.kt @@ -0,0 +1,13 @@ +package com.kouros.navigation.data.osrm + +import com.google.gson.annotations.SerializedName + + +data class Intersections( + + @SerializedName("out") var out: Int? = null, + @SerializedName("entry") var entry: ArrayList = arrayListOf(), + @SerializedName("bearings") var bearings: ArrayList = arrayListOf(), + @SerializedName("location") var location: ArrayList = arrayListOf(), + @SerializedName("lanes") var lanes: ArrayList = arrayListOf(), +) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/osrm/Lane.kt b/common/data/src/main/java/com/kouros/navigation/data/osrm/Lane.kt new file mode 100644 index 0000000..1c62711 --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/osrm/Lane.kt @@ -0,0 +1,8 @@ +package com.kouros.navigation.data.osrm + +import com.google.gson.annotations.SerializedName + +data class Lane( + @SerializedName("valid" ) var valid: Boolean, + @SerializedName("indications" ) var indications: List, +) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/osrm/Legs.kt b/common/data/src/main/java/com/kouros/navigation/data/osrm/Legs.kt new file mode 100644 index 0000000..d1ad77a --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/osrm/Legs.kt @@ -0,0 +1,14 @@ +package com.kouros.navigation.data.osrm + +import com.google.gson.annotations.SerializedName + + +data class Legs ( + + @SerializedName("steps" ) var steps : ArrayList = arrayListOf(), + @SerializedName("weight" ) var weight : Double? = null, + @SerializedName("summary" ) var summary : String? = null, + @SerializedName("duration" ) var duration : Double? = null, + @SerializedName("distance" ) var distance : Double? = null + +) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/osrm/Maneuver.kt b/common/data/src/main/java/com/kouros/navigation/data/osrm/Maneuver.kt new file mode 100644 index 0000000..d3b0402 --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/osrm/Maneuver.kt @@ -0,0 +1,14 @@ +package com.kouros.navigation.data.osrm + +import com.google.gson.annotations.SerializedName + + +data class Maneuver ( + + @SerializedName("bearing_after" ) var bearingAfter : Int? = null, + @SerializedName("bearing_before" ) var bearingBefore : Int? = null, + @SerializedName("location" ) var location : ArrayList = arrayListOf(), + @SerializedName("modifier" ) var modifier : String? = null, + @SerializedName("type" ) var type : String? = null + +) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/osrm/OsrmJson.kt b/common/data/src/main/java/com/kouros/navigation/data/osrm/OsrmJson.kt new file mode 100644 index 0000000..d330866 --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/osrm/OsrmJson.kt @@ -0,0 +1,12 @@ +package com.kouros.navigation.data.osrm + +import com.google.gson.annotations.SerializedName + + +data class OsrmJson ( + + @SerializedName("code" ) var code : String? = null, + @SerializedName("routes" ) var routes : ArrayList = arrayListOf(), + @SerializedName("waypoints" ) var waypoints : ArrayList = arrayListOf() + +) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/osrm/OsrmRepository.kt b/common/data/src/main/java/com/kouros/navigation/data/osrm/OsrmRepository.kt new file mode 100644 index 0000000..206ed7f --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/osrm/OsrmRepository.kt @@ -0,0 +1,18 @@ +package com.kouros.navigation.data.osrm + +import android.location.Location +import com.kouros.navigation.data.NavigationRepository +import com.kouros.navigation.data.SearchFilter + +private const val routeUrl = "https://router.project-osrm.org/route/v1/driving/" + +class OsrmRepository : NavigationRepository() { + override fun getRoute( + currentLocation: Location, + location: Location, + searchFilter: SearchFilter + ): String { + val routeLocation = "${currentLocation.latitude},${currentLocation.longitude};${location.latitude},${location.longitude}?steps=true" + return fetchUrl(routeUrl + routeLocation, true) + } +} \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/osrm/Routes.kt b/common/data/src/main/java/com/kouros/navigation/data/osrm/Routes.kt new file mode 100644 index 0000000..062778e --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/osrm/Routes.kt @@ -0,0 +1,15 @@ +package com.kouros.navigation.data.osrm + +import com.google.gson.annotations.SerializedName + + +data class Routes ( + + @SerializedName("legs" ) var legs : ArrayList = arrayListOf(), + @SerializedName("weight_name" ) var weightName : String? = null, + @SerializedName("geometry" ) var geometry : String? = null, + @SerializedName("weight" ) var weight : Double? = null, + @SerializedName("duration" ) var duration : Double? = null, + @SerializedName("distance" ) var distance : Double? = null + +) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/osrm/Steps.kt b/common/data/src/main/java/com/kouros/navigation/data/osrm/Steps.kt new file mode 100644 index 0000000..d110fc4 --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/osrm/Steps.kt @@ -0,0 +1,18 @@ +package com.kouros.navigation.data.osrm + +import com.google.gson.annotations.SerializedName + + +data class Steps ( + + @SerializedName("intersections" ) var intersections : ArrayList = arrayListOf(), + @SerializedName("driving_side" ) var drivingSide : String? = null, + @SerializedName("geometry" ) var geometry : String? = null, + @SerializedName("maneuver" ) var maneuver : Maneuver? = Maneuver(), + @SerializedName("name" ) var name : String? = null, + @SerializedName("mode" ) var mode : String? = null, + @SerializedName("weight" ) var weight : Double? = null, + @SerializedName("duration" ) var duration : Double? = null, + @SerializedName("distance" ) var distance : Double? = null + +) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/osrm/Waypoints.kt b/common/data/src/main/java/com/kouros/navigation/data/osrm/Waypoints.kt new file mode 100644 index 0000000..d7a20a3 --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/osrm/Waypoints.kt @@ -0,0 +1,13 @@ +package com.kouros.navigation.data.osrm + +import com.google.gson.annotations.SerializedName + + +data class Waypoints ( + + @SerializedName("hint" ) var hint : String? = null, + @SerializedName("location" ) var location : ArrayList = arrayListOf(), + @SerializedName("name" ) var name : String? = null, + @SerializedName("distance" ) var distance : Double? = null + +) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/osrm/osrm.json b/common/data/src/main/java/com/kouros/navigation/data/osrm/osrm.json new file mode 100644 index 0000000..83369e7 --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/osrm/osrm.json @@ -0,0 +1,1020 @@ +{ + "code": "Ok", + "routes": [ + { + "legs": [ + { + "steps": [ + { + "intersections": [ + { + "out": 0, + "entry": [true], + "bearings": [275], + "location": [11.57936, 48.185543] + } + ], + "driving_side": "right", + "geometry": "sfbeH_rteA?BAf@Af@?f@Aj@?R", + "maneuver": { + "bearing_after": 275, + "bearing_before": 0, + "location": [11.57936, 48.185543], + "modifier": "right", + "type": "depart" + }, + "name": "Vogelhartstraße", + "mode": "driving", + "weight": 12.7, + "duration": 12.7, + "distance": 69.8 + }, + { + "intersections": [ + { + "out": 0, + "in": 1, + "entry": [true, false, false, true], + "bearings": [0, 90, 195, 270], + "location": [11.578423, 48.185574] + } + ], + "driving_side": "right", + "geometry": "yfbeHclteAk@EYCkAGa@Cc@CC?y@A", + "maneuver": { + "bearing_after": 4, + "bearing_before": 271, + "location": [11.578423, 48.185574], + "modifier": "right", + "type": "turn" + }, + "name": "Silcherstraße", + "mode": "driving", + "weight": 25.2, + "duration": 25.2, + "distance": 154.2 + }, + { + "intersections": [ + { + "out": 0, + "in": 1, + "entry": [true, false, true], + "bearings": [90, 180, 270], + "location": [11.578564, 48.186957] + }, + { + "out": 0, + "in": 2, + "entry": [true, true, false], + "bearings": [90, 195, 270], + "location": [11.58106, 48.18689] + }, + { + "out": 0, + "in": 2, + "entry": [true, true, false], + "bearings": [90, 180, 270], + "location": [11.583158, 48.186877] + } + ], + "driving_side": "right", + "geometry": "oobeH_mteA@cADmC@uABkE@wA@gDAsB?Y?U?I?q@?_@@g@?IAiAAY", + "maneuver": { + "bearing_after": 91, + "bearing_before": 1, + "location": [11.578564, 48.186957], + "modifier": "right", + "type": "turn" + }, + "name": "Schmalkaldener Straße", + "mode": "driving", + "weight": 67, + "duration": 67, + "distance": 432.1 + }, + { + "intersections": [ + { + "out": 1, + "in": 2, + "entry": [false, true, false], + "bearings": [0, 180, 270], + "location": [11.584371, 48.186885] + }, + { + "out": 2, + "in": 0, + "entry": [false, false, true], + "bearings": [0, 150, 180], + "location": [11.584381, 48.186715] + }, + { + "out": 1, + "in": 0, + "entry": [false, true, true], + "bearings": [0, 180, 270], + "location": [11.584506, 48.185225] + }, + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "right" + ] + } + ], + "out": 2, + "in": 0, + "entry": [false, true, true, true], + "bearings": [0, 75, 180, 270], + "location": [11.58458, 48.184313] + }, + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "right" + ] + } + ], + "out": 2, + "in": 0, + "entry": [false, true, true, true], + "bearings": [0, 90, 180, 270], + "location": [11.584821, 48.181732] + }, + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + } + ], + "out": 2, + "in": 0, + "entry": [false, true, true], + "bearings": [0, 90, 180], + "location": [11.584973, 48.18015] + }, + { + "out": 1, + "in": 0, + "entry": [false, true, false], + "bearings": [0, 180, 270], + "location": [11.585106, 48.178587] + }, + { + "lanes": [ + { + "valid": true, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "right" + ] + } + ], + "out": 2, + "in": 0, + "entry": [false, false, true, true], + "bearings": [15, 90, 195, 270], + "location": [11.585104, 48.177692] + } + ], + "driving_side": "right", + "maneuver": { + "bearing_after": 177, + "bearing_before": 87, + "location": [11.584371, 48.186885], + "modifier": "right", + "type": "end of road" + }, + "geometry": "aobeHiqueA`@A\\ChDMd@Az@ElCIHA^A^Cp@CF?fFUz@EhBIF?RANAh@CbCMbAETAJAV?lCIhDQ`AE\\C\\AZ@F@HDFBJDJBXDPB", + "ref": "B 13", + "name": "Ingolstädter Straße", + "mode": "driving", + "weight": 112.1, + "duration": 112.1, + "distance": 1063.9 + }, + { + "intersections": [ + { + "out": 2, + "in": 0, + "entry": [false, true, true, true, false], + "bearings": [15, 75, 90, 180, 270], + "location": [11.585001, 48.177346] + }, + { + "lanes": [ + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + } + ], + "out": 1, + "in": 3, + "entry": [false, true, false, false], + "bearings": [15, 75, 180, 270], + "location": [11.585474, 48.177353] + }, + { + "lanes": [ + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "right" + ] + } + ], + "out": 0, + "in": 1, + "entry": [true, false, false], + "bearings": [90, 255, 315], + "location": [11.586131, 48.177456] + } + ], + "driving_side": "right", + "geometry": "ms`eHguueAD]?O?OE_@Kk@Ca@Eu@D_BF{AHkALqALgAPgAHe@Ha@Ps@Rs@Jc@J_@", + "maneuver": { + "bearing_after": 90, + "bearing_before": 191, + "location": [11.585001, 48.177346], + "modifier": "left", + "type": "on ramp" + }, + "name": "Schenkendorfstraße", + "mode": "driving", + "weight": 35.8, + "duration": 35.8, + "distance": 375.2 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "slight right" + ] + } + ], + "out": 0, + "in": 2, + "entry": [true, true, false], + "bearings": [120, 135, 300], + "location": [11.589803, 48.176704] + } + ], + "driving_side": "right", + "geometry": "ko`eHgsveAF[XaAZiA^mALe@@Y", + "maneuver": { + "bearing_after": 118, + "bearing_before": 116, + "location": [11.589803, 48.176704], + "modifier": "slight left", + "type": "fork" + }, + "name": "Schenkendorfstraße", + "mode": "driving", + "weight": 11.8, + "duration": 11.8, + "distance": 131.4 + }, + { + "intersections": [ + { + "out": 0, + "in": 1, + "entry": [true, false, false], + "bearings": [122, 297, 302], + "location": [11.591352, 48.176148] + }, + { + "out": 0, + "in": 2, + "entry": [true, false, false], + "bearings": [120, 285, 300], + "location": [11.592029, 48.17586] + }, + { + "lanes": [ + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "slight right" + ] + } + ], + "out": 0, + "in": 2, + "entry": [true, true, false], + "bearings": [120, 135, 300], + "location": [11.594022, 48.174977] + }, + { + "out": 2, + "in": 1, + "entry": [false, false, true], + "bearings": [14, 21, 205], + "location": [11.599736, 48.170666] + }, + { + "out": 1, + "in": 0, + "entry": [false, true, true], + "bearings": [30, 210, 225], + "location": [11.598911, 48.169478] + }, + { + "out": 2, + "in": 1, + "entry": [false, false, true], + "bearings": [15, 30, 210], + "location": [11.597915, 48.168028] + }, + { + "out": 1, + "in": 0, + "entry": [false, true], + "bearings": [30, 210], + "location": [11.59692, 48.166605] + }, + { + "out": 0, + "in": 1, + "entry": [true, false], + "bearings": [165, 345], + "location": [11.596001, 48.163978] + }, + { + "out": 0, + "in": 2, + "entry": [true, false, false], + "bearings": [135, 300, 315], + "location": [11.597365, 48.162396] + }, + { + "out": 0, + "in": 2, + "entry": [true, true, false], + "bearings": [135, 150, 315], + "location": [11.599799, 48.161034] + }, + { + "out": 0, + "in": 2, + "entry": [true, false, false], + "bearings": [135, 240, 315], + "location": [11.600215, 48.160767] + }, + { + "out": 0, + "in": 2, + "entry": [true, true, false], + "bearings": [135, 165, 330], + "location": [11.602935, 48.15794] + }, + { + "out": 0, + "in": 2, + "entry": [true, false, false], + "bearings": [120, 285, 300], + "location": [11.60442, 48.157119] + }, + { + "out": 0, + "in": 2, + "entry": [true, true, false], + "bearings": [120, 135, 300], + "location": [11.611708, 48.154071] + }, + { + "out": 0, + "in": 1, + "entry": [true, false], + "bearings": [135, 315], + "location": [11.613781, 48.152885] + } + ], + "driving_side": "right", + "maneuver": { + "bearing_after": 122, + "bearing_before": 115, + "location": [11.591352, 48.176148], + "modifier": "slight left", + "type": "merge" + }, + "geometry": "}k`eH}|veAx@gCfAcDrA{DRm@Pw@l@aBdAkCz@uBx@qBjAsCTk@jCuG^w@Ve@JOHKNOLMPMTKNGXINAPAP?N@VB\\Jz@`@v@f@~A~@tA|@r@`@LHNJnElChFbDp@b@rC`BdDjA~ATvAEZEREf@Mh@Wb@Wv@o@d@c@d@q@l@gAhAaC~AsDfBoDr@sA|@sA\\a@Z_@p@q@HIbAu@rBwAd@[`Ay@b@a@X[TYLQRWNW\\m@Xo@^}@Xy@La@FSL_@xBoHz@qCZaALa@`AeDb@wA\\kAx@oCb@qA\\cAt@sBt@sBfAoCh@iAl@mAjAuBdAiBz@uA", + "ref": "B 2R", + "name": "Schenkendorfstraße", + "mode": "driving", + "weight": 285.8, + "duration": 285.8, + "distance": 3685.4 + }, + { + "intersections": [ + { + "out": 0, + "in": 1, + "entry": [true, false], + "bearings": [135, 315], + "location": [11.614743, 48.152244] + }, + { + "out": 0, + "in": 2, + "entry": [true, false, false], + "bearings": [165, 330, 345], + "location": [11.615995, 48.150723] + } + ], + "driving_side": "right", + "maneuver": { + "bearing_after": 135, + "bearing_before": 135, + "location": [11.614743, 48.152244], + "modifier": "straight", + "type": "new name" + }, + "geometry": "ov{dHco{eAHONULQLONQLM^[j@e@XQ\\QZQ\\M\\MXKf@Kn@Kd@E^E", + "ref": "B 2R", + "name": "Richard-Strauss-Straße", + "mode": "driving", + "weight": 22.3, + "duration": 22.3, + "distance": 299.5 + }, + { + "intersections": [ + { + "out": 1, + "in": 0, + "entry": [false, true], + "bearings": [0, 180], + "location": [11.61624, 48.1498] + }, + { + "out": 1, + "in": 0, + "entry": [false, true, true], + "bearings": [0, 165, 180], + "location": [11.614595, 48.137999] + } + ], + "driving_side": "right", + "maneuver": { + "bearing_after": 180, + "bearing_before": 172, + "location": [11.61624, 48.1498], + "modifier": "straight", + "type": "new name" + }, + "geometry": "gg{dHox{eA`@?rA?~@@X?T?Z@lADfCTjJdA|@Jj@DfBPp[rCjDXnAJvBFZCzHeAxA_@l@Qt@[pAi@", + "ref": "B 2R", + "name": "Richard-Strauss-Tunnel", + "mode": "driving", + "weight": 124.1, + "duration": 124.1, + "distance": 1653.9 + }, + { + "intersections": [ + { + "out": 0, + "in": 2, + "entry": [true, false, false], + "bearings": [165, 315, 345], + "location": [11.615548, 48.135064] + }, + { + "out": 1, + "in": 0, + "entry": [false, true, true], + "bearings": [0, 180, 195], + "location": [11.616365, 48.133153] + }, + { + "out": 1, + "in": 0, + "entry": [false, true], + "bearings": [15, 195], + "location": [11.615923, 48.131602] + } + ], + "driving_side": "right", + "maneuver": { + "bearing_after": 160, + "bearing_before": 160, + "location": [11.615548, 48.135064], + "modifier": "straight", + "type": "new name" + }, + "geometry": "ckxdHet{eALGzGiCRGVERCR?TAD?`@BH@xBh@rBj@lA^", + "ref": "B 2R", + "name": "Leuchtenbergring", + "mode": "driving", + "weight": 33.4, + "duration": 33.4, + "distance": 443.8 + }, + { + "intersections": [ + { + "out": 1, + "in": 0, + "entry": [false, true], + "bearings": [15, 195], + "location": [11.615761, 48.131208] + } + ], + "driving_side": "right", + "maneuver": { + "bearing_after": 194, + "bearing_before": 194, + "location": [11.615761, 48.131208], + "modifier": "straight", + "type": "new name" + }, + "geometry": "aswdHou{eA|ErAf@J", + "ref": "B 2R", + "name": "Innsbrucker-Ring-Tunnel", + "mode": "driving", + "weight": 11.2, + "duration": 11.2, + "distance": 149.6 + }, + { + "intersections": [ + { + "out": 2, + "in": 0, + "entry": [false, true, true], + "bearings": [15, 180, 210], + "location": [11.615282, 48.129902] + } + ], + "driving_side": "right", + "geometry": "{jwdHor{eA~AdAhCvAnCxA`Ab@t@X", + "maneuver": { + "bearing_after": 205, + "bearing_before": 192, + "location": [11.615282, 48.129902], + "modifier": "slight right", + "type": "off ramp" + }, + "name": "", + "mode": "driving", + "weight": 27, + "duration": 27, + "distance": 300.1 + }, + { + "intersections": [ + { + "out": 2, + "in": 1, + "entry": [false, false, true], + "bearings": [0, 15, 195], + "location": [11.613727, 48.127414] + }, + { + "out": 2, + "in": 0, + "entry": [false, true, true, true], + "bearings": [15, 105, 195, 285], + "location": [11.613613, 48.127108] + } + ], + "driving_side": "right", + "geometry": "i{vdHyh{eA^JD@JDHBJBD@d@NvA\\|@Lf@FF@\\Bh@Dh@BtAHJ@P@", + "maneuver": { + "bearing_after": 194, + "bearing_before": 198, + "location": [11.613727, 48.127414], + "modifier": "straight", + "type": "turn" + }, + "name": "Ampfingstraße", + "mode": "driving", + "weight": 31.4, + "duration": 31.4, + "distance": 307.5 + }, + { + "intersections": [ + { + "out": 2, + "in": 0, + "entry": [false, true, true, true], + "bearings": [0, 90, 180, 270], + "location": [11.613091, 48.124689] + }, + { + "out": 2, + "in": 0, + "entry": [false, true, true], + "bearings": [0, 105, 180], + "location": [11.612954, 48.123397] + }, + { + "out": 1, + "in": 0, + "entry": [false, true, true], + "bearings": [0, 180, 270], + "location": [11.612939, 48.123269] + }, + { + "out": 2, + "in": 0, + "entry": [false, true, true, true], + "bearings": [0, 90, 180, 270], + "location": [11.612878, 48.122584] + }, + { + "out": 2, + "in": 0, + "entry": [false, true, true, true], + "bearings": [0, 90, 180, 270], + "location": [11.612861, 48.122308] + } + ], + "driving_side": "right", + "geometry": "ijvdHyd{eAJ@r@B`ETX@P@t@D`ABX@Z@\\?b@?b@Ad@@T?z@?T?L?X@", + "maneuver": { + "bearing_after": 182, + "bearing_before": 184, + "location": [11.613091, 48.124689], + "modifier": "straight", + "type": "new name" + }, + "name": "Aschheimer Straße", + "mode": "driving", + "weight": 44.9, + "duration": 44.9, + "distance": 422.8 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": false, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "none" + ] + }, + { + "valid": true, + "indications": [ + "none" + ] + } + ], + "out": 3, + "in": 0, + "entry": [false, false, true, true], + "bearings": [0, 90, 180, 285], + "location": [11.612849, 48.120892] + } + ], + "driving_side": "right", + "geometry": "qrudHic{eAC`@IhBGvBGfCC`C?ZAfBB~CJbEFvBFnC@VD^", + "maneuver": { + "bearing_after": 277, + "bearing_before": 180, + "location": [11.612849, 48.120892], + "modifier": "right", + "type": "turn" + }, + "name": "Anzinger Straße", + "mode": "driving", + "weight": 46.8, + "duration": 46.8, + "distance": 498.3 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": true, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "right" + ] + } + ], + "out": 2, + "in": 0, + "entry": [false, false, true, true], + "bearings": [90, 135, 255, 315], + "location": [11.606184, 48.120874] + }, + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "right" + ] + } + ], + "out": 2, + "in": 0, + "entry": [false, true, true, false], + "bearings": [75, 150, 240, 315], + "location": [11.605843, 48.120813] + }, + { + "out": 2, + "in": 1, + "entry": [false, false, true], + "bearings": [45, 60, 240], + "location": [11.605401, 48.120687] + }, + { + "out": 1, + "in": 0, + "entry": [false, true, true], + "bearings": [75, 255, 345], + "location": [11.602518, 48.120034] + }, + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "right" + ] + } + ], + "out": 2, + "in": 0, + "entry": [false, true, true, true], + "bearings": [75, 165, 255, 345], + "location": [11.60013, 48.119533] + }, + { + "out": 2, + "in": 0, + "entry": [false, true, true], + "bearings": [75, 165, 255], + "location": [11.598066, 48.119071] + }, + { + "out": 3, + "in": 1, + "entry": [true, false, true, true], + "bearings": [15, 75, 165, 240], + "location": [11.595294, 48.118425] + } + ], + "driving_side": "right", + "geometry": "mrudHsyyeABTFl@DZPz@R~@Tv@Hr@NlAv@~G?HFZ@LBN?F^tCHn@Fd@Hf@D^DZJx@BRDXD^@NLz@PtAVdBFb@Hf@Hf@Jp@DVDVHr@Lx@l@lENfAPdAXvA`@dC", + "maneuver": { + "bearing_after": 254, + "bearing_before": 262, + "location": [11.606184, 48.120874], + "modifier": "straight", + "type": "new name" + }, + "name": "Sankt-Martin-Straße", + "mode": "driving", + "weight": 100.8, + "duration": 100.8, + "distance": 945.7 + }, + { + "intersections": [ + { + "out": 1, + "in": 0, + "entry": [false, true, true], + "bearings": [75, 165, 255], + "location": [11.594178, 48.118127] + } + ], + "driving_side": "right", + "geometry": "iaudHsnweAPC^ITELCh@Al@Bp@DfBH", + "maneuver": { + "bearing_after": 168, + "bearing_before": 247, + "location": [11.594178, 48.118127], + "modifier": "left", + "type": "turn" + }, + "name": "Hohenwaldeckstraße", + "mode": "driving", + "weight": 27.4, + "duration": 27.4, + "distance": 183.5 + }, + { + "intersections": [ + { + "in": 0, + "entry": [true], + "bearings": [4], + "location": [11.594214, 48.116487] + } + ], + "driving_side": "right", + "geometry": "awtdHynweA", + "maneuver": { + "bearing_after": 0, + "bearing_before": 184, + "location": [11.594214, 48.116487], + "modifier": "left", + "type": "arrive" + }, + "name": "Hohenwaldeckstraße", + "mode": "driving", + "weight": 0, + "duration": 0, + "distance": 0 + } + ], + "weight": 1019.7, + "summary": "Isarring, Richard-Strauss-Tunnel", + "duration": 1019.7, + "distance": 11116.5 + } + ], + "weight_name": "routability", + "geometry": "sfbeH_rteAEzDuG[Lic@rz@}BN{P~EyTfZkt@bDC`d@bWtKiB|NkXxPiPt^ccA|MuJ`jA~H`_@gJjh@|Qja@bBAtg@jMr_A|AjJfIE", + "weight": 1019.7, + "duration": 1019.7, + "distance": 11116.5 + } + ], + "waypoints": [ + { + "hint": "7VEViP___38IAAAACgAAACAAAABmAAAA16KyQIr6mD9w-qdBPiiJQggAAAAKAAAAIAAAAGYAAACLGwEA4K-wAMdA3wLvr7AAlUHfAgYADxEAAAAA", + "location": [11.57936, 48.185543], + "name": "Vogelhartstraße", + "distance": 22.93305775 + }, + { + "hint": "oDEBgP___39XAAAAXAAAALsAAAAlAAAA4t1qQtUpMkCvevlCiIDIQVcAAABcAAAAuwAAACUAAACLGwEA5umwAAcz3gJS6rAAAjPeAg4AfwsAAAAA", + "location": [11.594214, 48.116487], + "name": "Hohenwaldeckstraße", + "distance": 8.059248837 + } + ] +} \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/overpass/Overpass.kt b/common/data/src/main/java/com/kouros/navigation/data/overpass/Overpass.kt index c676cdc..aeb8d10 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/overpass/Overpass.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/overpass/Overpass.kt @@ -2,9 +2,8 @@ package com.kouros.navigation.data.overpass import android.location.Location import com.google.gson.GsonBuilder -import com.kouros.navigation.utils.GeoUtils.getBoundingBox2 import com.kouros.navigation.utils.GeoUtils.getOverpassBbox -import com.kouros.navigation.utils.NavigationUtils +import kotlinx.serialization.json.Json import java.io.OutputStreamWriter import java.net.HttpURLConnection import java.net.URL @@ -12,8 +11,33 @@ import java.net.URL class Overpass { val overpassUrl = "https://overpass.kumi.systems/api/interpreter" - fun getAmenities(type: String, category: String, location: Location) : List { - val boundingBox = getOverpassBbox(location, 5.0) + fun getAround(radius: Int, linestring: String) : List { + val httpURLConnection = URL(overpassUrl).openConnection() as HttpURLConnection + httpURLConnection.requestMethod = "POST" + httpURLConnection.setRequestProperty( + "Accept", + "application/json" + ) + httpURLConnection.setDoOutput(true); + // define search query + val searchQuery = """ + |[out:json]; + |( + | way[highway](around:$radius,$linestring) + | ; + |); + |out body; + """.trimMargin() + return overpassApi(httpURLConnection, searchQuery) + } + + fun getAmenities( + type: String, + category: String, + location: Location, + radius: Double + ): List { + val boundingBox = getOverpassBbox(location, radius) val httpURLConnection = URL(overpassUrl).openConnection() as HttpURLConnection httpURLConnection.requestMethod = "POST" httpURLConnection.setRequestProperty( @@ -32,8 +56,11 @@ class Overpass { |); |out body; """.trimMargin() + return overpassApi(httpURLConnection, searchQuery) + } - // Send the JSON we created + fun overpassApi(httpURLConnection: HttpURLConnection, searchQuery: String) : List { + // Send the JSON we created val outputStreamWriter = OutputStreamWriter(httpURLConnection.outputStream) outputStreamWriter.write(searchQuery) outputStreamWriter.flush() @@ -44,9 +71,9 @@ class Overpass { .use { it.readText() } // defaults to UTF-8 val gson = GsonBuilder().serializeNulls().create() val overpass = gson.fromJson(response, Amenity::class.java) - println("Overpass: $type $response") + //println("Overpass: $response") return overpass.elements } - return emptyList() + return emptyList() } } \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/valhalla/ValhallaRepository.kt b/common/data/src/main/java/com/kouros/navigation/data/valhalla/ValhallaRepository.kt new file mode 100644 index 0000000..5ec0274 --- /dev/null +++ b/common/data/src/main/java/com/kouros/navigation/data/valhalla/ValhallaRepository.kt @@ -0,0 +1,29 @@ +package com.kouros.navigation.data.valhalla + +import android.location.Location +import com.kouros.navigation.data.Locations +import com.kouros.navigation.data.NavigationRepository +import com.kouros.navigation.data.SearchFilter +import com.kouros.navigation.data.ValhallaLocation +import kotlinx.serialization.json.Json + +private const val routeUrl = "https://kouros-online.de/valhalla/route?json=" +class ValhallaRepository : NavigationRepository() { + + override fun getRoute(currentLocation: Location, location: Location, searchFilter: SearchFilter): String { + SearchFilter + val vLocation = listOf( + Locations(lat = currentLocation.latitude, lon = currentLocation.longitude, search_filter = searchFilter), + Locations(lat = location.latitude, lon = location.longitude, search_filter = searchFilter) + ) + val valhallaLocation = ValhallaLocation( + locations = vLocation, + costing = "auto", + units = "km", + id = "my_work_route", + language = "de-DE" + ) + val routeLocation = Json.encodeToString(valhallaLocation) + return fetchUrl(routeUrl + routeLocation, true) + } +} \ No newline at end of file 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 9a766b9..edaa0ae 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 @@ -4,16 +4,16 @@ import android.location.Location import androidx.car.app.navigation.model.Maneuver import androidx.car.app.navigation.model.Step import com.kouros.data.R -import com.kouros.navigation.data.Constants -import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD import com.kouros.navigation.data.ManeuverType import com.kouros.navigation.data.Place import com.kouros.navigation.data.Route import com.kouros.navigation.data.StepData import com.kouros.navigation.utils.location -import org.maplibre.turf.TurfMeasurement -import org.maplibre.turf.TurfMisc +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import java.util.concurrent.TimeUnit import kotlin.math.roundToInt @@ -21,14 +21,19 @@ open class RouteModel() { data class RouteState( val route: Route? = null, val isNavigating: Boolean = false, - var destination: Place = Place(), + val destination: Place = Place(), val arrived: Boolean = false, - var maneuverType: Int = 0, + val maneuverType: Int = 0, var currentShapeIndex: Int = 0, var distanceToStepEnd: Float = 0F, var beginIndex: Int = 0, - var endIndex: Int = 0 - ) + var endIndex: Int = 0, + val travelMessage: String = "", + // max speed for street (maneuver) + val lastSpeedIndex: Int = 0, + val maxSpeed: Int = 0, + + ) var routeState = RouteState() @@ -61,7 +66,8 @@ open class RouteModel() { ) } - fun updateLocation(location: Location) { + @OptIn(DelicateCoroutinesApi::class) + fun updateLocation(location: Location, viewModel: ViewModel) { var nearestDistance = 100000.0f var newShapeIndex = -1 // find nearest waypoint and current shape index @@ -77,6 +83,24 @@ open class RouteModel() { // find maneuver // calculate distance to step end findManeuver(newShapeIndex) + + GlobalScope.launch(Dispatchers.IO) { + updateSpeedLimit(location, viewModel) + } + } + + fun updateSpeedLimit(location: Location, viewModel: ViewModel) { + // speed limit for each maneuver index + if (routeState.lastSpeedIndex < route.currentManeuverIndex) { + routeState = routeState.copy(lastSpeedIndex = route.currentManeuverIndex) + val elements = viewModel.getMaxSpeed(location) + elements.forEach { + if (it.tags.name != null && it.tags.maxspeed != null) { + val speed = it.tags.maxspeed!!.toInt() + routeState = routeState.copy(maxSpeed = speed) + } + } + } } private fun findManeuver(newShapeIndex: Int) { @@ -127,7 +151,7 @@ open class RouteModel() { maneuverType = relevantManeuver.type } val maneuverIconPair = maneuverIcon(maneuverType) - routeState.maneuverType = maneuverIconPair.first + routeState = routeState.copy(maneuverType = maneuverIconPair.first) // Construct and return the final StepData object return StepData( streetName, @@ -149,6 +173,7 @@ open class RouteModel() { when (distanceLeft) { in 0.0..NEXT_STEP_THRESHOLD -> { } + else -> { if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) { text = maneuver.streetNames[0] @@ -296,8 +321,8 @@ open class RouteModel() { fun hasArrived(type: Int): Boolean { - // return leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE && type == ManeuverType.DestinationRight.value - return type == ManeuverType.DestinationRight.value + // return leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE && type == ManeuverType.DestinationRight.value + return type == ManeuverType.DestinationRight.value || type == ManeuverType.Destination.value || type == ManeuverType.DestinationLeft.value } diff --git a/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt b/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt index 9635697..e6a4d26 100644 --- a/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt +++ b/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt @@ -251,7 +251,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { fun getAmenities(category: String, location: Location) { viewModelScope.launch(Dispatchers.IO) { - val amenities = Overpass().getAmenities("amenity", category, location) + val amenities = Overpass().getAmenities("amenity", category, location, 5.0) val distAmenities = mutableListOf() amenities.forEach { val plLocation = @@ -267,7 +267,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { fun getSpeedCameras(location: Location) { viewModelScope.launch(Dispatchers.IO) { - val amenities = Overpass().getAmenities("highway", "speed_camera", location) + val amenities = Overpass().getAmenities("highway", "speed_camera", location, 5.0) val distAmenities = mutableListOf() amenities.forEach { val plLocation = @@ -281,6 +281,12 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { } } + fun getMaxSpeed(location: Location) : List { + val lineString = "${location.latitude},${location.longitude}" + val amenities = Overpass().getAround(10, lineString) + return amenities + } + fun saveFavorite(place: Place) { place.category = Constants.FAVORITES savePlace(place) 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 c206822..791b991 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 @@ -74,10 +74,10 @@ fun calculateZoom(speed: Double?): Double { val speedKmh = (speed * 3.6).toInt() val zoom = when (speedKmh) { in 0..10 -> 18.0 - in 11..30 -> 17.0 - in 31..50 -> 16.0 - in 61..70 -> 15.0 - else -> 14 + in 11..30 -> 17.5 + in 31..50 -> 17.0 + in 61..70 -> 16.5 + else -> 16.0 } return zoom.toDouble() } diff --git a/common/data/src/main/res/drawable/warning_24px.xml b/common/data/src/main/res/drawable/warning_24px.xml new file mode 100644 index 0000000..3e981e7 --- /dev/null +++ b/common/data/src/main/res/drawable/warning_24px.xml @@ -0,0 +1,10 @@ + + +