From e2740110809e5e42a6d623264948e8611bea3117 Mon Sep 17 00:00:00 2001 From: Dimitris Date: Sat, 10 Jan 2026 12:48:41 +0100 Subject: [PATCH] Diverse --- app/build.gradle.kts | 6 +- .../com/kouros/navigation/MainApplication.kt | 4 +- .../com/kouros/navigation/ui/MainActivity.kt | 66 +- .../java/com/kouros/navigation/ui/MapView.kt | 3 +- .../kouros/navigation/ui/NavigationScreen.kt | 14 +- .../com/kouros/navigation/ui/SearchSheet.kt | 54 +- .../navigation/car/NavigationSession.kt | 64 +- .../kouros/navigation/car/SurfaceRenderer.kt | 3 +- .../car/navigation/RouteCarModel.kt | 9 +- .../navigation/car/screen/NavigationScreen.kt | 19 +- .../car/screen/NavigationSettings.kt | 28 +- .../navigation/car/screen/PlaceListScreen.kt | 5 - .../navigation/car/screen/RoutingSettings.kt | 8 +- .../java/com/kouros/navigation/car/Route.json | 255 ------- .../java/com/kouros/navigation/data/Data.kt | 40 +- .../navigation/data/NavigationRepository.kt | 14 +- .../java/com/kouros/navigation/data/Route.kt | 48 +- .../navigation/data/osrm/OsrmRepository.kt | 10 +- .../kouros/navigation/data/osrm/OsrmRoute.kt | 101 ++- .../com/kouros/navigation/data/osrm/Steps.kt | 2 +- .../com/kouros/navigation/data/osrm/osrm.json | 129 +++- .../kouros/navigation/data/route/Maneuver.kt | 3 + .../data/valhalla/ValhallaRepository.kt | 14 +- .../navigation/data/valhalla/ValhallaRoute.kt | 6 +- .../kouros/navigation/model/BaseStyleModel.kt | 1 - .../com/kouros/navigation/model/RouteModel.kt | 124 ++-- .../com/kouros/navigation/model/ViewModel.kt | 9 +- .../com/kouros/navigation/utils/GeoUtils.kt | 24 +- .../navigation/utils/NavigationUtils.kt | 2 +- common/data/src/main/res/drawable/none.png | Bin 0 -> 4759 bytes common/data/src/main/res/raw/hv.gpx | 693 ++++++++++++++++++ common/data/src/main/res/raw/vh.gpx | 678 +++++++++++++++++ .../data/src/main/res/values-de/strings.xml | 1 + common/data/src/main/res/values/strings.xml | 7 +- settings.gradle.kts | 4 + 35 files changed, 1877 insertions(+), 571 deletions(-) delete mode 100644 common/car/src/test/java/com/kouros/navigation/car/Route.json create mode 100644 common/data/src/main/res/drawable/none.png create mode 100644 common/data/src/main/res/raw/hv.gpx create mode 100644 common/data/src/main/res/raw/vh.gpx diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bfdd12e..2a261df 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 = 18 - versionName = "0.1.3.18" + versionCode = 23 + versionName = "0.1.3.23" base.archivesName = "navi-$versionName" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -94,7 +94,7 @@ dependencies { implementation(libs.androidx.compose.ui.graphics) implementation(libs.androidx.window) implementation(libs.androidx.compose.foundation.layout) - + implementation("com.github.ticofab:android-gpx-parser:2.3.1") testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/main/java/com/kouros/navigation/MainApplication.kt b/app/src/main/java/com/kouros/navigation/MainApplication.kt index bb254e9..bad399b 100644 --- a/app/src/main/java/com/kouros/navigation/MainApplication.kt +++ b/app/src/main/java/com/kouros/navigation/MainApplication.kt @@ -5,7 +5,7 @@ import android.content.Context import com.kouros.navigation.data.ObjectBox import com.kouros.navigation.di.appModule import com.kouros.navigation.model.ViewModel -import com.kouros.navigation.utils.NavigationUtils.getRouteEngine +import com.kouros.navigation.utils.NavigationUtils.getViewModel import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.startKoin @@ -17,7 +17,7 @@ class MainApplication : Application() { super.onCreate() ObjectBox.init(this); appContext = applicationContext - navigationViewModel = getRouteEngine(appContext!!) + navigationViewModel = getViewModel(appContext!!) startKoin { androidLogger(Level.DEBUG) androidContext(this@MainApplication) 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 24a2fde..483e183 100644 --- a/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt +++ b/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt @@ -4,6 +4,7 @@ import NavigationSheet import android.Manifest import android.annotation.SuppressLint import android.app.AppOpsManager +import android.content.Context import android.location.LocationManager import android.os.Bundle import android.os.Process @@ -38,6 +39,7 @@ 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.MainApplication.Companion.navigationViewModel import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE @@ -51,10 +53,14 @@ import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue import com.kouros.navigation.utils.bearing import com.kouros.navigation.utils.calculateZoom import com.kouros.navigation.utils.location +import io.ticofab.androidgpxparser.parser.GPXParser +import io.ticofab.androidgpxparser.parser.domain.Gpx +import io.ticofab.androidgpxparser.parser.domain.TrackSegment import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import org.joda.time.DateTime import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.location.DesiredAccuracy import org.maplibre.compose.location.Location @@ -84,6 +90,7 @@ class MainActivity : ComponentActivity() { routeData.value = routeModel.route.routeGeoJson simulate() //test() + //gpx(applicationContext) } } val cameraPosition = MutableLiveData( @@ -199,6 +206,7 @@ class MainActivity : ComponentActivity() { applicationContext, userLocationState, step, + nextStep, cameraPosition, routeData, tilt, @@ -244,11 +252,11 @@ class MainActivity : ComponentActivity() { if (route.currentStep + 1 <= legs.steps.size) { nextStepData.value = nextStep() } - if (routeState.maneuverType == 39 + if (maneuverType in 39..42 && leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE ) { // stopNavigation() - routeState = routeState.copy(arrived = true) + arrived = true routeData.value = "" } } @@ -270,10 +278,15 @@ class MainActivity : ComponentActivity() { } fun stopNavigation(closeSheet: () -> Unit) { + val latitude = routeModel.route.waypoints!![0][1] + val longitude = routeModel.route.waypoints!![0][0] closeSheet() routeModel.stopNavigation() + if (useMock) { + mock.setMockLocation(latitude, longitude) + } routeData.value = "" - stepData.value = StepData("", 0.0, 0, 0,0, 0.0) + stepData.value = StepData("", 0.0, 0, 0, 0, 0.0) } fun simulateNavigation() { @@ -306,14 +319,13 @@ class MainActivity : ComponentActivity() { fun simulate() { CoroutineScope(Dispatchers.IO).launch { - if (routeModel.isNavigating()) { - for ((index, waypoint) in routeModel.route.waypoints!!.withIndex()) { + for ((index, waypoint) in routeModel.route.waypoints!!.withIndex()) { + if (routeModel.isNavigating()) { var deviation = 0.0 - //if (index in 0..350 ) { + if (index in 0..routeModel.route.waypoints!!.size) { mock.setMockLocation(waypoint[1] + deviation, waypoint[0]) - delay(500L) // - // } + } } } } @@ -321,14 +333,44 @@ class MainActivity : ComponentActivity() { fun test() { for ((index, step) in routeModel.legs.steps.withIndex()) { - println("${step.maneuver.waypoints.size}") for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) { routeModel.updateLocation(location(waypoint[0], waypoint[1]), navigationViewModel) - routeModel.currentStep() + val step = routeModel.currentStep() + println("Street: ${step.instruction} Dist: ${step.leftStepDistance} ${step.currentManeuverType}") if (index + 1 <= routeModel.legs.steps.size) { - nextStepData.value = routeModel.nextStep() + //nextStepData.value = routeModel.nextStep() + } + } + } + } + + fun gpx(context: Context) { + CoroutineScope(Dispatchers.IO).launch { + val parser = GPXParser() + val input = context.resources.openRawResource(R.raw.vh) + val parsedGpx: Gpx? = parser.parse(input) // consider using a background thread + parsedGpx?.let { + val tracks = parsedGpx.tracks + tracks.forEach { tr -> + val segments: MutableList? = tr.trackSegments + segments!!.forEach { seg -> + var lastTime = DateTime.now() + seg!!.trackPoints.forEach { p -> + val ext = p.extensions + val speed: Double? + if (ext != null) { + speed = ext.speed + mock.curSpeed = speed.toFloat() + } + val duration = p.time.millis - lastTime.millis + mock.setMockLocation(p.latitude, p.longitude) + if (duration > 0) { + delay(duration / 5) + } + lastTime = p.time + } + } } - println(routeModel.routeState.maneuverType) } } } 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 893f549..6dc4a3d 100644 --- a/app/src/main/java/com/kouros/navigation/ui/MapView.kt +++ b/app/src/main/java/com/kouros/navigation/ui/MapView.kt @@ -29,6 +29,7 @@ fun MapView( applicationContext: Context, userLocationState: UserLocationState, step: StepData?, + nextStep: StepData?, cameraPosition: MutableLiveData, routeData: MutableLiveData, tilt: Double, @@ -57,7 +58,7 @@ fun MapView( val rememberBaseStyle = rememberBaseStyle( baseStyle) Column { - NavigationInfo(step) + NavigationInfo(step, nextStep) Box(contentAlignment = Alignment.Center) { MapLibre( applicationContext, diff --git a/app/src/main/java/com/kouros/navigation/ui/NavigationScreen.kt b/app/src/main/java/com/kouros/navigation/ui/NavigationScreen.kt index 176f443..97dc688 100644 --- a/app/src/main/java/com/kouros/navigation/ui/NavigationScreen.kt +++ b/app/src/main/java/com/kouros/navigation/ui/NavigationScreen.kt @@ -18,7 +18,7 @@ import com.kouros.navigation.data.StepData import com.kouros.navigation.utils.round @Composable -fun NavigationInfo(step: StepData?) { +fun NavigationInfo(step: StepData?, nextStep: StepData?) { if (step != null && step.instruction.isNotEmpty()) { Card(modifier = Modifier.padding(top = 60.dp)) { Column() { @@ -39,11 +39,13 @@ fun NavigationInfo(step: StepData?) { } Text(text = step.instruction, fontSize = 20.sp) } - Icon( - painter = painterResource(step.icon), - contentDescription = stringResource(id = R.string.accept_action_title), - modifier = Modifier.size(48.dp, 48.dp), - ) + if (nextStep != null && step.icon != nextStep.icon) { + Icon( + painter = painterResource(nextStep.icon), + contentDescription = stringResource(id = R.string.accept_action_title), + modifier = Modifier.size(48.dp, 48.dp), + ) + } } } } diff --git a/app/src/main/java/com/kouros/navigation/ui/SearchSheet.kt b/app/src/main/java/com/kouros/navigation/ui/SearchSheet.kt index 22186ff..981633f 100644 --- a/app/src/main/java/com/kouros/navigation/ui/SearchSheet.kt +++ b/app/src/main/java/com/kouros/navigation/ui/SearchSheet.kt @@ -57,38 +57,31 @@ fun SearchSheet( if (search.value != null) { searchResults.addAll(search.value!!) } - Home(applicationContext, viewModel, location, closeSheet = { closeSheet() }) - if (searchResults.isNotEmpty()) { - val textFieldState = rememberTextFieldState() - val items = listOf(searchResults) - if (items.isNotEmpty()) { - SearchBar( - textFieldState = textFieldState, - searchPlaces = recentPlaces.value!!, - searchResults = searchResults, - viewModel = viewModel, - context = applicationContext, - location = location, - closeSheet = { closeSheet() } - ) - } - } + Home(applicationContext, viewModel, location, closeSheet = { closeSheet() }) if (recentPlaces.value != null) { - val textFieldState = rememberTextFieldState() val items = listOf(recentPlaces) if (items.isNotEmpty()) { - SearchBar( - textFieldState = textFieldState, - searchPlaces = recentPlaces.value!!, - searchResults = searchResults, - viewModel = viewModel, - context = applicationContext, - location = location, - closeSheet = { closeSheet() } - ) + RecentPlaces(recentPlaces.value!!, viewModel, applicationContext, location, closeSheet) } } + // if (searchResults.isNotEmpty()) { + val textFieldState = rememberTextFieldState() + val items = listOf(searchResults) + // if (items.isNotEmpty()) { + SearchBar( + textFieldState = textFieldState, + searchPlaces = emptyList(), + searchResults = searchResults, + viewModel = viewModel, + context = applicationContext, + location = location, + closeSheet = { closeSheet() } + + ) + // } + //} + } @@ -138,15 +131,7 @@ fun SearchBar( closeSheet: () -> Unit ) { var expanded by rememberSaveable { mutableStateOf(true) } - Box( - modifier - .fillMaxSize() - .semantics { isTraversalGroup = true } - ) { SearchBar( - modifier = Modifier - .align(Alignment.TopCenter) - .semantics { traversalIndex = 0f }, inputField = { SearchBarDefaults.InputField( leadingIcon = { @@ -179,7 +164,6 @@ fun SearchBar( SearchPlaces(searchResults, viewModel, context, location, closeSheet) } } - } } private fun searchPlaces(viewModel: ViewModel, location: Location, it: String) { 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 fa043e3..fc38880 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 @@ -30,17 +30,19 @@ import com.kouros.navigation.car.screen.NavigationScreen import com.kouros.navigation.car.screen.RequestPermissionScreen import com.kouros.navigation.car.screen.SearchScreen import com.kouros.navigation.data.Constants +import com.kouros.navigation.data.Constants.CAR_LOCATION import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION import com.kouros.navigation.data.Constants.MAXIMAL_SNAP_CORRECTION -import com.kouros.navigation.data.Constants.ROUTING_ENGINE import com.kouros.navigation.data.Constants.TAG import com.kouros.navigation.data.RouteEngine import com.kouros.navigation.data.osrm.OsrmRepository import com.kouros.navigation.data.valhalla.ValhallaRepository import com.kouros.navigation.model.BaseStyleModel import com.kouros.navigation.model.ViewModel +import com.kouros.navigation.utils.GeoUtils.snapLocation +import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue -import com.kouros.navigation.utils.NavigationUtils.getRouteEngine +import com.kouros.navigation.utils.NavigationUtils.getViewModel import org.maplibre.compose.style.BaseStyle class NavigationSession : Session(), NavigationScreen.Listener { @@ -54,33 +56,32 @@ class NavigationSession : Session(), NavigationScreen.Listener { lateinit var surfaceRenderer: SurfaceRenderer var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? -> - val routingEngine = getIntKeyValue(carContext, ROUTING_ENGINE) -// if (routingEngine == RouteEngine.VALHALLA.ordinal) { + val useCarLocation = getBooleanKeyValue(carContext, CAR_LOCATION) + if (!useCarLocation) { updateLocation(location!!) - // } + } } private val mLifeCycleObserver: LifecycleObserver = object : DefaultLifecycleObserver { override fun onCreate(owner: LifecycleOwner) { - Log.i(TAG, "In onCreate()") } override fun onResume(owner: LifecycleOwner) { - Log.i(TAG, "In onResume()") } override fun onPause(owner: LifecycleOwner) { - Log.i(TAG, "In onPause()") } override fun onStop(owner: LifecycleOwner) { - Log.i(TAG, "In onStop()") } override fun onDestroy(owner: LifecycleOwner) { - val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo - carSensors.removeCarHardwareLocationListener(carLocationListener) + val useCarLocation = getBooleanKeyValue(carContext, CAR_LOCATION) + if (useCarLocation) { + val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors + carSensors.removeCarHardwareLocationListener(carLocationListener) + } carInfo.removeSpeedListener(carSpeedListener) Log.i(TAG, "In onDestroy()") val locationManager = @@ -123,7 +124,7 @@ class NavigationSession : Session(), NavigationScreen.Listener { override fun onCreateScreen(intent: Intent): Screen { - navigationViewModel = getRouteEngine(carContext) + navigationViewModel = getViewModel(carContext) navigationViewModel.routingEngine.observe(this, ::onRoutingEngineStateUpdated) routeModel = RouteCarModel() @@ -167,13 +168,16 @@ class NavigationSession : Session(), NavigationScreen.Listener { } fun addSensors() { - val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo - carSensors.addCarHardwareLocationListener( - CarSensors.UPDATE_RATE_NORMAL, - carContext.mainExecutor, - carLocationListener - ) + val useCarLocation = getBooleanKeyValue(carContext, CAR_LOCATION) + if (useCarLocation) { + val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors + carSensors.addCarHardwareLocationListener( + CarSensors.UPDATE_RATE_FASTEST, + carContext.mainExecutor, + carLocationListener + ) + } carInfo.addSpeedListener(carContext.mainExecutor, carSpeedListener) } @@ -229,7 +233,7 @@ class NavigationSession : Session(), NavigationScreen.Listener { updateLocation(location) locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, - /* minTimeMs= */ 1000, + /* minTimeMs= */ 500, /* minDistanceM= */ 5f, mLocationListener ) @@ -239,16 +243,18 @@ class NavigationSession : Session(), NavigationScreen.Listener { fun updateLocation(location: Location) { if (routeModel.isNavigating()) { navigationScreen.updateTrip(location) - val wayPointLocation = routeModel.route.currentStep().wayPointLocation - val distance = location.distanceTo(wayPointLocation) - if (distance > MAXIMAL_ROUTE_DEVIATION) { - navigationScreen.calculateNewRoute(routeModel.routeState.destination) - return - } - if (distance < MAXIMAL_SNAP_CORRECTION) { - surfaceRenderer.updateLocation(wayPointLocation) - } else { - surfaceRenderer.updateLocation(location) + if (!routeModel.arrived) { + val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations()) + val distance = location.distanceTo(snapedLocation) + if (distance > MAXIMAL_ROUTE_DEVIATION) { + navigationScreen.calculateNewRoute(routeModel.destination) + return + } + if (distance < MAXIMAL_SNAP_CORRECTION) { + surfaceRenderer.updateLocation(snapedLocation) + } else { + surfaceRenderer.updateLocation(location) + } } } else { surfaceRenderer.updateLocation(location) 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 7813b3b..80f601f 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 @@ -170,6 +170,7 @@ class SurfaceRenderer( @Composable fun MapView() { + //println("DarkMode ${carContext.isDarkMode}") val position: CameraPosition? by cameraPosition.observeAsState() val route: String? by routeData.observeAsState() val speedCameras: String? by speedCamerasData.observeAsState() @@ -193,7 +194,7 @@ class SurfaceRenderer( DrawNavigationImages( paddingValues, currentSpeed, - routeModel.routeState.maxSpeed, + routeModel.maxSpeed, width, height ) 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 3badba5..7f53857 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 @@ -58,7 +58,7 @@ class RouteCarModel() : RouteModel() { .setIcon(createCarIcon(carContext, stepData.icon)) .build() ) - .setRoad(routeState.destination.street!!) + .setRoad(destination.street!!) if (stepData.lane.isNotEmpty()) { addLanes(carContext, step, stepData) } @@ -110,9 +110,9 @@ class RouteCarModel() : RouteModel() { .setRemainingTimeColor(CarColor.YELLOW) .setRemainingDistanceColor(CarColor.RED) - if (routeState.travelMessage.isNotEmpty()) { + if (travelMessage.isNotEmpty()) { travelBuilder.setTripIcon(createCarIcon(carContext, R.drawable.warning_24px)) - travelBuilder.setTripText(CarText.create(routeState.travelMessage)) + travelBuilder.setTripText(CarText.create(travelMessage)) } return travelBuilder.build() } @@ -235,8 +235,7 @@ class RouteCarModel() : RouteModel() { R.string.exit_action_title, R.string.exit_action_title, FLAG_DEFAULT ) - - return Alert.Builder( /* alertId: */0, title, /* durationMillis: */10000) + return Alert.Builder( /* alertId: */0, title, /* durationMillis: */5000) .setSubtitle(subtitle) .setIcon(icon) .addAction(dismissAction).setCallback(object : AlertCallback { 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 561c9ac..dbcdd15 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 @@ -141,11 +141,11 @@ class NavigationScreen( } private fun navigationEndTemplate(actionStripBuilder: ActionStrip.Builder): Template { - if (routeModel.routeState.arrived) { + if (routeModel.arrived) { val timer = object : CountDownTimer(8000, 1000) { override fun onTick(millisUntilFinished: Long) {} override fun onFinish() { - routeModel.routeState = routeModel.routeState.copy(arrived = false) + routeModel.arrived = false navigationType = NavigationType.VIEW invalidate() } @@ -164,8 +164,8 @@ class NavigationScreen( fun navigationArrivedTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate { var street = "" - if (routeModel.routeState.destination.street != null) { - street = routeModel.routeState.destination.street!! + if (routeModel.destination.street != null) { + street = routeModel.destination.street!! } return NavigationTemplate.Builder() .setNavigationInfo( @@ -298,7 +298,7 @@ class NavigationScreen( .setOnClickListener { val navigateTo = location(recentPlace.longitude, recentPlace.latitude) viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, navigateTo) - routeModel.routeState = routeModel.routeState.copy(destination = recentPlace) + routeModel.destination = recentPlace } .build() } @@ -417,7 +417,7 @@ class NavigationScreen( viewModel.saveRecent(place) currentNavigationLocation = location viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, location) - routeModel.routeState = routeModel.routeState.copy(destination = place) + routeModel.destination = place invalidate() } @@ -454,11 +454,14 @@ class NavigationScreen( updateSpeedCamera(surfaceRenderer.lastLocation) with(routeModel) { updateLocation(location, viewModel) - if (routeState.maneuverType == Maneuver.TYPE_DESTINATION + if ((maneuverType == Maneuver.TYPE_DESTINATION + || maneuverType == Maneuver.TYPE_DESTINATION_LEFT + || maneuverType == Maneuver.TYPE_DESTINATION_RIGHT + || maneuverType == Maneuver.TYPE_DESTINATION_STRAIGHT) && leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE ) { stopNavigation() - routeState = routeState.copy(arrived = true) + arrived = true surfaceRenderer.routeData.value = "" navigationType = NavigationType.ARRIVAL invalidate() diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationSettings.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationSettings.kt index 042aca2..f1ea209 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationSettings.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationSettings.kt @@ -12,21 +12,29 @@ import androidx.car.app.model.Toggle import com.kouros.data.R import com.kouros.navigation.data.Constants.AVOID_MOTORWAY import com.kouros.navigation.data.Constants.AVOID_TOLLWAY +import com.kouros.navigation.data.Constants.CAR_LOCATION import com.kouros.navigation.model.ViewModel import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue import com.kouros.navigation.utils.NavigationUtils.setBooleanKeyValue -class NavigationSettings(private val carContext: CarContext, private var viewModel: ViewModel) : Screen(carContext) { +class NavigationSettings(private val carContext: CarContext, private var viewModel: ViewModel) : + Screen(carContext) { private var motorWayToggleState = false private var tollWayToggleState = false + private var carLocationToggleState = false + + init { motorWayToggleState = getBooleanKeyValue(carContext, AVOID_MOTORWAY) tollWayToggleState = getBooleanKeyValue(carContext, AVOID_MOTORWAY) + + carLocationToggleState = getBooleanKeyValue(carContext, CAR_LOCATION) + } override fun onGetTemplate(): Template { @@ -53,6 +61,24 @@ class NavigationSettings(private val carContext: CarContext, private var viewMod tollWayToggleState = !tollWayToggleState }.setChecked(tollWayToggleState).build() listBuilder.addItem(buildRowForTemplate(R.string.avoid_tolls_row_title, tollwayToggle)) + + val carLocationToggle: Toggle = + Toggle.Builder { checked: Boolean -> + if (checked) { + setBooleanKeyValue(carContext, true, CAR_LOCATION) + } else { + setBooleanKeyValue(carContext, false, CAR_LOCATION) + } + carLocationToggleState = !carLocationToggleState + }.setChecked(carLocationToggleState).build() + + listBuilder.addItem( + buildRowForTemplate( + R.string.use_car_location, + carLocationToggle + ) + ) + listBuilder.addItem( buildRowForScreenTemplate( RoutingSettings(carContext, viewModel), 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 b201da7..5a783cf 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 @@ -7,7 +7,6 @@ import android.text.SpannableString import androidx.car.app.CarContext import androidx.car.app.CarToast import androidx.car.app.Screen -import androidx.car.app.constraints.ConstraintManager import androidx.car.app.model.Action import androidx.car.app.model.CarIcon import androidx.car.app.model.Distance @@ -22,15 +21,11 @@ import androidx.lifecycle.Observer import com.kouros.data.R import com.kouros.navigation.car.SurfaceRenderer import com.kouros.navigation.car.navigation.RouteCarModel -import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants.CONTACTS import com.kouros.navigation.data.Constants.FAVORITES import com.kouros.navigation.data.Constants.RECENT -import com.kouros.navigation.data.Constants.categories -import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.Place import com.kouros.navigation.model.ViewModel -import kotlin.math.min class PlaceListScreen( diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/RoutingSettings.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutingSettings.kt index 90cdede..6d5d7f2 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/RoutingSettings.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutingSettings.kt @@ -10,18 +10,25 @@ import androidx.car.app.model.ListTemplate import androidx.car.app.model.Row import androidx.car.app.model.SectionedItemList import androidx.car.app.model.Template +import androidx.car.app.model.Toggle import com.kouros.data.R +import com.kouros.navigation.data.Constants.AVOID_MOTORWAY +import com.kouros.navigation.data.Constants.CAR_LOCATION import com.kouros.navigation.data.Constants.ROUTING_ENGINE import com.kouros.navigation.data.RouteEngine import com.kouros.navigation.model.ViewModel +import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue +import com.kouros.navigation.utils.NavigationUtils.setBooleanKeyValue import com.kouros.navigation.utils.NavigationUtils.setIntKeyValue class RoutingSettings(private val carContext: CarContext, private var viewModel: ViewModel) : Screen(carContext) { private var routingEngine = RouteEngine.VALHALLA.ordinal + init { routingEngine = getIntKeyValue(carContext, ROUTING_ENGINE) + } override fun onGetTemplate(): Template { @@ -58,7 +65,6 @@ class RoutingSettings(private val carContext: CarContext, private var viewModel: .build() } - private fun onSelected(index: Int) { setIntKeyValue(carContext, index, ROUTING_ENGINE) viewModel.routingEngine.value = index 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 deleted file mode 100644 index 82d80ff..0000000 --- a/common/car/src/test/java/com/kouros/navigation/car/Route.json +++ /dev/null @@ -1,255 +0,0 @@ -{ - "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/data/src/main/java/com/kouros/navigation/data/Data.kt b/common/data/src/main/java/com/kouros/navigation/data/Data.kt index a61ef08..a2e06a0 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/Data.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/Data.kt @@ -76,39 +76,15 @@ data class Locations ( var lat : Double, var lon : Double, var street : String = "", - val search_filter: SearchFilter, + val search_filter: String, ) -@Serializable data class SearchFilter( - var max_road_class: String = "", - var exclude_toll : Boolean = false -) { + var avoidMotorway: Boolean = false, + var avoidTollway : Boolean = false, - class Builder { - private var avoidMotorway = false - private var avoidTollway = false +) - fun avoidMotorway (value: Boolean ) = apply { - avoidMotorway = value - } - - fun avoidTollway (value: Boolean ) = apply { - avoidTollway = value - } - - fun build(): SearchFilter { - val filter = SearchFilter() - if (avoidMotorway) { - filter.max_road_class = "trunk" - } - if (avoidTollway) { - filter.exclude_toll = true - } - return filter - } - } -} @Serializable data class ValhallaLocation ( @@ -119,13 +95,6 @@ data class ValhallaLocation ( var language: String ) -data class BoundingBox ( - var southernLat : Double, - var westernLon: Double, - var northerLat : Double, - var easternLon : Double -) - object Constants { //const val STYLE: String = "https://kouros-online.de/liberty.json" @@ -175,6 +144,7 @@ object Constants { const val AVOID_TOLLWAY = "AvoidTollway" + const val CAR_LOCATION = "CarLocation" const val ROUTING_ENGINE = "RoutingEngine" const val NEXT_STEP_THRESHOLD = 120.0 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 0909648..8dcb311 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 @@ -20,6 +20,8 @@ import android.content.Context import android.location.Location import com.kouros.navigation.data.overpass.Elements import com.kouros.navigation.model.RouteModel +import com.kouros.navigation.utils.GeoUtils.calculateSquareRadius +import com.kouros.navigation.utils.GeoUtils.getBoundingBox import org.json.JSONArray import java.net.Authenticator import java.net.HttpURLConnection @@ -45,17 +47,13 @@ abstract class NavigationRepository { } fun searchPlaces(search: String, location: Location) : String { -// val bbox = getBoundingBox(location.longitude, location.latitude, 10.0) -// val neLon = bbox["ne"]?.get("lon") -// val neLat = bbox["ne"]?.get("lat") -// val swLon = bbox["sw"]?.get("lon") -// val swLat = bbox["sw"]?.get("lat") -// val viewbox = "&viewbox=$swLon,$swLat,$neLon,$neLat" - return fetchUrl("${nominatimUrl}search?q=$search&format=jsonv2&addressdetails=true,&countrycodes=de", false) + val box = calculateSquareRadius(location.latitude, location.longitude, 20.0) + val viewbox = "&bounded=1&viewbox=${box[2]},${box[0]},${box[3]},${box[1]}" + return fetchUrl("${nominatimUrl}search?q=$search&format=jsonv2&addressdetails=true$viewbox", false) } fun reverseAddress(location: Location) : String { - return fetchUrl("${nominatimUrl}reverse?lat=${location.latitude}&lon=${location.longitude}&format=jsonv2&addressdetails=true&countrycodes=de", false) + return fetchUrl("${nominatimUrl}reverse?lat=${location.latitude}&lon=${location.longitude}&format=jsonv2&addressdetails=true", false) } fun fetchUrl(url: String, authenticator : Boolean): String { 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 58f59ef..5b16fc2 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 @@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder import com.kouros.navigation.data.osrm.OsrmResponse import com.kouros.navigation.data.osrm.OsrmRoute import com.kouros.navigation.data.route.Leg +import com.kouros.navigation.data.route.Maneuver import com.kouros.navigation.data.route.Step import com.kouros.navigation.data.route.Summary import com.kouros.navigation.data.valhalla.ValhallaResponse @@ -80,11 +81,37 @@ data class Route( routeGeoJson = this.routeGeoJson, ) } + + fun buildEmpty(): Route { + return Route( + routeEngine = 0, + summary = Summary(0.0, 0.0), + legs = emptyList(), + waypoints = emptyList(), + routeGeoJson = "", + ) + } + } + + fun currentStep(): Step { + return if (legs != null && legs.isNotEmpty()) { + legs.first().steps[currentStep] + } else { + Step(maneuver = Maneuver(waypoints = emptyList(), location = location(0.0, 0.0))) + } + } + + fun nextStep(): Step { + val nextIndex = currentStep + 1 + return if (nextIndex < legs!!.first().steps.size) { + legs.first().steps[nextIndex] + } else { + throw IndexOutOfBoundsException("No next maneuver available.") + } } fun maneuverLocations(): List { - val step = currentStep() - val waypoints = step.maneuver.waypoints + val waypoints = currentStep().maneuver.waypoints val points = mutableListOf() for (loc in waypoints) { val point = Point.fromLngLat(loc[0], loc[1]) @@ -92,21 +119,4 @@ data class Route( } return points } - - fun currentStep(): Step { - if (legs != null) { - return legs.first().steps[currentStep] - } else { - throw IndexOutOfBoundsException("No legs available.") - } - } - - fun nextStep(): Step { - val nextIndex = currentStep + 1 - return if (nextIndex < legs!!.first().steps.size) { - legs.first().steps[currentStep + 1] - } else { - throw IndexOutOfBoundsException("No next maneuver available.") - } - } } \ 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 index 14c9e55..64dfdf7 100644 --- 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 @@ -12,7 +12,15 @@ class OsrmRepository : NavigationRepository() { location: Location, searchFilter: SearchFilter ): String { + + var exclude = "" + if (searchFilter.avoidMotorway) { + exclude = "&exclude=motorway" + } + if (searchFilter.avoidTollway) { + exclude = "$exclude&exclude=toll" + } val routeLocation = "${currentLocation.longitude},${currentLocation.latitude};${location.longitude},${location.latitude}?steps=true" - return fetchUrl(routeUrl + routeLocation, true) + return fetchUrl(routeUrl + routeLocation + exclude, true) } } \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/osrm/OsrmRoute.kt b/common/data/src/main/java/com/kouros/navigation/data/osrm/OsrmRoute.kt index 71d1cff..527efe9 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/osrm/OsrmRoute.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/osrm/OsrmRoute.kt @@ -26,11 +26,13 @@ class OsrmRoute { val points = decodePolyline(it.geometry!!, 5) waypoints.addAll(points) val maneuver = RouteManeuver( - bearingBefore = it.maneuver!!.bearingBefore ?: 0, - bearingAfter = it.maneuver!!.bearingAfter ?: 0, - type = convertType(it.maneuver!!), - waypoints = points + bearingBefore = it.maneuver.bearingBefore ?: 0, + bearingAfter = it.maneuver.bearingAfter ?: 0, + type = convertType(it.maneuver), + waypoints = points, + location = location(it.maneuver.location[0], it.maneuver.location[1]) ) + it.intersections.forEach { it2 -> if (it2.location[0] != 0.0) { val lanes = mutableListOf() @@ -47,7 +49,14 @@ class OsrmRoute { intersections.add(Intersection(it2.location, lanes)) } } - val step = Step( index = stepIndex, name = it.name!!, distance = it.distance!! / 1000, duration = it.duration!!, maneuver = maneuver, intersection = intersections) + val step = Step( + index = stepIndex, + name = it.name!!, + distance = it.distance!! / 1000, + duration = it.duration!!, + maneuver = maneuver, + intersection = intersections + ) steps.add(step) stepIndex += 1 } @@ -67,60 +76,100 @@ class OsrmRoute { ManeuverType.depart.value -> { newType = androidx.car.app.navigation.model.Maneuver.TYPE_DEPART } + ManeuverType.arrive.value -> { newType = androidx.car.app.navigation.model.Maneuver.TYPE_DESTINATION + if (maneuver.modifier == "right") { + newType = androidx.car.app.navigation.model.Maneuver.TYPE_DESTINATION_RIGHT + } + if (maneuver.modifier == "left") { + newType = androidx.car.app.navigation.model.Maneuver.TYPE_DESTINATION_LEFT + } + if (maneuver.modifier == "straight") { + newType = androidx.car.app.navigation.model.Maneuver.TYPE_DESTINATION_STRAIGHT + } } + ManeuverType.continue_.value -> { newType = androidx.car.app.navigation.model.Maneuver.TYPE_STRAIGHT } + + ManeuverType.newName.value -> { + if (maneuver.modifier == "straight") { + newType = androidx.car.app.navigation.model.Maneuver.TYPE_STRAIGHT + } + } + ManeuverType.turn.value, ManeuverType.endOfRoad.value -> { if (maneuver.modifier == "right") { newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_RIGHT } + if (maneuver.modifier == "left") { + newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_LEFT + } + if (maneuver.modifier == "straight") { + newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT + } } - ManeuverType.turn.value, + ManeuverType.endOfRoad.value, ManeuverType.onRamp.value - -> { + -> { if (maneuver.modifier == "left") { newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_LEFT } } + + ManeuverType.offRamp.value + -> { + if (maneuver.modifier == "slight right") { + newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT + } + } + ManeuverType.fork.value -> { if (maneuver.modifier == "slight left") { newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_LEFT } } + ManeuverType.fork.value -> { if (maneuver.modifier == "slight right") { newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT } } + + ManeuverType.merge.value + -> { + if (maneuver.modifier == "slight left") { + newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_LEFT + } + } } - return newType + } -} - -enum class ManeuverType(val value: String) { - turn("turn"), - depart("depart"), - arrive("arrive"), - merge("merge"), - onRamp("on ramp"), - offRamp("off ramp"), - fork("fork"), - endOfRoad("end of road"), - continue_("continue"), - roundAbout("roundabout"), - rotary("rotary"), - roundaboutTurn("roundabout turn"), - notification("notification"), - exitRoundabout("exit roundabout"), - exitRotary("exit rotary") + enum class ManeuverType(val value: String) { + turn("turn"), + depart("depart"), + arrive("arrive"), + merge("merge"), + onRamp("on ramp"), + offRamp("off ramp"), + fork("fork"), + endOfRoad("end of road"), + continue_("continue"), + roundAbout("roundabout"), + rotary("rotary"), + roundaboutTurn("roundabout turn"), + notification("notification"), + exitRoundabout("exit roundabout"), + exitRotary("exit rotary"), + newName("new name"), + } } \ 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 index d110fc4..aa4abc2 100644 --- 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 @@ -8,7 +8,7 @@ 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("maneuver" ) val maneuver : Maneuver? = Maneuver(), @SerializedName("name" ) var name : String? = null, @SerializedName("mode" ) var mode : String? = null, @SerializedName("weight" ) var weight : Double? = null, 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 index 83369e7..63f8212 100644 --- 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 @@ -294,25 +294,28 @@ "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] + }, + { + "out": 0, + "classes": [ + "tunnel" + ], + "in": 1, + "entry": [true, false], + "bearings": [105, 285], + "location": [11.58707, 48.17739] + }, + { + "out": 0, + "in": 1, + "entry": [true, false], + "bearings": [120, 300], + "location": [11.589463, 48.176823] } ], "driving_side": "right", @@ -412,6 +415,23 @@ "bearings": [120, 135, 300], "location": [11.594022, 48.174977] }, + { + "out": 0, + "classes": [ + "tunnel" + ], + "in": 1, + "entry": [true, false], + "bearings": [120, 315], + "location": [11.596646, 48.173717] + }, + { + "out": 0, + "in": 1, + "entry": [true, false], + "bearings": [120, 300], + "location": [11.597609, 48.173233] + }, { "out": 2, "in": 1, @@ -435,6 +455,9 @@ }, { "out": 1, + "classes": [ + "tunnel" + ], "in": 0, "entry": [false, true], "bearings": [30, 210], @@ -491,6 +514,9 @@ }, { "out": 0, + "classes": [ + "tunnel" + ], "in": 1, "entry": [true, false], "bearings": [135, 315], @@ -550,6 +576,9 @@ "intersections": [ { "out": 1, + "classes": [ + "tunnel" + ], "in": 0, "entry": [false, true], "bearings": [0, 180], @@ -557,10 +586,20 @@ }, { "out": 1, + "classes": [ + "tunnel" + ], "in": 0, "entry": [false, true, true], "bearings": [0, 165, 180], "location": [11.614595, 48.137999] + }, + { + "out": 0, + "in": 1, + "entry": [true, false], + "bearings": [165, 345], + "location": [11.614951, 48.136421] } ], "driving_side": "right", @@ -589,10 +628,27 @@ "location": [11.615548, 48.135064] }, { - "out": 1, - "in": 0, - "entry": [false, true, true], - "bearings": [0, 180, 195], + "out": 0, + "classes": [ + "tunnel" + ], + "in": 1, + "entry": [true, false], + "bearings": [165, 345], + "location": [11.615591, 48.134991] + }, + { + "out": 0, + "in": 1, + "entry": [true, false], + "bearings": [165, 345], + "location": [11.616284, 48.13357] + }, + { + "out": 0, + "in": 2, + "entry": [true, true, false], + "bearings": [180, 195, 345], "location": [11.616365, 48.133153] }, { @@ -605,7 +661,7 @@ ], "driving_side": "right", "maneuver": { - "bearing_after": 160, + "bearing_after": 157, "bearing_before": 160, "location": [11.615548, 48.135064], "modifier": "straight", @@ -623,6 +679,9 @@ "intersections": [ { "out": 1, + "classes": [ + "tunnel" + ], "in": 0, "entry": [false, true], "bearings": [15, 195], @@ -649,10 +708,20 @@ "intersections": [ { "out": 2, + "classes": [ + "tunnel" + ], "in": 0, "entry": [false, true, true], "bearings": [15, 180, 210], "location": [11.615282, 48.129902] + }, + { + "out": 1, + "in": 0, + "entry": [false, true], + "bearings": [30, 210], + "location": [11.614931, 48.129418] } ], "driving_side": "right", @@ -926,7 +995,7 @@ } ], "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", + "geometry": "mrudHsyyeABTFl@DZPz@R~@Tv@Hr@Hp@DZJbARdBVtB?HFZ@LBN?F^tCHn@Fd@Hf@D^DZJx@BRDXD^@NLz@BTL~@VdBFb@Hf@Hf@Jp@DVDVHr@Lx@l@lENfAPdAXvA`@dC", "maneuver": { "bearing_after": 254, "bearing_before": 262, @@ -936,9 +1005,9 @@ }, "name": "Sankt-Martin-Straße", "mode": "driving", - "weight": 100.8, - "duration": 100.8, - "distance": 945.7 + "weight": 94.8, + "duration": 94.8, + "distance": 945.8 }, { "intersections": [ @@ -951,7 +1020,7 @@ } ], "driving_side": "right", - "geometry": "iaudHsnweAPC^ITELCh@Al@Bp@DfBH", + "geometry": "iaudHsnweAPCJCRETELCh@Al@Bp@DfBH", "maneuver": { "bearing_after": 168, "bearing_before": 247, @@ -990,28 +1059,28 @@ "distance": 0 } ], - "weight": 1019.7, + "weight": 1013.7, "summary": "Isarring, Richard-Strauss-Tunnel", - "duration": 1019.7, + "duration": 1013.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, + "weight": 1013.7, + "duration": 1013.7, "distance": 11116.5 } ], "waypoints": [ { - "hint": "7VEViP___38IAAAACgAAACAAAABmAAAA16KyQIr6mD9w-qdBPiiJQggAAAAKAAAAIAAAAGYAAACLGwEA4K-wAMdA3wLvr7AAlUHfAgYADxEAAAAA", + "hint": "77u6gP___38IAAAACgAAACAAAABmAAAA16KyQIr6mD9w-qdBPiiJQggAAAAKAAAAIAAAAGYAAACYEgAA4K-wAMdA3wLvr7AAlUHfAgYADxEAAAAA", "location": [11.57936, 48.185543], "name": "Vogelhartstraße", "distance": 22.93305775 }, { - "hint": "oDEBgP___39XAAAAXAAAALsAAAAlAAAA4t1qQtUpMkCvevlCiIDIQVcAAABcAAAAuwAAACUAAACLGwEA5umwAAcz3gJS6rAAAjPeAg4AfwsAAAAA", + "hint": "hL-3gP___39XAAAAXAAAALsAAAAlAAAA4t1qQtUpMkC7evlCiIDIQVcAAABcAAAAuwAAACUAAACYEgAA5umwAAcz3gJS6rAAAjPeAhAAfwsAAAAA", "location": [11.594214, 48.116487], "name": "Hohenwaldeckstraße", "distance": 8.059248837 diff --git a/common/data/src/main/java/com/kouros/navigation/data/route/Maneuver.kt b/common/data/src/main/java/com/kouros/navigation/data/route/Maneuver.kt index 1f1ba33..f66f0f2 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/route/Maneuver.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/route/Maneuver.kt @@ -1,8 +1,11 @@ package com.kouros.navigation.data.route +import android.location.Location + data class Maneuver( val bearingBefore : Int = 0, val bearingAfter : Int = 0, val type: Int = 0, val waypoints: List>, + val location: Location, ) 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 index 54e7532..ac1b1c4 100644 --- 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 @@ -13,10 +13,18 @@ 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 + + var exclude = "" + if (searchFilter.avoidMotorway) { + exclude = "&max_road_class='trunk'" + } + if (searchFilter.avoidTollway) { + exclude = "$exclude&exclude_toll=true" + } + val vLocation = listOf( - Locations(lat = currentLocation.latitude, lon = currentLocation.longitude, search_filter = searchFilter), - Locations(lat = location.latitude, lon = location.longitude, search_filter = searchFilter) + Locations(lat = currentLocation.latitude, lon = currentLocation.longitude, search_filter = exclude), + Locations(lat = location.latitude, lon = location.longitude, search_filter = exclude) ) val valhallaLocation = ValhallaLocation( locations = vLocation, diff --git a/common/data/src/main/java/com/kouros/navigation/data/valhalla/ValhallaRoute.kt b/common/data/src/main/java/com/kouros/navigation/data/valhalla/ValhallaRoute.kt index 2a6e18d..298ffc3 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/valhalla/ValhallaRoute.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/valhalla/ValhallaRoute.kt @@ -9,6 +9,7 @@ import com.kouros.navigation.data.route.Step import com.kouros.navigation.data.route.Summary import com.kouros.navigation.utils.GeoUtils.createLineStringCollection import com.kouros.navigation.utils.GeoUtils.decodePolyline +import com.kouros.navigation.utils.location class ValhallaRoute { @@ -25,7 +26,10 @@ class ValhallaRoute { bearingAfter = it.bearingAfter, //type = it.type, type = convertType(it), - waypoints =waypoints.subList(it.beginShapeIndex, it.endShapeIndex+1) + waypoints =waypoints.subList(it.beginShapeIndex, it.endShapeIndex+1), + // TODO: calculate from ShapeIndex ! + location = location(0.0, 0.0) + ) var name = "" if (it.streetNames != null && it.streetNames.isNotEmpty()) { diff --git a/common/data/src/main/java/com/kouros/navigation/model/BaseStyleModel.kt b/common/data/src/main/java/com/kouros/navigation/model/BaseStyleModel.kt index 6dcc131..277f2c7 100644 --- a/common/data/src/main/java/com/kouros/navigation/model/BaseStyleModel.kt +++ b/common/data/src/main/java/com/kouros/navigation/model/BaseStyleModel.kt @@ -14,7 +14,6 @@ class BaseStyleModel { } fun readStyle(context: Context, darkModeSettings: Int, isCarDarkMode: Boolean): BaseStyle.Json { - println("BaseStyle ${isDarkTheme(context)}") val liberty = when(darkModeSettings) { 0 -> context.resources.openRawResource(R.raw.liberty) 1 -> context.resources.openRawResource(R.raw.liberty_night) 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 f8087f0..7a5d2f2 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 @@ -30,66 +30,52 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import java.util.Collections import java.util.concurrent.TimeUnit +import kotlin.math.absoluteValue import kotlin.math.roundToInt open class RouteModel() { - data class RouteState( - val route: Route? = null, - val isNavigating: Boolean = false, - val destination: Place = Place(), - val arrived: Boolean = false, - val maneuverType: Int = 0, - val travelMessage: String = "", - val lastSpeedLocation: Location = location(0.0, 0.0), - val lastSpeedIndex: Int = 0, - val maxSpeed: Int = 0, - val location: Location = location(0.0, 0.0), - val lastLocation: Location = location(0.0, 0.0), - val bearing: Float = 0F - ) - var routeState = RouteState() - - var route: Route - get() = routeState.route!! - set(value) { - routeState = routeState.copy(route = value) - } + var route = Route.Builder().buildEmpty() + var navigating: Boolean = false + var destination: Place = Place() + var arrived: Boolean = false + var maneuverType: Int = 0 + var travelMessage: String = "" + var lastSpeedLocation: Location = location(0.0, 0.0) + var lastSpeedIndex: Int = 0 + var maxSpeed: Int = 0 + var location: Location = location(0.0, 0.0) + var lastLocation: Location = location(0.0, 0.0) + var bearing: Float = 0F val legs: Leg - get() = routeState.route!!.legs!!.first() + get() = route.legs!!.first() fun startNavigation(routeString: String, context: Context) { val routeEngine = getIntKeyValue(context = context, ROUTING_ENGINE) - var newRoute = Route.Builder() + route = Route.Builder() .routeEngine(routeEngine) .route(routeString) .build() // TODO: - newRoute = newRoute.copy(centerLocation = createCenterLocation(newRoute.routeGeoJson)) - println("Route ${newRoute.centerLocation}") - this.routeState = routeState.copy( - route = newRoute, - isNavigating = true - ) + route = route.copy(centerLocation = createCenterLocation(route.routeGeoJson)) + navigating = true } fun stopNavigation() { - this.routeState = routeState.copy( - route = null, - isNavigating = false, - arrived = false, - maneuverType = 0, - ) + route = Route.Builder().buildEmpty() + navigating = false + arrived = false + maneuverType = 0 + } @OptIn(DelicateCoroutinesApi::class) - fun updateLocation(location: Location, viewModel: ViewModel) { - routeState = routeState.copy(location = location) + fun updateLocation(curLocation: Location, viewModel: ViewModel) { + location = curLocation findStep(location) updateSpeedLimit(location, viewModel) - } private fun findStep(location: Location) { @@ -104,9 +90,8 @@ open class RouteModel() { route.currentStep = step.index step.waypointIndex = wayIndex step.wayPointLocation = location(waypoint[0], waypoint[1]) - val bearing = routeState.lastLocation.bearingTo(location) - this.routeState = - routeState.copy(lastLocation = location, bearing = bearing) + lastLocation = location + bearing = lastLocation.bearingTo(location) } } if (nearestDistance == 0F) { @@ -120,31 +105,38 @@ open class RouteModel() { } } - private fun currentIntersection(location: Location): Intersection { + private fun currentLanes(location: Location): List { var inter = Intersection() var nearestDistance = 100000.0f route.currentStep().intersection.forEach { - val distance = location.distanceTo(location(it.location[0], it.location[1])) - if (distance < nearestDistance) { - nearestDistance = distance - inter = it + if (it.lane.isNotEmpty()) { + val distance = location.distanceTo(location(it.location[0], it.location[1])) + val interBearing = location.bearingTo(location(it.location[0], it.location[1])) + if (distance < nearestDistance) { + nearestDistance = distance + if (distance <= NEXT_STEP_THRESHOLD) { + if ((interBearing.absoluteValue - route.currentStep().maneuver.bearingAfter.absoluteValue).absoluteValue < 10) { + inter = it + } + } + } } } - return inter + return inter.lane } fun updateSpeedLimit(location: Location, viewModel: ViewModel) = runBlocking { CoroutineScope(Dispatchers.IO).launch { // speed limit - val distance = routeState.lastSpeedLocation.distanceTo(location) - if (distance > 500 || routeState.lastSpeedIndex < route.currentStep) { - routeState = routeState.copy(lastSpeedIndex = route.currentStep) - routeState = routeState.copy(lastSpeedLocation = location) + val distance = lastSpeedLocation.distanceTo(location) + if (distance > 500 || lastSpeedIndex < route.currentStep) { + lastSpeedIndex = route.currentStep + lastSpeedLocation = location 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) + maxSpeed = speed } } } @@ -160,7 +152,7 @@ open class RouteModel() { isNearNextManeuver && route.currentStep < (route.legs!!.first().steps.size) // Determine the maneuver type and corresponding icon - var maneuverType = if (hasArrived(currentStep.maneuver.type)) { + var curManeuverType = if (hasArrived(currentStep.maneuver.type)) { currentStep.maneuver.type } else { Maneuver.TYPE_STRAIGHT @@ -174,12 +166,17 @@ open class RouteModel() { // Safely get the street name from the maneuver val streetName = relevantStep.name if (shouldAdvance) { - maneuverType = relevantStep.maneuver.type + curManeuverType = relevantStep.maneuver.type + } + val maneuverIcon = maneuverIcon(curManeuverType) + maneuverType = curManeuverType + + val lanes = if (shouldAdvance) { + currentLanes(location) + } else { + emptyList() } - val maneuverIcon = maneuverIcon(maneuverType) - routeState = routeState.copy(maneuverType = maneuverType) // Construct and return the final StepData object - val intersection = currentIntersection(routeState.location) return StepData( streetName, distanceToNextStep, @@ -187,7 +184,7 @@ open class RouteModel() { maneuverIcon, arrivalTime(), travelLeftDistance(), - intersection.lane + lanes ) } @@ -279,6 +276,9 @@ open class RouteModel() { } Maneuver.TYPE_DESTINATION, + Maneuver.TYPE_DESTINATION_RIGHT, + Maneuver.TYPE_DESTINATION_LEFT, + Maneuver.TYPE_DESTINATION_STRAIGHT -> { currentTurnIcon = R.drawable.ic_turn_destination } @@ -320,7 +320,7 @@ open class RouteModel() { } fun isNavigating(): Boolean { - return routeState.isNavigating + return navigating } @@ -330,10 +330,11 @@ open class RouteModel() { || type == ManeuverType.DestinationLeft.value } + fun createLaneIcon(context: Context, stepData: StepData): IconCompat { val bitmaps = mutableListOf() stepData.lane.forEach { - if (it.indications.isNotEmpty() && it.valid) { + if (it.indications.isNotEmpty()) { //&& it.valid) { Collections.sort(it.indications) val resource = laneToResource(it.indications, stepData) if (resource.isNotEmpty()) { @@ -356,7 +357,7 @@ open class RouteModel() { return bitmaps.first() } val bmOverlay = createBitmap( - bitmaps.first().getWidth() * (bitmaps.size) , + bitmaps.first().getWidth() * (bitmaps.size), bitmaps.first().getHeight(), bitmaps.first().getConfig()!! ) @@ -402,6 +403,7 @@ open class RouteModel() { } } + "right" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT) "${direction}_o" else "${direction}_x" "left" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_LEFT) "${direction}_o" else "${direction}_x" "straight" -> if (stepData.currentManeuverType == Maneuver.TYPE_STRAIGHT) "${direction}_o" else "${direction}_x" "right_slight" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_SLIGHT_RIGHT) "${direction}_o" else "${direction}_x" 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 9bd52d0..a0d11fc 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 @@ -9,6 +9,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.google.gson.GsonBuilder import com.kouros.navigation.data.Constants +import com.kouros.navigation.data.Constants.ROUTING_ENGINE import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.ObjectBox.boxStore import com.kouros.navigation.data.Place @@ -19,6 +20,7 @@ import com.kouros.navigation.data.nominatim.SearchResult import com.kouros.navigation.data.overpass.Elements import com.kouros.navigation.data.overpass.Overpass import com.kouros.navigation.utils.NavigationUtils +import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue import com.kouros.navigation.utils.location import io.objectbox.kotlin.boxFor import kotlinx.coroutines.Dispatchers @@ -71,7 +73,6 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { MutableLiveData() } - fun loadRecentPlace(location: Location, context: Context) { viewModelScope.launch(Dispatchers.IO) { try { @@ -356,7 +357,6 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { } fun getSearchFilter(context: Context): SearchFilter { - val avoidMotorway = NavigationUtils.getBooleanKeyValue( context = context, Constants.AVOID_MOTORWAY @@ -365,10 +365,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { context = context, Constants.AVOID_TOLLWAY ) - return SearchFilter.Builder() - .avoidMotorway(avoidMotorway) - .avoidTollway(avoidTollway) - .build() + return SearchFilter(avoidMotorway, avoidTollway) } diff --git a/common/data/src/main/java/com/kouros/navigation/utils/GeoUtils.kt b/common/data/src/main/java/com/kouros/navigation/utils/GeoUtils.kt index 4dbbc72..662926e 100644 --- a/common/data/src/main/java/com/kouros/navigation/utils/GeoUtils.kt +++ b/common/data/src/main/java/com/kouros/navigation/utils/GeoUtils.kt @@ -1,7 +1,6 @@ package com.kouros.navigation.utils import android.location.Location -import com.kouros.navigation.data.BoundingBox import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.put import org.maplibre.geojson.FeatureCollection @@ -10,7 +9,6 @@ import org.maplibre.spatialk.geojson.Feature import org.maplibre.spatialk.geojson.dsl.addFeature import org.maplibre.spatialk.geojson.dsl.buildFeatureCollection import org.maplibre.spatialk.geojson.dsl.buildLineString -import org.maplibre.spatialk.geojson.dsl.buildMultiPoint import org.maplibre.spatialk.geojson.toJson import org.maplibre.turf.TurfMeasurement import org.maplibre.turf.TurfMisc @@ -34,8 +32,7 @@ object GeoUtils { } - fun decodePolyline(encoded: String, precision: Int = 6,): List> { - //val precisionOptional = if (precisionOptional.isNotEmpty()) precisionOptional[0] else 6 + fun decodePolyline(encoded: String, precision: Int = 6): List> { val factor = 10.0.pow(precision) var lat = 0 @@ -128,13 +125,18 @@ object GeoUtils { return "$swLon,$swLat,$neLon,$neLat" } - fun getBoundingBox2(location: Location, radius: Double): BoundingBox { - val bbox = getBoundingBox(location.longitude, location.latitude, radius) - val neLon = bbox["ne"]?.get("lon") - val neLat = bbox["ne"]?.get("lat") - val swLon = bbox["sw"]?.get("lon") - val swLat = bbox["sw"]?.get("lat") - return BoundingBox(swLat ?: 0.0 , swLon ?: 0.0, neLat ?: 0.0, neLon ?: 0.0) + /** + * Calculate the lat and len of a square around a point. + * @return latMin, latMax, lngMin, lngMax + */ + fun calculateSquareRadius(lat: Double, lng: Double, radius: Double): DoubleArray { + val earthRadius = 6371.0 // earth radius in km + val latMin = lat - toDegrees(radius / earthRadius) + val latMax = lat + toDegrees(radius / earthRadius) + val lngMin = lng - toDegrees(radius / earthRadius / cos(toRadians(lat))) + val lngMax = lng + toDegrees(radius / earthRadius / cos(toRadians(lat))) + + return doubleArrayOf(latMin, latMax, lngMin, lngMax) } fun getBoundingBox( lat: Double, 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 ddbaafb..1eb9b5c 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 @@ -25,7 +25,7 @@ import kotlin.time.Duration.Companion.seconds object NavigationUtils { - fun getRouteEngine(context: Context): ViewModel { + fun getViewModel(context: Context): ViewModel { val routeEngine = getIntKeyValue(context = context, ROUTING_ENGINE) return when (routeEngine) { RouteEngine.VALHALLA.ordinal -> ViewModel(ValhallaRepository()) diff --git a/common/data/src/main/res/drawable/none.png b/common/data/src/main/res/drawable/none.png new file mode 100644 index 0000000000000000000000000000000000000000..c1248e5c0cfc5867a09b2eef7310f3befeb26425 GIT binary patch literal 4759 zcmeHLc~BHr8gI{0!~>0p2b*??#trmL_w=0Y3@ie2$S8pkCQ2-Nx_gF(ndwPS!;Ij8 zM1w*+fFz^{(G4nEMhO~?K}DkI?iRvkjahH;pmtr41QU%hYpMHsxGSmJvUdHCshZ<` z@B4o5`+nc=z3MmXlIF*b_M74dLD1;DC> zSvvy@OI-}icv&k1c`vSiJ#s@6?0@8b@$$mG>sQ^}G_&-fWcdmS+FFym{lMxU{As=R zy7%ek>pLWq##Hiqv*wQ2v#9=)SxRcEu55$8P!mz&2|qG6=)H`Jk)g9!7Q_Yzr*Y%Y zJ(;n;_lL`o*I@_wLaXD>qMEayKI9N{KBWhoC_rY*bWId{k6-<)GfGk2f_W zoJbnCrg3-U+KaOSEv3i5LBbN5>$}DcT@#e%I?z1xjr2rI+`h2K!;h{DZwV~C7G-|T zobTLUhpr#ew9FsB+0yX0edQ=(8wLatCCzyonFbqb^xak@i9h)#@X#!d08 zOJF%CEMk%tE=Mp(rC=WJ&d=d88hhZK?k*MpA9640l4CMd?r_NaM!1ETTmaIQ&~HY# zO<=#tlNmRc!&6L5F5?tJ`a;lDPrNIKxBJSWDLG?j9Kh8LR>k@)85?g*>WL63u(1x8 zFA9*|&r@Kny=3*vO`P$S(>D5z~v0Hb}+w37Vr=n(+Np zkXoxoiIRv#fvOOtTFoF@ic}&>1!Ki6I#i93sy;4&8A&{l?`)k+mY z<5m<=QVJD9S}+tL)flDJU<{^EGJPNx@GMXzY44kr2t@-ZhQTa48r34S)=C2?8f2qJ zb%<7r(^iz$VisEIgQ6*7F2_4a&`#Dt+8DXZY4c5pgcFfT@dl|vhW1*L?4)1?0S0Lz z>&)@?PMBB+lOm8Jo0vweQ7e>cRIO91z>2+2sSNK1N)$0MREDd4Gh$l^Pz)fJ6m<#! ze0ER^5ydm4!0{%Ivm2yhO0XE&Gi?Ohi6#XyniLoSiYn9uiV>*FgsBJ>N}%dcaoES7 zqgm_H|K=@j9$4Sm@;KHF)?ex~b?&GX=B>_A=g`jjwh|2cHU&Xaoh7)*T!!}L39ve+ zs7%snW5DUrCD(2{`x{cwX>n4c(2@vAYjB_;5=AUJ6^>XfN=AueC~n0%)zpLT=B$E; z8UNwt;gpY;D!;;%H(Ria)l9*f;g)ysd?_D+XB=P012(+19G zaNNs#&igLTKuccat4nS#atRn7Sme3*9iVG~uIFOlxts^oH9*&MG4Nc@1M2#}(dE~B zV`QA*LC*v3gFhbLvJl)Q2V3UFMnll9^&tu{8tICA!wo^BCW!ArP-RsRFiM1YV~phX zpkZSa!&ho6)&kRHA;v63aSrj)0r{SV85;JmLMALe3#Y9bGYMSy-SN?prnoAMBdK#8qAhfbavQ~duvw)mQDHg)vU0u zp&w6AmPCGjh9Jwfs;&)+HKb$9+Jy1-m4DIIUbsAI*DpM7zceg3&!$PfJO0*|bpb6qzAO&CHFVU7&jN0&nQ8q~dW?)2T~qLnW?M#H zNya)HUUYjTBuO`)rv`Tv6Ay|??w9X4-?C`a!=GN-*&cSRd9dW|5a+gP_(p#0-B|}` zjIow4-m3Ul;k3*Zr!FUwg{3D~WXFbI8WQjaeQ1V6LYa=%)(2Pa9_>7I>Xq!PYe;Ki zUT{|F7ex)S2W4AQ>#ppI9G*ISV`;>=V~Lule84tS%?vx$@%;`*{^`3 + + + + + + + + + + + + + + +GPS Logger 20260101-110217 +H + +car + + + + Track 20260101-110217 + + 549.4920.00015 + 549.4920.00013 + 548.4920.19017 + 549.4920.03014 + 549.4920.00016 + 549.4920.00014 + 549.4920.01013 + 549.4920.00013 + 549.4920.13015 + 552.4925.16018 + 555.4924.83019 + 555.4924.76018 + 554.4924.06017 + 549.4924.72015 + 546.4926.41014 + 546.4926.51011 + 544.4926.37015 + 544.4926.27015 + 543.4925.74018 + 542.4914.34015 + 540.4913.69015 + 536.4913.99017 + 534.4916.6808 + 535.4916.46012 + 536.4917.57018 + 535.4918.0309 + 535.4917.08011 + 535.4918.02012 + 535.4917.07014 + 535.4915.49014 + 534.4916.86017 + 533.4913.88020 + 532.4916.05020 + 532.4919.03020 + 532.49110.04019 + 532.49110.47016 + 533.49110.89017 + 533.49211.43018 + 533.49211.55019 + 533.49211.99022 + 532.49212.11022 + 532.49212.26021 + 531.49212.75020 + 531.49212.99018 + 531.49213.31019 + 531.49213.51019 + 530.49213.78021 + 530.49313.69019 + 530.49313.05012 + 530.49312.83016 + 530.49313.67015 + 530.49312.79018 + 531.49313.26017 + 531.49313.51016 + 530.49313.09017 + 531.49413.43018 + 531.49413.28019 + 531.49413.14023 + 531.49413.24021 + 532.49413.06020 + 532.49413.07018 + 532.49412.99018 + 532.49412.85021 + 532.49412.70019 + 531.49512.63020 + 531.49512.66014 + 531.49512.91015 + 531.49513.06017 + 530.49513.19016 + 530.49513.06014 + 529.49513.17016 + 529.49513.26019 + 529.49513.23017 + 528.49613.23019 + 528.49613.23019 + 528.49612.76020 + 528.49613.17022 + 527.49613.20022 + 527.49613.32018 + 527.49613.13018 + 527.49613.19018 + 527.49613.04016 + 527.49713.36018 + 527.49713.19017 + 527.49712.71020 + 527.49713.13019 + 527.49712.86017 + 527.49713.25018 + 527.49713.28017 + 527.49712.85018 + 527.49812.89021 + 527.49813.46019 + 527.49813.45019 + 527.49813.77020 + 528.49814.20021 + 528.49813.57021 + 529.49813.14021 + 529.49812.86023 + 528.49812.33023 + 528.49911.63021 + 528.49912.41017 + 528.49911.26021 + 529.49910.12023 + 530.4998.59020 + 530.4996.50021 + 530.4992.60024 + 531.4990.01025 + 531.4990.00023 + 531.4990.00029 + 530.4990.65029 + 529.4996.94029 + 529.5008.99028 + 530.50010.67028 + 530.50011.18026 + 531.50011.72029 + 531.50011.63027 + 531.50012.42022 + 532.50012.77022 + 532.50013.16022 + 533.50113.27024 + 533.50113.40020 + 533.50113.39018 + 533.50113.53017 + 533.50113.61017 + 533.50113.74019 + 533.50113.78017 + 533.50213.81019 + 533.50213.96018 + 532.50214.05020 + 533.50213.85019 + 532.50213.48019 + 532.50213.49020 + 531.50213.61017 + 532.50314.29019 + 532.50313.97020 + 533.50313.70022 + 532.50313.60020 + 532.50313.68017 + 532.50314.13019 + 531.50314.07018 + 531.50413.70020 + 531.50413.25020 + 530.50411.94019 + 530.50411.03017 + 530.50410.45016 + 530.5048.31019 + 530.5045.75019 + 530.5054.66021 + 529.5056.82021 + 529.5056.08023 + 528.5057.28021 + 519.5058.11019 + 518.50510.08014 + 518.50510.98015 + 518.50511.66015 + 518.50512.08020 + 518.50512.59013 + 518.50513.11017 + 519.50413.20018 + 520.50413.02018 + 520.50413.14017 + 520.50413.12018 + 521.50413.18016 + 521.50413.27016 + 521.50413.39016 + 521.50413.49021 + 522.50413.53016 + 522.50413.59019 + 522.50413.52022 + 522.50413.43022 + 522.50413.30024 + 522.50412.39022 + 523.50412.06023 + 522.50411.52019 + 523.50411.40018 + 522.50410.86018 + 523.5049.47018 + 523.5047.81014 + 522.5045.82018 + 523.5041.86018 + 522.5040.01017 + 522.5040.00018 + 522.5040.05018 + 523.5037.83022 + 524.5039.63023 + 524.50310.61023 + 524.50311.18022 + 525.50311.73022 + 525.50312.31021 + 525.50312.61020 + 525.50312.85023 + 525.50312.99021 + 526.50313.09020 + 526.50313.03018 + 526.50312.68017 + 527.50312.23019 + 527.50311.83016 + 527.50311.44018 + 528.50310.90021 + 529.50310.28021 + 529.5039.65021 + 529.5037.62014 + 529.5036.29015 + 529.5037.25019 + 528.5039.06020 + 528.50310.36017 + 528.50311.38019 + 528.50312.06021 + 527.50312.32018 + 527.50312.46019 + 527.50312.57020 + 526.50312.71018 + 526.50312.86016 + 526.50312.88022 + 525.50312.79020 + 525.50312.65019 + 524.50312.63019 + 524.50312.75018 + 523.50312.77020 + 523.50312.74019 + 523.50312.63019 + 523.50312.29019 + 522.50312.07017 + 522.50312.17018 + 522.50312.43020 + 522.50312.74023 + 521.50312.84023 + 521.50313.05023 + 521.50312.87022 + 521.50312.78022 + 521.50312.65023 + 521.50312.56018 + 521.50312.49020 + 521.50312.60019 + 521.50312.57018 + 521.50312.69019 + 521.50312.75016 + 520.50312.52020 + 520.50312.14021 + 520.50311.65022 + 520.50310.42019 + 521.5038.96022 + 521.5038.64015 + 521.5038.45015 + 521.50310.09013 + 521.50310.85016 + 520.50311.29013 + 520.50311.56015 + 519.50311.89015 + 519.50312.33016 + 519.50312.78014 + 518.50313.15012 + 517.50313.34014 + 517.50313.42016 + 516.50313.47017 + 516.50313.36014 + 516.50313.34014 + 515.50313.31016 + 516.50313.17015 + 516.50212.99015 + 515.50212.80017 + 515.50212.78013 + 515.50212.84014 + 515.50212.98015 + 514.50213.19015 + 514.50213.42014 + 514.50213.47011 + 514.50213.5804 + 514.50213.750 + 514.50213.9101 + 514.50214.100 + 514.50114.360 + 514.50114.630 + 514.50114.840 + 514.50115.040 + 514.50115.190 + 514.50115.3501 + 514.50115.8304 + 514.50114.56015 + 514.50014.32013 + 514.50014.27012 + 514.50014.28014 + 514.50014.42015 + 514.50014.68014 + 513.50014.86013 + 512.50015.06012 + 511.50015.02013 + 511.50015.04016 + 511.50014.9308 + 510.50014.9003 + 510.49914.890 + 510.49914.880 + 509.49914.950 + 509.49915.150 + 508.49915.380 + 508.49915.600 + 507.49915.830 + 507.49916.040 + 506.49916.150 + 531.49515.44015 + 525.49415.08021 + 519.49414.93020 + 516.49414.96020 + 514.49414.85020 + 514.49414.87023 + 513.49414.16022 + 513.49414.26021 + 514.49414.64020 + 513.49414.86015 + 511.49315.20017 + 509.49315.48017 + 508.49316.09015 + 507.49315.98015 + 506.49316.61015 + 505.49316.5809 + 500.49215.7007 + 501.49115.96010 + 508.49114.86011 + 509.49115.34013 + 510.49115.44013 + 510.49115.34015 + 509.49015.22013 + 509.49014.12017 + 507.49015.36014 + 507.49015.30012 + 506.49015.56012 + 506.49015.64012 + 504.49015.95016 + 504.48916.32017 + 503.48916.41015 + 503.48916.60016 + 504.48916.60015 + 503.48916.61014 + 502.48816.58020 + 502.48816.65017 + 503.48817.05016 + 503.48816.61018 + 503.48816.68015 + 504.48716.60013 + 503.48716.64015 + 503.48716.75016 + 503.48716.71014 + 503.48716.70017 + 502.48716.65014 + 504.48616.54017 + 504.48616.43017 + 504.48616.34018 + 504.48616.33020 + 504.48616.40018 + 504.48516.34016 + 504.48516.33013 + 505.48516.40018 + 505.48516.46015 + 505.48516.53018 + 505.48416.67018 + 505.48416.73015 + 506.48416.67019 + 506.48416.63018 + 506.48416.53017 + 506.48416.49020 + 506.48316.47019 + 505.48316.22019 + 506.48316.06022 + 506.48315.93022 + 506.48315.93023 + 506.48215.86023 + 506.48215.70019 + 506.48215.51021 + 506.48215.60020 + 505.48215.62015 + 505.48215.69018 + 505.48115.75021 + 505.48115.75018 + 504.48115.88020 + 504.48115.95017 + 503.48116.14020 + 502.48116.24025 + 502.48016.39022 + 502.48016.46021 + 502.48016.49018 + 501.48016.11021 + 501.48016.22021 + 500.48016.41027 + 501.48016.19024 + 501.47916.33023 + 500.47916.34019 + 500.47916.94018 + 499.47917.00020 + 499.47917.08020 + 499.47917.13019 + 499.47917.24020 + 498.47817.03018 + 497.47817.09016 + 497.47817.09020 + 496.47816.93018 + 496.47816.69015 + 496.47816.59019 + 496.47716.37015 + 496.47716.25020 + 496.47715.56016 + 496.47714.87017 + 496.47714.24019 + 496.47713.60018 + 495.47613.25014 + 495.47613.34016 + 495.47613.81019 + 495.47614.07014 + 495.47613.87015 + 495.47613.68014 + 495.47613.65018 + 496.47513.71019 + 496.47513.64021 + 496.47513.67019 + 496.47512.00019 + 497.47510.55020 + 497.47510.47022 + 497.47511.60020 + 497.47413.22019 + 498.47414.71018 + 498.47416.05020 + 499.47416.28021 + 499.47416.61019 + 499.47416.87016 + 499.47317.04017 + 498.47317.02021 + 497.47316.86019 + 496.47316.83021 + 495.47316.90020 + 494.47316.97022 + 494.47317.09019 + 493.47317.13019 + 493.47317.21010 + 493.47217.2303 + 492.47217.220 + 492.47217.240 + 492.47217.270 + 492.47217.360 + 492.47217.450 + 492.47217.590 + 491.47217.800 + 491.47217.920 + 491.47217.31012 + 491.47217.25016 + 490.47216.99020 + 489.47216.81018 + 489.47316.73020 + 489.47316.67013 + 488.47316.52016 + 489.47316.58018 + 489.47316.60016 + 488.47316.62017 + 488.47316.65017 + 488.47316.56016 + 487.47316.51017 + 486.47316.43020 + 486.47316.42019 + 486.47316.40018 + 486.47316.42020 + 486.47316.41019 + 486.47316.39020 + 486.47316.44019 + 486.47316.43021 + 486.47316.40020 + 487.47316.46020 + 488.47316.37020 + 488.47316.31018 + 487.47316.24017 + 487.47316.26016 + 487.47316.34020 + 487.47316.35017 + 487.47316.48018 + 487.47316.65015 + 486.47216.77021 + 487.47217.15019 + 486.47217.13017 + 486.47217.19019 + 486.47216.93017 + 485.47216.93017 + 485.47216.90018 + 485.47116.99015 + 485.47117.04014 + 485.47117.07016 + 485.47117.14014 + 484.47116.96013 + 485.47016.89013 + 485.47016.70013 + 484.47016.58011 + 484.47016.18010 + 484.47015.91011 + 484.46915.64011 + 484.46915.5605 + 484.46915.5101 + 484.46915.270 + 484.46915.020 + 485.46914.980 + 486.46814.90012 + 487.46814.04010 + 487.46813.56011 + 488.46813.37012 + 489.46813.20012 + 488.46812.87015 + 488.46812.88016 + 488.46712.98019 + 488.46713.11020 + 489.46713.31017 + 489.46713.51019 + 489.46713.70018 + 490.46713.63019 + 490.46613.66019 + 490.46613.60020 + 491.46613.64017 + 491.46613.57019 + 492.46613.71018 + 492.46613.69021 + 491.46613.68017 + 490.46513.62022 + 489.46513.51021 + 489.46513.62019 + 489.46513.75021 + 489.46513.86020 + 489.46513.78010 + 489.46413.98013 + 489.46413.8309 + 490.46414.14013 + 491.46414.30018 + 492.46414.46015 + 493.46414.69015 + 494.46314.92017 + 494.46315.08016 + 494.46315.20015 + 495.46315.12013 + 495.46314.92011 + 495.46314.7408 + 495.46214.5009 + 495.46214.22012 + 495.46214.22012 + 495.46214.08011 + 494.46213.9008 + 494.46213.86011 + 494.46213.88012 + 494.46113.75018 + 494.46113.53015 + 494.46113.38015 + 494.46113.36016 + 494.46113.31013 + 494.46113.19017 + 494.46013.08018 + 494.46012.84014 + 495.46012.99017 + 495.46013.02017 + 495.46012.92018 + 495.46013.01019 + 496.45913.03019 + 496.45912.91016 + 496.45912.45016 + 496.45912.14017 + 495.45911.80015 + 495.45911.40013 + 496.45911.02016 + 496.45910.47014 + 496.4588.12016 + 497.4585.08015 + 497.4580.01019 + 497.4580.00022 + 497.4580.00015 + 497.4580.01020 + 497.4580.00020 + 497.4580.01020 + 501.4584.50019 + 500.4587.57021 + 500.4589.97024 + 500.45810.93023 + 500.45711.53019 + 499.45711.95020 + 499.45712.62020 + 498.45712.90021 + 498.45713.08022 + 498.45713.10021 + 498.45713.00022 + 497.45712.84023 + 497.45712.74023 + 497.45712.94019 + 497.45712.98019 + 496.45713.04020 + 496.45713.02018 + 496.45712.99016 + 496.45712.77013 + 495.45712.95019 + 495.45613.01021 + 495.45613.03019 + 495.45613.09021 + 494.45613.18021 + 494.45613.22019 + 493.45613.18016 + 493.45613.31015 + 493.45613.50014 + 493.45613.66015 + 493.45613.53017 + 493.45613.50019 + 493.45613.34025 + 492.45613.22023 + 492.45613.32019 + 492.45613.20015 + 493.45613.52016 + 492.45513.44018 + 493.45513.43019 + 492.45513.54019 + 492.45513.88018 + 492.45514.10017 + 491.45514.13018 + 490.45513.94017 + 490.45513.77019 + 490.45513.61019 + 490.45513.39019 + 490.45513.19026 + 491.45513.04018 + 491.45512.84018 + 491.45512.51017 + 491.45511.62017 + 491.45510.69017 + 491.4548.35019 + 492.4544.63018 + 494.4543.62021 + 494.4544.09022 + 494.4545.68023 + 494.4548.18016 + 495.4549.63015 + 495.4539.90018 + 496.4539.61015 + 496.4538.64017 + 497.4535.77013 + 497.4533.90018 + 497.4536.19015 + 497.4537.15014 + 497.4537.91014 + 498.4527.99013 + 498.4527.95017 + 498.4527.32020 + 498.4526.05014 + 498.4524.15017 + 498.4525.16021 + 499.4526.32017 + 499.4526.10019 + 499.4526.54018 + 499.4526.95015 + 499.4517.29013 + 500.4517.77015 + 500.4517.39019 + 499.4517.37017 + 500.4517.12014 + 501.4516.49017 + 501.4505.12016 + 501.4505.44014 + 502.4507.18014 + 502.4507.35018 + 502.4507.04017 + 502.4506.17016 + 501.4504.89016 + 501.4493.97014 + 502.4491.34019 + + + + + \ No newline at end of file diff --git a/common/data/src/main/res/raw/vh.gpx b/common/data/src/main/res/raw/vh.gpx new file mode 100644 index 0000000..978df5f --- /dev/null +++ b/common/data/src/main/res/raw/vh.gpx @@ -0,0 +1,678 @@ + + + + + + + + + + + + + + + +GPS Logger 20260101-113817 +Vh + +car + + + + Track 20260101-113817 + + 500.4491.56024 + 490.4494.69020 + 488.4493.14020 + 486.4493.89013 + 486.4493.75013 + 488.4494.87017 + 493.4492.52018 + 497.4484.19014 + 499.4485.71020 + 497.4486.86023 + 496.4487.36014 + 496.4488.11014 + 497.4487.29017 + 497.4486.71019 + 498.4488.50018 + 498.4487.38019 + 500.4485.75018 + 501.4483.59021 + 501.4485.58020 + 501.4486.41021 + 501.4487.98018 + 500.4498.59019 + 500.4498.47016 + 498.4498.77019 + 497.4496.98014 + 497.4498.29015 + 496.4508.20014 + 495.4508.28014 + 494.4507.83014 + 494.4507.66018 + 493.4507.36018 + 493.4507.79016 + 493.4518.87014 + 493.4518.87016 + 493.4518.86013 + 494.4518.81015 + 494.4518.03017 + 494.4526.94015 + 493.4526.27014 + 494.4526.50018 + 494.4528.45017 + 494.4528.41017 + 494.4527.22023 + 494.4535.20016 + 494.4533.16022 + 495.4535.09019 + 495.4539.18017 + 495.45310.11017 + 495.45311.46017 + 495.45312.68018 + 495.45313.25020 + 495.45313.54017 + 496.45314.22021 + 496.45315.06020 + 496.45315.11020 + 497.45415.11018 + 497.45413.93019 + 496.45413.28021 + 496.45412.13021 + 495.45411.19019 + 495.45410.10018 + 494.4548.43019 + 493.4546.58015 + 492.4543.50018 + 491.4540.01018 + 491.4540.00018 + 491.4540.00016 + 491.4540.24015 + 491.4548.20018 + 492.45411.59019 + 492.45412.66016 + 492.45413.62017 + 492.45414.57018 + 492.45414.23018 + 492.45514.33019 + 492.45516.24018 + 492.45516.57020 + 493.45515.25018 + 493.45513.63019 + 494.45514.29018 + 494.45514.38018 + 494.45514.71020 + 494.45510.96021 + 494.45510.63014 + 494.4559.98017 + 494.4558.62016 + 494.4556.47015 + 493.4555.31014 + 493.4550.02015 + 493.4550.00014 + 493.4550.00018 + 492.4550.21018 + 493.4568.30016 + 492.45610.80018 + 492.45611.34022 + 491.45612.56019 + 491.45612.77016 + 491.45613.57017 + 490.45613.85017 + 490.45614.12018 + 491.45614.03018 + 490.45613.93018 + 490.45614.16022 + 491.45614.54019 + 492.45614.93019 + 493.45614.71019 + 494.45615.12021 + 495.45715.22019 + 495.45714.95018 + 496.45714.76020 + 496.45714.43017 + 496.45714.00022 + 496.45713.98019 + 496.45714.11020 + 496.45713.44019 + 496.45713.06020 + 497.45712.98022 + 497.45712.71020 + 497.45711.89021 + 497.45711.60024 + 497.45710.45026 + 497.4577.56026 + 498.4584.53022 + 499.4580.02019 + 499.4580.00021 + 499.4580.01021 + 498.4585.77021 + 499.4588.16022 + 499.4587.28019 + 499.4585.31019 + 500.4582.90024 + 501.4584.26023 + 500.4587.69024 + 499.4589.71021 + 498.45811.52021 + 497.45812.59019 + 496.45913.05022 + 495.45913.37022 + 494.45913.66021 + 493.45913.86013 + 493.45914.15014 + 493.45914.25014 + 493.46014.34015 + 492.46014.43014 + 492.46014.34011 + 492.46014.3609 + 491.46014.2708 + 491.46014.1308 + 491.46114.0707 + 491.46113.7709 + 490.46113.3709 + 490.46113.0309 + 490.46112.9509 + 490.46113.2709 + 489.46214.36012 + 489.46215.53011 + 489.46216.1909 + 489.46215.70013 + 489.46215.0309 + 489.46214.99015 + 488.46315.00013 + 488.46315.80015 + 487.46316.55014 + 488.46316.47011 + 489.46316.28011 + 488.46416.08015 + 488.46416.06013 + 488.46415.87012 + 488.46415.93013 + 487.46416.19016 + 486.46416.56016 + 485.46516.50015 + 485.46516.34013 + 485.46516.13020 + 484.46515.98013 + 484.46515.72013 + 483.46615.69014 + 483.46615.36015 + 483.46615.21017 + 483.46615.06014 + 483.46615.45014 + 482.46615.73015 + 483.46716.03014 + 483.46716.20012 + 483.46716.39016 + 483.46716.53012 + 482.46716.57012 + 482.46816.64013 + 481.46816.64015 + 480.46816.73016 + 480.46817.00018 + 480.46817.31015 + 480.46917.59017 + 481.46917.63015 + 480.46917.56016 + 481.46917.55011 + 481.46917.3207 + 481.46916.9705 + 481.47016.550 + 481.47016.370 + 481.47016.4108 + 482.47016.9307 + 483.47016.44012 + 483.47116.42015 + 483.47116.33015 + 484.47116.24016 + 485.47116.04015 + 485.47115.81016 + 484.47215.70014 + 485.47215.56013 + 484.47215.71014 + 484.47215.43013 + 484.47215.10015 + 484.47215.17016 + 485.47214.99014 + 485.47214.68016 + 486.47314.60015 + 486.47314.77017 + 487.47314.91017 + 487.47315.26016 + 487.47315.62017 + 487.47315.79017 + 488.47315.79018 + 488.47315.81015 + 489.47315.90018 + 489.47315.95016 + 489.47315.99017 + 490.47316.13012 + 490.47316.12016 + 490.47216.12016 + 491.47215.97015 + 490.47215.71017 + 490.47215.79016 + 491.47215.79018 + 491.47215.69015 + 492.47215.47018 + 492.47215.19013 + 492.47215.24017 + 492.47215.31018 + 493.47215.19018 + 493.47215.06018 + 494.47215.10018 + 494.47215.31017 + 493.47215.53018 + 494.47215.65017 + 494.47215.84019 + 493.47215.83017 + 493.47215.87016 + 493.47216.00018 + 492.47215.96019 + 492.47215.94019 + 491.47215.90019 + 491.47215.69017 + 491.47215.63017 + 491.47215.48012 + 491.47215.41012 + 491.47215.30011 + 491.47215.1304 + 491.47214.880 + 491.47214.720 + 491.47214.760 + 492.47214.850 + 492.47214.940 + 492.47215.140 + 492.47215.310 + 492.47215.490 + 492.47215.640 + 493.47215.720 + 496.47315.72021 + 497.47315.81020 + 498.47415.89024 + 499.47415.94023 + 499.47416.09023 + 499.47416.14024 + 499.47416.22021 + 499.47416.28027 + 499.47516.40024 + 499.47516.50018 + 499.47516.50021 + 498.47516.39017 + 498.47516.12022 + 498.47516.01018 + 498.47615.93016 + 498.47615.92019 + 498.47615.91018 + 498.47615.78016 + 499.47615.80012 + 499.47615.30015 + 499.47714.45015 + 499.47714.33016 + 499.47714.79017 + 499.47715.57013 + 499.47716.06018 + 500.47716.15012 + 500.47816.31016 + 500.47816.52015 + 500.47816.36014 + 500.47816.24014 + 500.47816.23014 + 499.47816.32015 + 499.47916.48013 + 500.47916.69017 + 500.47916.78015 + 500.47916.83021 + 501.47916.84015 + 501.47916.92013 + 500.47917.21015 + 501.48017.30016 + 501.48017.48019 + 500.48017.34018 + 501.48017.14017 + 501.48016.97014 + 502.48016.89016 + 501.48016.81017 + 501.48116.77016 + 501.48116.85015 + 501.48116.97016 + 502.48116.95018 + 502.48116.88014 + 502.48116.91015 + 502.48216.99017 + 502.48217.12016 + 501.48217.04020 + 501.48217.06022 + 501.48217.08022 + 501.48316.98011 + 501.48316.73019 + 501.48316.72015 + 501.48316.56016 + 501.48316.50018 + 500.48416.47015 + 501.48416.50017 + 500.48416.59021 + 500.48416.65020 + 500.48416.66019 + 500.48416.72020 + 499.48516.81022 + 499.48516.70022 + 500.48516.68016 + 499.48516.66013 + 499.48516.63016 + 499.48616.48015 + 499.48616.61016 + 499.48616.62013 + 499.48616.44015 + 499.48616.24011 + 499.48716.22016 + 498.48716.20016 + 498.48716.16015 + 498.48716.14019 + 498.48716.07017 + 498.48715.94014 + 498.48815.85019 + 497.48815.87016 + 497.48815.92016 + 497.48815.77019 + 497.48815.64014 + 497.48915.85013 + 498.48916.10013 + 498.48916.23018 + 499.48916.25014 + 499.48916.25014 + 500.48916.19011 + 500.49015.96017 + 500.49015.83019 + 501.49015.53016 + 501.49015.39011 + 501.49015.32011 + 501.49015.60011 + 502.49115.76021 + 502.49115.86019 + 502.49116.00024 + 501.49115.99022 + 500.49115.93011 + 500.49115.90015 + 500.49216.05013 + 500.49215.97013 + 500.49216.11014 + 500.49216.09014 + 500.49216.0105 + 499.49215.9001 + 499.49315.5901 + 500.49315.370 + 500.49315.410 + 501.49315.19011 + 502.49315.0208 + 503.49315.3509 + 505.49415.34011 + 506.49414.83012 + 507.49415.60014 + 508.49414.98014 + 509.49414.79014 + 508.49414.83014 + 508.49414.69013 + 508.49414.66017 + 508.49414.68016 + 508.49514.80016 + 508.49514.83013 + 508.49514.96013 + 506.49515.02013 + 506.49515.22010 + 505.49515.51013 + 503.49515.88012 + 503.49516.19011 + 502.49516.33012 + 502.49516.4505 + 502.49516.4104 + 502.49516.450 + 502.49516.600 + 502.49516.750 + 502.49516.8901 + 503.49616.930 + 503.49616.830 + 503.49616.840 + 503.49616.720 + 503.49616.500 + 523.50117.17017 + 521.50117.03019 + 522.50117.76022 + 523.50117.00022 + 526.50116.35020 + 514.50214.48014 + 516.50214.48010 + 516.50214.40014 + 516.50213.85014 + 515.50213.67013 + 514.50213.56013 + 512.50213.30010 + 512.50313.46012 + 513.50312.63010 + 513.50313.57013 + 514.50313.70014 + 513.50313.60014 + 512.50313.83012 + 515.50313.79012 + 514.50313.73011 + 520.50315.88018 + 522.50315.81019 + 520.50315.31022 + 520.50314.88018 + 520.50314.85020 + 520.50314.87018 + 520.50314.89017 + 519.50314.98017 + 518.50314.92017 + 518.50312.94021 + 518.50310.30020 + 518.5035.72019 + 519.5030.01018 + 519.5030.00015 + 519.5030.00016 + 519.5030.02018 + 520.5037.52021 + 519.50310.38020 + 519.50311.40019 + 519.50312.38018 + 519.50312.93019 + 519.50313.29019 + 519.50313.61017 + 519.50313.72017 + 519.50313.74015 + 519.50313.80013 + 518.50313.98018 + 518.50313.98015 + 518.50313.86016 + 518.50313.62013 + 518.50312.82015 + 518.50311.81016 + 519.50310.49015 + 519.5039.27019 + 520.5037.56019 + 519.5035.08018 + 519.5033.12024 + 520.5037.62023 + 520.50311.03023 + 520.50311.91023 + 520.50312.66022 + 520.50312.85022 + 520.50413.11019 + 520.50413.40018 + 521.50413.51018 + 521.50413.37022 + 521.50413.42015 + 521.50413.38019 + 521.50413.26018 + 521.50413.08021 + 521.50412.96019 + 521.50412.95020 + 521.50412.88021 + 521.50413.09018 + 521.50413.21018 + 521.50413.29018 + 522.50413.33021 + 522.50413.45020 + 523.50413.45022 + 523.50413.23020 + 523.50412.90017 + 523.50412.59019 + 523.50412.26020 + 523.50411.88015 + 523.50411.09016 + 523.50410.16016 + 524.5058.31019 + 523.5055.33016 + 523.5050.01016 + 523.5050.00017 + 523.5050.02017 + 525.5055.28022 + 525.5055.41023 + 525.5058.10020 + 525.5049.84022 + 525.50410.58021 + 524.50411.45020 + 524.50411.98020 + 524.50412.23017 + 524.50412.41017 + 524.50412.40016 + 524.50312.34019 + 524.50312.35021 + 524.50312.37024 + 524.50312.45022 + 524.50312.61021 + 524.50312.78020 + 524.50312.86022 + 524.50212.85020 + 524.50212.88021 + 524.50212.77017 + 524.50212.75017 + 524.50212.75017 + 524.50212.88017 + 524.50213.05021 + 525.50213.22017 + 525.50113.25019 + 525.50113.22013 + 525.50113.53020 + 525.50113.98019 + 525.50114.16016 + 526.50114.32020 + 526.50114.45018 + 526.50014.51019 + 526.50014.48013 + 526.50014.16017 + 526.50013.77017 + 527.50013.46021 + 527.50013.26022 + 527.50013.19019 + 527.49912.85018 + 527.49912.77020 + 527.49912.91025 + 527.49913.13022 + 526.49913.30022 + 526.49913.27020 + 527.49913.41023 + 526.49913.49019 + 526.49913.50019 + 526.49913.42019 + 526.49813.28023 + 525.49813.17020 + 525.49813.18021 + 525.49813.27020 + 525.49813.29020 + 525.49813.34020 + 525.49813.39014 + 525.49813.27015 + 525.49713.18019 + 525.49713.20016 + 525.49713.03013 + 525.49712.82019 + 525.49712.76017 + 525.49712.76020 + 525.49712.78022 + 526.49712.74020 + 525.49712.66017 + 526.49612.52018 + 526.49612.31017 + 526.49612.04018 + 526.49611.39019 + 526.49610.37019 + 526.4967.66014 + 527.4964.72013 + 528.4960.02020 + 528.4960.00019 + 528.4960.02020 + 528.4960.01021 + 528.4960.00021 + 528.4960.00020 + 528.4960.01018 + 528.4960.01020 + 528.4960.00020 + 528.4960.00020 + 528.4960.01019 + 528.4960.00020 + 528.4960.03019 + 528.4967.59020 + 528.49510.48023 + 528.49511.13023 + 528.49511.87020 + 528.49512.21018 + 528.49512.23018 + 528.49512.25018 + 528.49512.37019 + 528.49512.65017 + 529.49512.94018 + 529.49413.05018 + 528.49413.19015 + 528.49413.24014 + 529.49413.26016 + 529.49413.23016 + 529.49413.18016 + 529.49413.40017 + 529.49413.52019 + 529.49313.61018 + 529.49313.75018 + 528.49313.98018 + 528.49314.08017 + 528.49314.19014 + 527.49314.33017 + 526.49314.49018 + 526.49314.50018 + 526.49314.29018 + 527.49214.15018 + 527.49214.19013 + 528.49214.04018 + 528.49213.88013 + 529.49213.57014 + 529.49212.92015 + 530.49211.57016 + 530.4929.78018 + 531.4925.89022 + 531.4914.55017 + 531.4926.33019 + 531.4927.89011 + 533.4928.87020 + 534.4928.81021 + 535.49210.0409 + 535.49210.12020 + 537.4929.43025 + 539.4929.74023 + 540.4929.89020 + 541.4928.8709 + 542.4926.7709 + 543.4922.69015 + 534.4920.07017 + 534.4920.00014 + 534.4920.68017 + + + + + \ No newline at end of file diff --git a/common/data/src/main/res/values-de/strings.xml b/common/data/src/main/res/values-de/strings.xml index 63b578c..8a38e4b 100644 --- a/common/data/src/main/res/values-de/strings.xml +++ b/common/data/src/main/res/values-de/strings.xml @@ -47,5 +47,6 @@ Apotheke Ladestation Speed camera + Auto Location verwenden diff --git a/common/data/src/main/res/values/strings.xml b/common/data/src/main/res/values/strings.xml index 38bb54d..e5b0030 100644 --- a/common/data/src/main/res/values/strings.xml +++ b/common/data/src/main/res/values/strings.xml @@ -30,7 +30,8 @@ Reject OK Search - Valhalla - Osrm - Routing engine + Valhalla + Osrm + Routing engine + Use car location \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 4078229..a28c095 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,6 +16,10 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { + url = uri("https://jitpack.io") + } + } }