diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f4a3a22..6ec8ca3 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 = 36 - versionName = "0.2.0.36" + versionCode = 38 + versionName = "0.2.0.38" base.archivesName = "navi-$versionName" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } 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 af40bc1..7ba1186 100644 --- a/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt +++ b/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt @@ -87,8 +87,8 @@ class MainActivity : ComponentActivity() { val routeModel = RouteModel() var tilt = 50.0 - val useMock = true - val type = 1 // simulate 2 test 3 gpx + val useMock = false + val type = 3 // simulate 2 test 3 gpx 4 testSingle var currentIndex = 0 val stepData: MutableLiveData by lazy { @@ -109,14 +109,15 @@ class MainActivity : ComponentActivity() { 3 -> gpx( context = applicationContext ) + + 4 -> testSingle() } } } } val cameraPosition = MutableLiveData( CameraPosition( - zoom = 15.0, - target = Position(latitude = 48.1857475, longitude = 11.5793627) + zoom = 15.0, target = Position(latitude = 48.1857475, longitude = 11.5793627) ) ) @@ -140,17 +141,15 @@ class MainActivity : ComponentActivity() { } locationManager = getSystemService(LOCATION_SERVICE) as LocationManager fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) - fusedLocationClient.lastLocation - .addOnSuccessListener { _: android.location.Location? -> - if (useMock) { - mock = MockLocation(locationManager) - mock.setMockLocation( - homeVogelhart.latitude, - homeVogelhart.longitude - ) - navigationViewModel.route.observe(this, observer) - } + fusedLocationClient.lastLocation.addOnSuccessListener { _: android.location.Location? -> + if (useMock) { + mock = MockLocation(locationManager) + mock.setMockLocation( + homeVogelhart.latitude, homeVogelhart.longitude + ) + navigationViewModel.route.observe(this, observer) } + } enableEdgeToEdge() setContent { CheckPermissionScreen() @@ -196,8 +195,7 @@ class MainActivity : ComponentActivity() { val sheetPeekHeightState = remember { mutableStateOf(256.dp) } val locationProvider = rememberDefaultLocationProvider( - updateInterval = 0.5.seconds, - desiredAccuracy = DesiredAccuracy.Highest + updateInterval = 0.5.seconds, desiredAccuracy = DesiredAccuracy.Highest ) val userLocationState = rememberUserLocationState(locationProvider) val locationState = locationProvider.location.collectAsState() @@ -263,12 +261,10 @@ class MainActivity : ComponentActivity() { @Composable fun Settings(navController: NavController, modifier: Modifier = Modifier) { Box( - modifier = Modifier - .fillMaxSize() + modifier = Modifier.fillMaxSize() ) { FloatingActionButton( - modifier = Modifier - .padding(start = 10.dp, top = 40.dp), + modifier = Modifier.padding(start = 10.dp, top = 40.dp), onClick = { navController.navigate("settings") }, @@ -284,44 +280,35 @@ class MainActivity : ComponentActivity() { @Composable fun SheetContent( - locationState: Double, - step: StepData?, - nextStep: StepData?, - closeSheet: () -> Unit + locationState: Double, step: StepData?, nextStep: StepData?, closeSheet: () -> Unit ) { if (!routeModel.isNavigating()) { SearchSheet(applicationContext, navigationViewModel, lastLocation) { closeSheet() } } else { NavigationSheet( applicationContext, - routeModel, step!!, nextStep!!, + routeModel, + step!!, + nextStep!!, { stopNavigation { closeSheet() } }, - { simulateNavigation() } - ) + { simulateNavigation() }) } // For recomposition! Text("$locationState", fontSize = 12.sp) } fun updateLocation(location: Location?) { - if (location != null - && lastLocation.latitude != location.position.latitude - && lastLocation.longitude != location.position.longitude - ) { + if (location != null && lastLocation.latitude != location.position.latitude && lastLocation.longitude != location.position.longitude) { val currentLocation = location(location.position.longitude, location.position.latitude) val bearing = bearing(lastLocation, currentLocation, cameraPosition.value!!.bearing) with(routeModel) { if (isNavigating()) { updateLocation(currentLocation, navigationViewModel) stepData.value = currentStep() - if (route.currentStepIndex + 1 <= curLeg.steps.size) { - nextStepData.value = nextStep() - } - if (maneuverType in 39..42 - && routeCalculator.leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE - ) { + nextStepData.value = nextStep() + if (navState.maneuverType in 39..42 && routeCalculator.leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE) { // stopNavigation() - arrived = true + navState.copy(arrived = true) routeData.value = "" } } @@ -329,9 +316,7 @@ class MainActivity : ComponentActivity() { val zoom = calculateZoom(location.speed) cameraPosition.postValue( cameraPosition.value!!.copy( - zoom = zoom, - target = location.position, - bearing = bearing + zoom = zoom, target = location.position, bearing = bearing ), ) lastLocation = currentLocation @@ -351,7 +336,7 @@ class MainActivity : ComponentActivity() { 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() { @@ -361,14 +346,10 @@ class MainActivity : ComponentActivity() { private fun checkMockLocationEnabled() { try { // Check if mock location is enabled for this app - val appOpsManager = - getSystemService(APP_OPS_SERVICE) as AppOpsManager - val mode = - appOpsManager.checkOp( - AppOpsManager.OPSTR_MOCK_LOCATION, - Process.myUid(), - packageName - ) + val appOpsManager = getSystemService(APP_OPS_SERVICE) as AppOpsManager + val mode = appOpsManager.checkOp( + AppOpsManager.OPSTR_MOCK_LOCATION, Process.myUid(), packageName + ) if (mode != AppOpsManager.MODE_ALLOWED) { Toast.makeText( @@ -389,7 +370,7 @@ class MainActivity : ComponentActivity() { val deviation = 0.0 if (index in 0..routeModel.curRoute.waypoints.size) { mock.setMockLocation(waypoint[1], waypoint[0]) - delay(500L) // + Thread.sleep(500) } } } @@ -399,26 +380,36 @@ class MainActivity : ComponentActivity() { fun test() { for ((index, step) in routeModel.curLeg.steps.withIndex()) { //if (index in 3..3) { - for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) { - routeModel.updateLocation( - location(waypoint[0], waypoint[1]), - navigationViewModel - ) - val step = routeModel.currentStep() - println("Step: ${step.instruction} ${step.leftStepDistance}") - if (index + 1 <= routeModel.curLeg.steps.size) { - //nextStepData.value = routeModel.nextStep() - } - } + for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) { + routeModel.updateLocation( + location(waypoint[0], waypoint[1]), navigationViewModel + ) + val step = routeModel.currentStep() + val nextStep = routeModel.nextStep() + println("Step: ${step.instruction} ${step.leftStepDistance} ${nextStep.currentManeuverType}") + } //} } } - fun test2() { - CoroutineScope(Dispatchers.IO).launch { - // Balanstr. - mock.setMockLocation(48.119357, 11.599130) + fun testSingle() { + testSingleUpdate(48.185976, 11.578463) // Silcherstr. 23-13 + testSingleUpdate(48.186712, 11.578574) // Silcherstr. 27-33 + testSingleUpdate(48.186899, 11.580480) // Schmalkadenerstr. 24-28 + } + + fun testSingleUpdate(latitude: Double, longitude: Double) { + if (1 == 1) { + mock.setMockLocation(latitude, longitude) + } else { + routeModel.updateLocation( + location(longitude, latitude), navigationViewModel + ) } + val step = routeModel.currentStep() + val nextStep = routeModel.nextStep() + println("Step: ${step.instruction} ${step.leftStepDistance} ${nextStep.currentManeuverType}") + Thread.sleep(1_000) } fun gpx(context: Context) { diff --git a/app/src/main/java/com/kouros/navigation/ui/NavigationSheet.kt b/app/src/main/java/com/kouros/navigation/ui/NavigationSheet.kt index 68f394b..798925a 100755 --- a/app/src/main/java/com/kouros/navigation/ui/NavigationSheet.kt +++ b/app/src/main/java/com/kouros/navigation/ui/NavigationSheet.kt @@ -34,7 +34,7 @@ fun NavigationSheet( val distance = (step.leftDistance / 1000).round(1) if (step.lane.isNotEmpty()) { - routeModel.iconMapper.addLanes( step) + routeModel.navState.iconMapper.addLanes( step) } Column { diff --git a/build.gradle.kts b/build.gradle.kts index a32a614..c40487e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,6 @@ buildscript { val objectboxVersion by extra("5.0.1") // For KTS build scripts dependencies { - // Android Gradle Plugin 8.0 or later supported classpath(libs.gradle) classpath("io.objectbox:objectbox-gradle-plugin:$objectboxVersion") } 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 bb5476a..7930831 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 @@ -251,11 +251,11 @@ class NavigationSession : Session(), NavigationScreen.Listener { fun updateLocation(location: Location) { if (routeModel.isNavigating()) { navigationScreen.updateTrip(location) - if (!routeModel.arrived) { + if (!routeModel.navState.arrived) { val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations()) val distance = location.distanceTo(snapedLocation) if (distance > MAXIMAL_ROUTE_DEVIATION) { - navigationScreen.calculateNewRoute(routeModel.destination) + navigationScreen.calculateNewRoute(routeModel.navState.destination) return } if (distance < MAXIMAL_SNAP_CORRECTION) { diff --git a/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt b/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt index f90064a..6340255 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt @@ -470,7 +470,7 @@ fun DebugInfo( contentAlignment = Alignment.CenterStart ) { val textMeasurerLocation = rememberTextMeasurer() - val location = routeModel.currentLocation.latitude.toString() + val location = routeModel.navState.currentLocation.latitude.toString() val styleSpeed = TextStyle( fontSize = 26.sp, fontWeight = FontWeight.Bold, 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 edd0c8c..a8df211 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 @@ -68,8 +68,8 @@ class RouteCarModel() : RouteModel() { .setManeuver( maneuver.build() ) - if (destination.street != null) { - step.setRoad(destination.street!!) + if (navState.destination.street != null) { + step.setRoad(navState.destination.street!!) } if (stepData.lane.isNotEmpty()) { addLanes(carContext, step, stepData) @@ -127,9 +127,9 @@ class RouteCarModel() : RouteModel() { .setRemainingTimeColor(CarColor.GREEN) .setRemainingDistanceColor(CarColor.BLUE) - if (travelMessage.isNotEmpty()) { + if (navState.travelMessage.isNotEmpty()) { travelBuilder.setTripIcon(createCarIcon(carContext, R.drawable.warning_24px)) - travelBuilder.setTripText(CarText.create(travelMessage)) + travelBuilder.setTripText(CarText.create(navState.travelMessage)) } return travelBuilder.build() } @@ -147,10 +147,10 @@ class RouteCarModel() : RouteModel() { "${direction}_${it2.trim()}" } } - val laneDirection = iconMapper.addLanes(direction, stepData) + val laneDirection = navState.iconMapper.addLanes(direction, stepData) if (laneDirection != LaneDirection.SHAPE_UNKNOWN) { if (!laneImageAdded) { - step.setLanesImage(createCarIcon(iconMapper.createLaneIcon(carContext, stepData))) + step.setLanesImage(createCarIcon(navState.iconMapper.createLaneIcon(carContext, stepData))) laneImageAdded = true } val laneType = diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/CategoryScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/CategoryScreen.kt index fb2223d..53bcd12 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/CategoryScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/CategoryScreen.kt @@ -44,10 +44,10 @@ class CategoryScreen( val loc = location(0.0, 0.0) elements.forEach { if (loc.latitude == 0.0) { - loc.longitude = it.lon!! - loc.latitude = it.lat!! + loc.longitude = it.lon + loc.latitude = it.lat } - coordinates.add(listOf(it.lon!!, it.lat!!)) + coordinates.add(listOf(it.lon, it.lat)) } if (elements.isNotEmpty()) { val route = createPointCollection(coordinates, category) @@ -111,7 +111,7 @@ class CategoryScreen( } val row = Row.Builder() .setOnClickListener { - val location = location(it.lon!!, it.lat!!) + val location = location(it.lon, it.lat) surfaceRenderer.setCategoryLocation(location, category) } .setTitle(name) 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 0f9c62a..afc2220 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 @@ -31,16 +31,12 @@ import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE import com.kouros.navigation.data.Place import com.kouros.navigation.data.nominatim.SearchResult import com.kouros.navigation.data.overpass.Elements -import com.kouros.navigation.data.tomtom.Features -import com.kouros.navigation.data.tomtom.Geometry import com.kouros.navigation.model.ViewModel import com.kouros.navigation.utils.GeoUtils import com.kouros.navigation.utils.location import java.time.LocalDateTime -import java.time.Period import java.time.ZoneOffset import kotlin.math.absoluteValue -import kotlin.time.Duration class NavigationScreen( carContext: CarContext, @@ -154,11 +150,11 @@ class NavigationScreen( } private fun navigationEndTemplate(actionStripBuilder: ActionStrip.Builder): Template { - if (routeModel.arrived) { + if (routeModel.navState.arrived) { val timer = object : CountDownTimer(8000, 1000) { override fun onTick(millisUntilFinished: Long) {} override fun onFinish() { - routeModel.arrived = false + routeModel.navState = routeModel.navState.copy(arrived = false) navigationType = NavigationType.VIEW invalidate() } @@ -177,8 +173,8 @@ class NavigationScreen( fun navigationArrivedTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate { var street = "" - if (routeModel.destination.street != null) { - street = routeModel.destination.street!! + if (routeModel.navState.destination.street != null) { + street = routeModel.navState.destination.street!! } return NavigationTemplate.Builder() .setNavigationInfo( @@ -316,7 +312,7 @@ class NavigationScreen( navigateTo, surfaceRenderer.carOrientation ) - routeModel.destination = recentPlace + routeModel.navState = routeModel.navState.copy(destination = recentPlace) } .build() } @@ -444,7 +440,7 @@ class NavigationScreen( location, surfaceRenderer.carOrientation ) - routeModel.destination = place + routeModel.navState = routeModel.navState.copy(destination = place) invalidate() } @@ -492,14 +488,14 @@ class NavigationScreen( updateSpeedCamera(location) with(routeModel) { updateLocation(location, viewModel) - if ((maneuverType == Maneuver.TYPE_DESTINATION - || maneuverType == Maneuver.TYPE_DESTINATION_LEFT - || maneuverType == Maneuver.TYPE_DESTINATION_RIGHT - || maneuverType == Maneuver.TYPE_DESTINATION_STRAIGHT) + if ((navState.maneuverType == Maneuver.TYPE_DESTINATION + || navState.maneuverType == Maneuver.TYPE_DESTINATION_LEFT + || navState.maneuverType == Maneuver.TYPE_DESTINATION_RIGHT + || navState.maneuverType == Maneuver.TYPE_DESTINATION_STRAIGHT) && routeCalculator.leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE ) { stopNavigation() - arrived = true + navState = navState.copy(arrived = true) surfaceRenderer.routeData.value = "" navigationType = NavigationType.ARRIVAL invalidate() 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 07e2283..3965270 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 @@ -124,7 +124,7 @@ class PlaceListScreen( setSpan( DistanceSpan.create( Distance.create( - it.distance.toDouble(), + (it.distance/1000).toDouble(), Distance.UNIT_KILOMETERS ) ), 0, 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt index 24030e9..822dc52 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt @@ -220,7 +220,7 @@ class RoutePreviewScreen( } private fun onRouteSelected(index: Int) { - routeModel.currentRouteIndex = index + routeModel.navState = routeModel.navState.copy(currentRouteIndex = index) surfaceRenderer.setPreviewRouteData(routeModel) //setResult(destination) //finish() 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 10c7ad6..f445df8 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 @@ -147,6 +147,10 @@ object Constants { const val DESTINATION_ARRIVAL_DISTANCE = 40.0 + const val NEAREST_LOCATION_DISTANCE = 10F + + const val MAXIMUM_LOCATION_DISTANCE = 100000F + } 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 95e07c4..e00f061 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 @@ -50,11 +50,10 @@ abstract class NavigationRepository { searchFilter: SearchFilter, context: Context ): Double { - //val route = getRoute(context, currentLocation, location, carOrientation, searchFilter) - //val routeModel = RouteModel() - //routeModel.startNavigation(route, context) - // return routeModel.curRoute.summary.distance - return 0.0 + val route = getRoute(context, currentLocation, location, carOrientation, searchFilter) + val routeModel = RouteModel() + routeModel.startNavigation(route, context) + return routeModel.curRoute.summary.distance } fun searchPlaces(search: String, location: Location): 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 b1281a3..8879603 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 @@ -26,7 +26,6 @@ data class Route( ) { data class Builder( - var routeEngine: Int = 0, var summary: Summary = Summary(), var routes: List = emptyList(), @@ -76,8 +75,6 @@ data class Route( return Route( routeEngine = 0, routes = emptyList(), - //waypoints = emptyList(), - //routeGeoJson = "", ) } } 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 4d1b4ca..e301f32 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 @@ -58,7 +58,7 @@ class OsrmRoute { } val step = Step( index = stepIndex, - name = step.name, + street = step.name, distance = step.distance / 1000, duration = step.duration, maneuver = maneuver, 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 8d43000..4a2ad02 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 @@ -9,4 +9,5 @@ data class Maneuver( val waypoints: List>, val location: Location, val exit: Int = 0, + val street: String = "", ) diff --git a/common/data/src/main/java/com/kouros/navigation/data/route/Step.kt b/common/data/src/main/java/com/kouros/navigation/data/route/Step.kt index 709ff1d..4e7a9cd 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/route/Step.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/route/Step.kt @@ -10,6 +10,6 @@ data class Step( val maneuver: Maneuver, val duration: Double = 0.0, val distance: Double = 0.0, - val name : String = "", + val street : String = "", val intersection: List = mutableListOf(), ) diff --git a/common/data/src/main/java/com/kouros/navigation/data/tomtom/Instruction.kt b/common/data/src/main/java/com/kouros/navigation/data/tomtom/Instruction.kt index 01afaa7..2f02250 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/tomtom/Instruction.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/tomtom/Instruction.kt @@ -14,7 +14,7 @@ data class Instruction( val roadNumbers: List, val routeOffsetInMeters: Int, val signpostText: String, - val street: String = "", + val street: String? = "", val travelTimeInSeconds: Int, val turnAngleInDecimalDegrees: Int, val exitNumber: String? = "0", diff --git a/common/data/src/main/java/com/kouros/navigation/data/tomtom/Route.kt b/common/data/src/main/java/com/kouros/navigation/data/tomtom/Route.kt index f83f4d9..5219b31 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/tomtom/Route.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/tomtom/Route.kt @@ -3,6 +3,6 @@ package com.kouros.navigation.data.tomtom data class Route( val guidance: Guidance, val legs: List, - val sections: List
, + val sections: List
?, val summary: SummaryX ) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/tomtom/TomTomRepository.kt b/common/data/src/main/java/com/kouros/navigation/data/tomtom/TomTomRepository.kt index 4e77006..0501d6c 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/tomtom/TomTomRepository.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/tomtom/TomTomRepository.kt @@ -18,6 +18,8 @@ val tomtomTrafficUrl = "https://api.tomtom.com/traffic/services/5/incidentDetail private val tomtomFields = "{incidents{type,geometry{type,coordinates},properties{iconCategory,events{description}}}}" +const val useAsset = false + class TomTomRepository : NavigationRepository() { override fun getRoute( context: Context, @@ -26,9 +28,11 @@ class TomTomRepository : NavigationRepository() { carOrientation: Float, searchFilter: SearchFilter ): String { - val routeJson = context.resources.openRawResource(R.raw.tomom_routing) - val routeJsonString = routeJson.bufferedReader().use { it.readText() } - return routeJsonString + if (useAsset) { + val routeJson = context.resources.openRawResource(R.raw.tomom_routing) + val routeJsonString = routeJson.bufferedReader().use { it.readText() } + return routeJsonString + } val url = routeUrl + "${currentLocation.latitude},${currentLocation.longitude}:${location.latitude},${location.longitude}" + "/json?vehicleHeading=90§ionType=traffic&report=effectiveSettings&routeType=eco" + @@ -44,7 +48,6 @@ class TomTomRepository : NavigationRepository() { } override fun getTraffic(context: Context, location: Location, carOrientation: Float): String { - val useAsset = true val bbox = calculateSquareRadius(location.latitude, location.longitude, 15.0) return if (useAsset) { val trafficJson = context.resources.openRawResource(R.raw.tomtom_traffic) diff --git a/common/data/src/main/java/com/kouros/navigation/data/tomtom/TomTomRoute.kt b/common/data/src/main/java/com/kouros/navigation/data/tomtom/TomTomRoute.kt index eac55af..3646081 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/tomtom/TomTomRoute.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/tomtom/TomTomRoute.kt @@ -37,24 +37,28 @@ class TomTomRoute { val steps = mutableListOf() var lastPointIndex = 0 for (index in 1..< route.guidance.instructions.size) { + val lastInstruction = route.guidance.instructions[index-1] val instruction = route.guidance.instructions[index] + val street = lastInstruction.street ?: "" + val maneuverStreet = instruction.street ?: "" val maneuver = RouteManeuver( bearingBefore = 0, bearingAfter = 0, type = convertType(instruction.maneuver), waypoints = points.subList( lastPointIndex, - instruction.pointIndex, + instruction.pointIndex+1, ), exit = exitNumber(instruction), location = location( instruction.point.longitude, instruction.point.latitude ), + street = maneuverStreet ) lastPointIndex = instruction.pointIndex val intersections = mutableListOf() - route.sections.forEach { section -> + route.sections?.forEach { section -> val lanes = mutableListOf() var startIndex = 0 if (section.startPointIndex <= instruction.pointIndex - 3 @@ -78,10 +82,9 @@ class TomTomRoute { allIntersections.addAll(intersections) stepDistance = route.guidance.instructions[index].routeOffsetInMeters - stepDistance stepDuration = route.guidance.instructions[index].travelTimeInSeconds - stepDuration - val name = instruction.street val step = Step( index = stepIndex, - name = name, + street = street, distance = stepDistance, duration = stepDuration, maneuver = maneuver, 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 0701739..14163f3 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 @@ -34,7 +34,7 @@ class ValhallaRoute { if (it.streetNames != null && it.streetNames.isNotEmpty()) { name = it.streetNames[0] } - val step = Step( index = stepIndex, name = name, distance = it.length, duration = it.time, maneuver = maneuver) + val step = Step( index = stepIndex, street = name, distance = it.length, duration = it.time, maneuver = maneuver) steps.add(step) stepIndex += 1 } diff --git a/common/data/src/main/java/com/kouros/navigation/model/IconMapper.kt b/common/data/src/main/java/com/kouros/navigation/model/IconMapper.kt index 9e01768..250b911 100644 --- a/common/data/src/main/java/com/kouros/navigation/model/IconMapper.kt +++ b/common/data/src/main/java/com/kouros/navigation/model/IconMapper.kt @@ -17,8 +17,7 @@ import java.util.Collections import java.util.Locale import kotlin.collections.forEach -class IconMapper(var routeModel: RouteModel) { - +class IconMapper() { fun maneuverIcon(routeManeuverType: Int): Int { var currentTurnIcon = R.drawable.ic_turn_name_change @@ -102,7 +101,7 @@ class IconMapper(var routeModel: RouteModel) { } } - "left", "slight_left" -> { + "left" -> { when (stepData.currentManeuverType) { Maneuver.TYPE_TURN_NORMAL_LEFT -> LaneDirection.SHAPE_NORMAL_LEFT else diff --git a/common/data/src/main/java/com/kouros/navigation/model/RouteCalculator.kt b/common/data/src/main/java/com/kouros/navigation/model/RouteCalculator.kt index efbf310..b7efa2a 100644 --- a/common/data/src/main/java/com/kouros/navigation/model/RouteCalculator.kt +++ b/common/data/src/main/java/com/kouros/navigation/model/RouteCalculator.kt @@ -2,6 +2,8 @@ package com.kouros.navigation.model import android.location.Location import androidx.car.app.navigation.model.Step +import com.kouros.navigation.data.Constants.MAXIMUM_LOCATION_DISTANCE +import com.kouros.navigation.data.Constants.NEAREST_LOCATION_DISTANCE import com.kouros.navigation.utils.location import java.util.concurrent.TimeUnit import kotlin.math.roundToInt @@ -12,38 +14,31 @@ class RouteCalculator(var routeModel: RouteModel) { var lastSpeedIndex: Int = 0 - fun findStep(location: Location) { - var nearestDistance = 100000f + var nearestDistance = MAXIMUM_LOCATION_DISTANCE for ((index, step) in routeModel.curLeg.steps.withIndex()) { - if (index >= routeModel.route.currentStepIndex) { + if (index >= routeModel.navState.route.currentStepIndex) { for ((wayIndex, waypoint) in step.maneuver.waypoints.withIndex()) { if (wayIndex >= step.waypointIndex) { val distance = location.distanceTo(location(waypoint[0], waypoint[1])) if (distance < nearestDistance) { nearestDistance = distance - routeModel.route.currentStepIndex = step.index + routeModel.navState.route.currentStepIndex = step.index step.waypointIndex = wayIndex step.wayPointLocation = location(waypoint[0], waypoint[1]) - routeModel.routeBearing = routeModel.lastLocation.bearingTo(location) - } else { - if (nearestDistance != 100000f) { - break; - } + routeModel.navState = routeModel.navState.copy( + routeBearing = routeModel.navState.lastLocation.bearingTo(location) + ) } } - if (nearestDistance == 0F) { - break - } } } - if (nearestDistance == 0F) { - break + if (nearestDistance < NEAREST_LOCATION_DISTANCE) { + break; } } } - fun travelLeftTime(): Double { var timeLeft = 0.0 // time for next step until end step @@ -102,10 +97,8 @@ class RouteCalculator(var routeModel: RouteModel) { if (distance > 500 || lastSpeedIndex < routeModel.route.currentStepIndex) { lastSpeedIndex = routeModel.route.currentStepIndex lastSpeedLocation = location - viewModel.getMaxSpeed(location, routeModel.previousStreet()) + viewModel.getMaxSpeed(location, routeModel.route.currentStep().street) } } } - - } \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt b/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt index 5ca9623..a479d2e 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 @@ -13,75 +13,81 @@ import com.kouros.navigation.data.route.Leg import com.kouros.navigation.data.route.Routes import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue import com.kouros.navigation.utils.location -import kotlinx.coroutines.DelicateCoroutinesApi import kotlin.math.absoluteValue -open class RouteModel() { +open class RouteModel { - var route = Route.Builder().buildEmpty() + // Immutable Data Class + data class NavigationState( + val route: Route = Route.Builder().buildEmpty(), + val iconMapper : IconMapper = IconMapper(), + val navigating: Boolean = false, + val arrived: Boolean = false, + val travelMessage: String = "", + val maneuverType: Int = 0, + val lastLocation: Location = location(0.0, 0.0), + val currentLocation: Location = location(0.0, 0.0), + val routeBearing: Float = 0F, + val currentRouteIndex: Int = 0, + val destination: Place = Place() + ) - val routeCalculator = RouteCalculator(this) + var navState = NavigationState() - var iconMapper = IconMapper(this) - var navigating: Boolean = false - var destination: Place = Place() - var arrived: Boolean = false - var maneuverType: Int = 0 - var travelMessage: String = "" + val route: Route + get() = navState.route - var currentLocation: Location = location(0.0, 0.0) + val routeCalculator : RouteCalculator = RouteCalculator(this) - var lastLocation: Location = location(0.0, 0.0) - var routeBearing: Float = 0F - - var currentRouteIndex = 0 val curRoute: Routes - get() = route.routes[currentRouteIndex] + get() = navState.route.routes[navState.currentRouteIndex] val curLeg: Leg - get() = route.routes[currentRouteIndex].legs.first() - + get() = navState.route.routes[navState.currentRouteIndex].legs.first() fun startNavigation(routeString: String, context: Context) { val routeEngine = getIntKeyValue(context = context, ROUTING_ENGINE) - route = Route.Builder() - .routeEngine(routeEngine) - .route(routeString) - .build() + navState = navState.copy( + route = Route.Builder() + .routeEngine(routeEngine) + .route(routeString) + .build() + ) if (hasLegs()) { - navigating = true + navState = navState.copy(navigating = true) } } private fun hasLegs(): Boolean { - return route.routes.isNotEmpty() && route.routes[0].legs.isNotEmpty() + return navState.route.routes.isNotEmpty() && navState.route.routes[0].legs.isNotEmpty() } fun stopNavigation() { - route = Route.Builder().buildEmpty() - navigating = false - arrived = false - maneuverType = Maneuver.TYPE_UNKNOWN - + navState = navState.copy( + route = Route.Builder().buildEmpty(), + navigating = false, + arrived = false, + maneuverType = Maneuver.TYPE_UNKNOWN + ) } - @OptIn(DelicateCoroutinesApi::class) fun updateLocation(curLocation: Location, viewModel: ViewModel) { - currentLocation = curLocation + navState = navState.copy(currentLocation = curLocation) routeCalculator.findStep(curLocation) routeCalculator.updateSpeedLimit(curLocation, viewModel) - lastLocation = currentLocation + navState = navState.copy(lastLocation = navState.currentLocation) } - private fun currentLanes(location: Location): List { + private fun currentLanes(): List { var lanes = emptyList() - if (route.legs().isNotEmpty()) { - route.legs().first().intersection.forEach { it -> + if (navState.route.legs().isNotEmpty()) { + navState.route.legs().first().intersection.forEach { if (it.lane.isNotEmpty()) { - val distance = lastLocation.distanceTo(location(it.location[0], it.location[1])) + val distance = + navState.lastLocation.distanceTo(location(it.location[0], it.location[1])) val sectionBearing = - lastLocation.bearingTo(location(it.location[0], it.location[1])) - if (distance < 500 && (routeBearing.absoluteValue - sectionBearing.absoluteValue).absoluteValue < 10) { + navState.lastLocation.bearingTo(location(it.location[0], it.location[1])) + if (distance < 500 && (navState.routeBearing.absoluteValue - sectionBearing.absoluteValue).absoluteValue < 10) { lanes = it.lane } } @@ -90,25 +96,24 @@ open class RouteModel() { return lanes } - fun currentStep(): StepData { val distanceToNextStep = routeCalculator.leftStepDistance() // Determine the maneuver type and corresponding icon - val currentStep = route.nextStep(0) + val currentStep = navState.route.nextStep(0) // Safely get the street name from the maneuver - val streetName = currentStep.name + val streetName = currentStep.maneuver.street val curManeuverType = currentStep.maneuver.type val exitNumber = currentStep.maneuver.exit - val maneuverIcon = iconMapper.maneuverIcon(curManeuverType) - maneuverType = curManeuverType + val maneuverIcon = navState.iconMapper.maneuverIcon(curManeuverType) + navState = navState.copy(maneuverType = curManeuverType) - val lanes = currentLanes(currentLocation) + val lanes = currentLanes() // Construct and return the final StepData object return StepData( streetName, distanceToNextStep, - maneuverType, + navState.maneuverType, maneuverIcon, routeCalculator.arrivalTime(), routeCalculator.travelLeftDistance(), @@ -118,22 +123,21 @@ open class RouteModel() { } fun nextStep(): StepData { - val step = route.nextStep(1) + val step = navState.route.nextStep(1) val maneuverType = step.maneuver.type val distanceLeft = routeCalculator.leftStepDistance() var text = "" when (distanceLeft) { in 0.0..NEXT_STEP_THRESHOLD -> { } - else -> { - if (step.name.isNotEmpty()) { - text = step.name + if (step.street.isNotEmpty()) { + text = step.street } } } - val maneuverIcon = iconMapper.maneuverIcon(maneuverType) + val maneuverIcon = navState.iconMapper.maneuverIcon(maneuverType) // Construct and return the final StepData object return StepData( text, @@ -147,14 +151,7 @@ open class RouteModel() { ) } - fun previousStreet(): String { - if (route.currentStepIndex > 0) { - return route.legs().first().steps[route.currentStepIndex - 1].name - } - return "" - } - fun isNavigating(): Boolean { - return navigating + return navState.navigating } } \ No newline at end of file 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 bdc0cfc..da34480 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 @@ -31,7 +31,6 @@ object GeoUtils { return newLocation } - fun decodePolyline(encoded: String, precision: Int = 6): List> { val factor = 10.0.pow(precision)