From cddb1932605df644b330555f289ba270e991c602 Mon Sep 17 00:00:00 2001 From: Dimitris Date: Mon, 1 Dec 2025 19:45:17 +0100 Subject: [PATCH] MapView, Navigation to RecentPlace --- app/build.gradle.kts | 12 +- common/car/build.gradle.kts | 1 + .../java/com/kouros/navigation/car/MapView.kt | 81 +++-- .../navigation/car/NavigationSession.kt | 1 - .../kouros/navigation/car/SurfaceRenderer.kt | 37 ++- .../navigation/car/screen/NavigationScreen.kt | 295 ++++++++++++------ .../navigation/car/screen/PlaceListScreen.kt | 2 + .../car/screen/RoutePreviewScreen.kt | 13 +- .../navigation/car/screen/SearchScreen.kt | 1 - common/car/src/main/res/values-de/strings.xml | 1 + common/car/src/main/res/values/strings.xml | 1 + common/data/build.gradle.kts | 1 + .../java/com/kouros/navigation/data/Color.kt | 2 + .../navigation/data/NavigationRepository.kt | 10 +- .../navigation/data/nominatim/SearchResult.kt | 2 +- .../com/kouros/navigation/model/ViewModel.kt | 40 ++- 16 files changed, 346 insertions(+), 154 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b0c710d..380b8f6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -10,7 +10,7 @@ android { defaultConfig { applicationId = "com.kouros.navigation" - minSdk = 30 + minSdk = 33 targetSdk = 36 versionCode = 1 versionName = "0.1.3" @@ -46,11 +46,11 @@ android { // Specifies one flavor dimension. flavorDimensions += "version" productFlavors { - create("demo") { - dimension = "version" - applicationIdSuffix = ".demo" - versionNameSuffix = "-demo" - } +// create("demo") { +// dimension = "version" +// applicationIdSuffix = ".demo" +// versionNameSuffix = "-demo" +// } create("full") { dimension = "version" applicationIdSuffix = ".full" diff --git a/common/car/build.gradle.kts b/common/car/build.gradle.kts index f862dd1..d4f49ba 100644 --- a/common/car/build.gradle.kts +++ b/common/car/build.gradle.kts @@ -9,6 +9,7 @@ android { compileSdk = 36 defaultConfig { + minSdk = 33 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-rules.pro") } diff --git a/common/car/src/main/java/com/kouros/navigation/car/MapView.kt b/common/car/src/main/java/com/kouros/navigation/car/MapView.kt index 9f8da93..d8be321 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/MapView.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/MapView.kt @@ -1,8 +1,10 @@ package com.kouros.navigation.car import android.location.Location +import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Badge @@ -11,13 +13,12 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.drawText import androidx.compose.ui.text.rememberTextMeasurer @@ -26,6 +27,7 @@ import androidx.compose.ui.unit.sp import com.kouros.android.cars.carappservice.R import com.kouros.navigation.data.NavigationColor import com.kouros.navigation.data.RouteColor +import com.kouros.navigation.data.SpeedColor import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.CameraState import org.maplibre.compose.camera.rememberCameraState @@ -134,43 +136,78 @@ fun NavigationImage(height: Int, street: String) { } ) { Icon( + modifier = Modifier.size(72.dp, 72.dp), imageVector = vector, contentDescription = "Navigation", tint = color ) if (street.isNotEmpty()) - Text(text=street) + Text(text = street) } } + @Composable private fun Speed( width: Int, height: Int, location: Location ) { - - val textMeasurer = rememberTextMeasurer() + val radius = 32 Box( modifier = Modifier - .size(30.dp, 30.dp) .padding( - start = width.dp - percent(width, 20).dp, - top = height.dp - 60.dp + start = width.dp- 300.dp, + top = height.dp- 80.dp + ), + contentAlignment = Alignment.Center + ) { + val textMeasurerSpeed = rememberTextMeasurer() + val textMeasurerKm = rememberTextMeasurer() + val speed = (location.speed * 3.6).toInt().toString() + val kmh = "km/h" + val styleSpeed = TextStyle( + fontSize = 22.sp, + color = Color.White, + ) + val styleKm = TextStyle( + fontSize = 12.sp, + color = Color.White, + ) + val textLayoutSpeed = remember(speed) { + textMeasurerSpeed.measure(speed, styleSpeed) + } + val textLayoutKm = remember(kmh) { + textMeasurerSpeed.measure(kmh, styleKm) + } + Canvas(modifier = Modifier.fillMaxSize()) { + drawCircle( + center = Offset( + x = center.x, + y = center.y + ), + radius = radius.toFloat(), + color = SpeedColor, ) - .drawWithCache { - val measuredText = - textMeasurer.measure( - AnnotatedString("${(location.speed * 3.6).toInt()}"), - style = TextStyle(color = Color.White, fontSize = 22.sp) - ) - onDrawBehind { - drawCircle( - Color.Black, radius = 30.dp.toPx(), center = Offset(15f, 12f) - ) - drawText(measuredText) - } - } - ) + drawText( + textMeasurer = textMeasurerSpeed, + text = speed, + style = styleSpeed, + topLeft = Offset( + x = center.x - textLayoutSpeed.size.width / 2, + y = center.y - textLayoutSpeed.size.height / 2 - 5, + ) + ) + drawText( + textMeasurer = textMeasurerKm, + text = "km/h", + style = styleKm, + topLeft = Offset( + x = center.x - textLayoutKm.size.width / 2, + y = center.y - textLayoutKm.size.height / 2 + 15, + ) + ) + } + } } fun getPaddingValues(height: Int, preView: Boolean): PaddingValues { 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 e469486..43dd569 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 @@ -87,7 +87,6 @@ class NavigationSession : Session(), NavigationScreen.Listener { lifecycle.addObserver(mLifeCycleObserver) } - @RequiresApi(Build.VERSION_CODES.M) override fun onCreateScreen(intent: Intent): Screen { routeModel = RouteCarModel() 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 25011f6..a3c54b1 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 @@ -54,7 +54,7 @@ class SurfaceRenderer( ) ) var visibleArea = MutableLiveData( - Rect() + Rect(0,0,0,0) ) var stableArea = Rect() @@ -76,6 +76,7 @@ class SurfaceRenderer( var panView = false val tilt = 55.0 + var previewDistance = 0.0 val mSurfaceCallback: SurfaceCallback = object : SurfaceCallback { lateinit var lifecycleOwner: CustomLifecycleOwner @@ -84,7 +85,6 @@ class SurfaceRenderer( lateinit var presentation: Presentation - @RequiresApi(Build.VERSION_CODES.M) override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) { synchronized(this@SurfaceRenderer) { Log.i(TAG, "Surface available $surfaceContainer") @@ -134,7 +134,6 @@ class SurfaceRenderer( } } - @RequiresApi(Build.VERSION_CODES.KITKAT) override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) { synchronized(this@SurfaceRenderer) { Log.i(TAG, "SurfaceRenderer destroyed") @@ -168,7 +167,7 @@ class SurfaceRenderer( val previewRoute: String? by previewRouteData.observeAsState() val cameraState = cameraState(width, height, position, tilt, preview) - val baseStyle =BaseStyle.Uri(Constants.STYLE) + val baseStyle = BaseStyle.Uri(Constants.STYLE) // if (isSystemInDarkTheme()) BaseStyle.Uri(Constants.STYLE_DARK) else BaseStyle.Uri( // Constants.STYLE // ) @@ -257,7 +256,7 @@ class SurfaceRenderer( } } - fun updateLocation(location: Location) { + fun updateLocation(location: Location) { synchronized(this) { if (!preview) { var bearing = cameraPosition.value!!.bearing @@ -307,25 +306,29 @@ class SurfaceRenderer( previewRouteData.value = routeModel.route.routeGeoJson centerLocation = routeModel.centerLocation preview = true + previewDistance = routeModel.route.distance } private fun previewZoom(): Double { - if (routeModel.isNavigating()) { - when (routeModel.route.distance) { - in 0.0..10.0 -> { - return 14.0 - } - in 10.0..20.0 -> { - return 12.0 - } - in 20.0..30.0 -> { - return 11.0 - } + when (previewDistance) { + in 0.0..10.0 -> { + return 13.0 + } + in 10.0..20.0 -> { + return 11.0 + } + in 20.0..30.0 -> { + return 10.0 } } - return 10.0 + return 9.0 } + + fun setPreViewDistance(): Double { + return previewDistance + } + companion object { private const val TAG = "MapRenderer" 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 f3394d2..fa6fd47 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 @@ -6,7 +6,6 @@ import android.location.Location import android.location.LocationManager import android.os.CountDownTimer import android.os.Handler -import android.os.Looper import androidx.car.app.CarContext import androidx.car.app.Screen import androidx.car.app.model.Action @@ -14,8 +13,12 @@ import androidx.car.app.model.ActionStrip import androidx.car.app.model.CarColor import androidx.car.app.model.CarIcon import androidx.car.app.model.Distance +import androidx.car.app.model.Header +import androidx.car.app.model.MessageTemplate import androidx.car.app.model.Template import androidx.car.app.navigation.model.Maneuver +import androidx.car.app.navigation.model.MapController +import androidx.car.app.navigation.model.MapWithContentTemplate import androidx.car.app.navigation.model.MessageInfo import androidx.car.app.navigation.model.NavigationTemplate import androidx.car.app.navigation.model.RoutingInfo @@ -31,6 +34,7 @@ import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.Place import com.kouros.navigation.model.ViewModel +import com.kouros.navigation.utils.location class NavigationScreen( carContext: CarContext, @@ -43,46 +47,45 @@ class NavigationScreen( /** A listener for navigation start and stop signals. */ interface Listener { - /** Stops navigation. */ + /** Stops navigation. */ fun stopNavigation() } var currentNavigationLocation = Location(LocationManager.GPS_PROVIDER) + lateinit var recentPlace: Place + + var recentPlaceFound = false + + var recentPlaceActive = true + var calculateNewRoute = false - val vieModel = ViewModel(NavigationRepository()) + val viewModel = ViewModel(NavigationRepository()) val observer = Observer { route -> if (route.isNotEmpty()) { routeModel.startNavigation(route) surfaceRenderer.setRouteData() + recentPlaceActive = false + invalidate() + } + } + + val recentObserver = Observer { lastPlace -> + if (!routeModel.isNavigating()) { + recentPlace = lastPlace + recentPlaceFound = true invalidate() } } init { - vieModel.route.observe(this, observer) + viewModel.route.observe(this, observer) + viewModel.recentPlace.observe(this, recentObserver) + viewModel.loadRecentPlace(location = surfaceRenderer.lastLocation) } override fun onGetTemplate(): Template { - val actionStripBuilder: ActionStrip.Builder = ActionStrip.Builder() - actionStripBuilder.addAction( - Action.Builder() - .setIcon(routeModel.createCarIcon(carContext, R.drawable.ic_search_black36dp)) - .setOnClickListener { - startSearchScreen() - } - //.setFlags(Action.FLAG_IS_PERSISTENT) - .build() - ) - actionStripBuilder.addAction( - Action.Builder() - .setIcon(routeModel.createCarIcon(carContext, R.drawable.settings_24px)) - .setOnClickListener { - screenManager.push(SettingsScreen(carContext)) - } - //.setFlags(Action.FLAG_IS_PERSISTENT) - .build() - ) + val actionStripBuilder = createActionStripBuilder() return if (routeModel.isNavigating()) { if (calculateNewRoute) { getNavigationLoadingTemplate(actionStripBuilder) @@ -96,21 +99,7 @@ class NavigationScreen( private fun getNavigationTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate { actionStripBuilder.addAction( - Action.Builder() - .setTitle(carContext.getString(R.string.stop_action_title)) - .setIcon( - CarIcon.Builder( - IconCompat.createWithResource( - carContext, - R.drawable.ic_close_white_24dp - ) - ) - .build() - ) - .setOnClickListener { - stopNavigation() - } - .build() + stopAction() ) return NavigationTemplate.Builder() .setNavigationInfo( @@ -123,7 +112,7 @@ class NavigationScreen( .build() } - private fun getNavigationEndTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate { + private fun getNavigationEndTemplate(actionStripBuilder: ActionStrip.Builder): Template { if (routeModel.isArrived()) { val timer = object : CountDownTimer(10000, 10000) { override fun onTick(millisUntilFinished: Long) {} @@ -155,14 +144,43 @@ class NavigationScreen( .setMapActionStrip(mapActionStripBuilder().build()) .build() } else { - return NavigationTemplate.Builder() - .setBackgroundColor(CarColor.SECONDARY) - .setActionStrip(actionStripBuilder.build()) - .setMapActionStrip(mapActionStripBuilder().build()) - .build() + return if (recentPlaceFound && recentPlaceActive) { + return getRecentPlaceTemplate() + } else { + NavigationTemplate.Builder() + .setBackgroundColor(CarColor.SECONDARY) + .setActionStrip(actionStripBuilder.build()) + .setMapActionStrip(mapActionStripBuilder().build()) + .build() + } } } + fun getRecentPlaceTemplate(): Template { + val messageTemplate = MessageTemplate.Builder( + recentPlace.name + "\n" + + recentPlace.city + ) + .setHeader( + Header.Builder() + .setTitle(carContext.getString(R.string.drive_now)) + .build() + ) + .addAction(navigateAction()) + .addAction(closeAction()) + .build() + + val builder = MapWithContentTemplate.Builder() + .setContentTemplate(messageTemplate) + .setActionStrip( + mapActionStripBuilder() + .addAction(settingsAction()) + .addAction(searchAction()) + .build() + ) + return builder.build() + } + fun getNavigationLoadingTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate { return NavigationTemplate.Builder() .setNavigationInfo(RoutingInfo.Builder().setLoading(true).build()) @@ -198,58 +216,151 @@ class NavigationScreen( } } + private fun createActionStripBuilder(): ActionStrip.Builder { + val actionStripBuilder: ActionStrip.Builder = ActionStrip.Builder() + actionStripBuilder.addAction( + searchAction() + ) + actionStripBuilder.addAction( + settingsAction() + ) + return actionStripBuilder + } private fun mapActionStripBuilder(): ActionStrip.Builder { val actionStripBuilder = ActionStrip.Builder() - .addAction( - Action.Builder() - .setIcon( - CarIcon.Builder( - IconCompat.createWithResource( - carContext, - R.drawable.ic_zoom_in_24 - ) - ) - .build() - ).setOnClickListener { - surfaceRenderer.handleScale(1) - } - .build() - ) - .addAction( - Action.Builder() - .setIcon( - CarIcon.Builder( - IconCompat.createWithResource( - carContext, - R.drawable.ic_zoom_out_24 - ) - ) - .build() - ).setOnClickListener { - surfaceRenderer.handleScale(-1) - } - .build()) + .addAction(zoomPlus()) + .addAction(zoomMinus()) if (surfaceRenderer.panView) { - actionStripBuilder.addAction( - Action.Builder() - .setIcon( - CarIcon.Builder( - IconCompat.createWithResource( - carContext, - R.drawable.ic_pan_24 - ) - ) - .build() - ).setOnClickListener { - surfaceRenderer.panView = false - } - .build() - ) + actionStripBuilder + .addAction( + panAction() + ) } return actionStripBuilder } + private fun stopAction(): Action { + return Action.Builder() + .setTitle(carContext.getString(R.string.stop_action_title)) + .setIcon( + CarIcon.Builder( + IconCompat.createWithResource( + carContext, + R.drawable.ic_close_white_24dp + ) + ) + .build() + ) + .setOnClickListener { + stopNavigation() + } + .build() + } + + private fun navigateAction(): Action { + return Action.Builder() + .setIcon( + CarIcon.Builder( + IconCompat.createWithResource( + carContext, + R.drawable.assistant_navigation_48px + ) + ) + .build() + ) + .setOnClickListener { + val navigateTo = location(recentPlace.latitude, recentPlace.longitude) + viewModel.loadRoute(surfaceRenderer.lastLocation, navigateTo) + routeModel.destination = recentPlace + } + .build() + } + + private fun closeAction(): Action { + return Action.Builder() + .setIcon( + CarIcon.Builder( + IconCompat.createWithResource( + carContext, + R.drawable.ic_close_white_24dp + ) + ) + .build() + ) + .setOnClickListener { + recentPlaceActive = false + invalidate() + } + .build() + } + + private fun searchAction(): Action { + return Action.Builder() + .setIcon(routeModel.createCarIcon(carContext, R.drawable.ic_search_black36dp)) + .setOnClickListener { + startSearchScreen() + } + .build() + } + + private fun settingsAction(): Action { + return Action.Builder() + .setIcon(routeModel.createCarIcon(carContext, R.drawable.settings_24px)) + .setOnClickListener { + screenManager.push(SettingsScreen(carContext)) + } + .build() + } + + private fun zoomPlus(): Action { + return Action.Builder() + .setIcon( + CarIcon.Builder( + IconCompat.createWithResource( + carContext, + R.drawable.ic_zoom_in_24 + ) + ) + .build() + ).setOnClickListener { + surfaceRenderer.handleScale(1) + } + .build() + } + + private fun zoomMinus(): Action { + return Action.Builder() + .setIcon( + CarIcon.Builder( + IconCompat.createWithResource( + carContext, + R.drawable.ic_zoom_out_24 + ) + ) + .build() + ).setOnClickListener { + surfaceRenderer.handleScale(-1) + } + .build() + } + + private fun panAction(): Action { + return Action.Builder() + .setIcon( + CarIcon.Builder( + IconCompat.createWithResource( + carContext, + R.drawable.ic_pan_24 + ) + ) + .build() + ).setOnClickListener { + surfaceRenderer.panView = false + } + .build() + } + private fun getSuggestion(title: Int, subtitle: Int, icon: CarIcon): Suggestion { return Suggestion.Builder() .setIdentifier("0") @@ -282,8 +393,8 @@ class NavigationScreen( val location = Location(LocationManager.GPS_PROVIDER) location.latitude = place.latitude location.longitude = place.longitude - vieModel.saveRecent(place) - vieModel.loadRoute(surfaceRenderer.lastLocation, location) + viewModel.saveRecent(place) + viewModel.loadRoute(surfaceRenderer.lastLocation, location) currentNavigationLocation = location routeModel.destination = place invalidate() @@ -303,7 +414,7 @@ class NavigationScreen( val mainThreadhandler = Handler(carContext.mainLooper) mainThreadhandler.post { object : CountDownTimer(5000, 1000) { - override fun onTick(millisUntilFinished: Long) { } + override fun onTick(millisUntilFinished: Long) {} override fun onFinish() { calculateNewRoute = false stopNavigation() @@ -314,7 +425,7 @@ class NavigationScreen( fun reRoute() { NavigationMessage(carContext).createAlert() - vieModel.loadRoute(surfaceRenderer.lastLocation, currentNavigationLocation) + viewModel.loadRoute(surfaceRenderer.lastLocation, currentNavigationLocation) } fun updateTrip() { 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 a27e8ce..975a028 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 @@ -2,9 +2,11 @@ package com.kouros.navigation.car.screen import android.location.Location import android.net.Uri +import android.os.Build import android.text.Spannable import android.text.SpannableString import android.util.Log +import androidx.annotation.RequiresApi import androidx.car.app.CarContext import androidx.car.app.CarToast import androidx.car.app.Screen 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 c60e2b3..ecf9527 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 @@ -15,7 +15,6 @@ */ package com.kouros.navigation.car.screen -import android.location.Geocoder import android.location.Location import android.location.LocationManager import android.os.CountDownTimer @@ -60,7 +59,6 @@ class RoutePreviewScreen( private var mItemLimit = 0 - private var street = "" val vieModel = ViewModel(NavigationRepository()) val routeModel = RouteCarModel() @@ -70,14 +68,7 @@ class RoutePreviewScreen( if (route.isNotEmpty()) { routeModel.startNavigation(route) surfaceRenderer.setPreviewRouteData(routeModel) - val geocoder = Geocoder(carContext) - // nominatim -> - geocoder.getFromLocation(destination.latitude, destination.longitude, 1) { - for (address in it) { - street = address.getAddressLine(0) - } - invalidate() - } + invalidate() } } @@ -192,7 +183,7 @@ class RoutePreviewScreen( return Row.Builder() .setTitle(route) .setOnClickListener { onRouteSelected(index) } - .addText(street) + .addText( "${destination.street!!} ${destination.postalCode} ${destination.city}") .addAction(action) .build() } diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt index 5384c54..218b6bf 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/SearchScreen.kt @@ -37,7 +37,6 @@ class SearchScreen( lateinit var searchResult: List val observer = Observer> { newSearch -> - println(newSearch) searchResult = newSearch invalidate() } diff --git a/common/car/src/main/res/values-de/strings.xml b/common/car/src/main/res/values-de/strings.xml index 01339df..0f2e588 100644 --- a/common/car/src/main/res/values-de/strings.xml +++ b/common/car/src/main/res/values-de/strings.xml @@ -364,4 +364,5 @@ Routen Letzte Ziele Kontakte + Jetzt losfahren diff --git a/common/car/src/main/res/values/strings.xml b/common/car/src/main/res/values/strings.xml index ea7db48..fdb0200 100644 --- a/common/car/src/main/res/values/strings.xml +++ b/common/car/src/main/res/values/strings.xml @@ -491,4 +491,5 @@ Routes Recent Contacts + Drive now diff --git a/common/data/build.gradle.kts b/common/data/build.gradle.kts index b455cbd..a43bdf1 100644 --- a/common/data/build.gradle.kts +++ b/common/data/build.gradle.kts @@ -15,6 +15,7 @@ android { compileSdk = 36 defaultConfig { + minSdk = 33 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-rules.pro") } diff --git a/common/data/src/main/java/com/kouros/navigation/data/Color.kt b/common/data/src/main/java/com/kouros/navigation/data/Color.kt index c0c5b74..81283bf 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/Color.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/Color.kt @@ -5,3 +5,5 @@ import androidx.compose.ui.graphics.Color val NavigationColor = Color(0xFF052086) val RouteColor = Color(0xFF5582D0) + +val SpeedColor = Color(0xFF262525) \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt b/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt index dc21142..588cd16 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 @@ -32,7 +32,8 @@ class NavigationRepository { private val routeUrl = "https://kouros-online.de/valhalla/route?json=" - private val nominatimUrl = "https://nominatim.openstreetmap.org/search?q=" + private val nominatimUrl = "https://nominatim.openstreetmap.org/" + fun getRoute(currentLocation : Location, location: Location): String { val vLocation = listOf( Locations(lat = currentLocation.latitude, lon = currentLocation.longitude), @@ -57,7 +58,11 @@ class NavigationRepository { } fun searchPlaces(search : String) : String { - return fetchUrl("$nominatimUrl$search&format=jsonv2&addressdetails=true&countrycodes=de", false) + return fetchUrl("${nominatimUrl}search?q=$search&format=jsonv2&addressdetails=true&countrycodes=de", false) + } + + fun reverseAddress(location: Location) : String { + return fetchUrl("${nominatimUrl}reverse?lat=${location.latitude}&lon=${location.longitude}&format=jsonv2&addressdetails=true&countrycodes=de", false) } fun getPlaces(): List { @@ -103,6 +108,7 @@ class NavigationRepository { httpURLConnection.setRequestProperty("User-Agent", "email=nominatim@kouros-online.de"); httpURLConnection.requestMethod = "GET" val responseCode = httpURLConnection.responseCode + println(responseCode) if (responseCode == HttpURLConnection.HTTP_OK) { val response = httpURLConnection.inputStream.bufferedReader() .use { it.readText() } // defaults to UTF-8 diff --git a/common/data/src/main/java/com/kouros/navigation/data/nominatim/SearchResult.kt b/common/data/src/main/java/com/kouros/navigation/data/nominatim/SearchResult.kt index 4bb7043..e97534b 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/nominatim/SearchResult.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/nominatim/SearchResult.kt @@ -16,8 +16,8 @@ data class SearchResult( @SerializedName("osm_type") var osmType: String = "", @SerializedName("osm_id") var osmId: Long = 0, @SerializedName("lat") var lat: String = "", - @SerializedName("lon") var lon: String = "", @SerializedName("category") var category: String = "", + @SerializedName("lon") var lon: String = "", @SerializedName("type") var type: String = "", @SerializedName("place_rank") var placeRank: Int = 0, @SerializedName("importance") var importance: Double = 0.0, 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 a0b31e0..fd21b31 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 @@ -3,6 +3,8 @@ package com.kouros.navigation.model import android.content.Context import android.location.Geocoder import android.location.Location +import android.os.Build +import androidx.annotation.RequiresApi import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -32,6 +34,9 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { MutableLiveData() } + val recentPlace: MutableLiveData by lazy { + MutableLiveData() + } val places: MutableLiveData> by lazy { MutableLiveData>() } @@ -45,6 +50,31 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { } + fun loadRecentPlace(location: Location) { + viewModelScope.launch(Dispatchers.IO) { + try { + val placeBox = boxStore.boxFor(Place::class) + val query = placeBox + .query(Place_.name.notEqual("")) + .orderDesc(Place_.lastDate) + .build() + val results = query.find() + query.close() + for (place in results) { + val plLocation = location(place.latitude, place.longitude) + // val distance = repository.getRouteDistance(location, plLocation) + //place.distance = distance.toFloat() + if (place.distance == 0F) { + recentPlace.postValue(place) + println("RecentPlace $recentPlace") + return@launch + } + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } fun loadPlaces(location: Location) { viewModelScope.launch(Dispatchers.IO) { try { @@ -59,7 +89,6 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { val plLocation = location(place.latitude, place.longitude) val distance = repository.getRouteDistance(location, plLocation) place.distance = distance.toFloat() - println(place.lastDate) } places.postValue(results) } catch (e: Exception) { @@ -148,6 +177,15 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { } } + fun reverseAddress(location: Location ): String { + val address = repository.reverseAddress(location) + println(address) + val gson = GsonBuilder().serializeNulls().create() + val place = gson.fromJson(address, SearchResult::class.java) + println(place.address.road) + return place.address.road + } + fun saveRecent(place: Place) { viewModelScope.launch(Dispatchers.IO) { place.category = Constants.RECENT