MapView, Navigation to RecentPlace
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -9,6 +9,7 @@ android {
|
||||
compileSdk = 36
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 33
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
.drawWithCache {
|
||||
val measuredText =
|
||||
textMeasurer.measure(
|
||||
AnnotatedString("${(location.speed * 3.6).toInt()}"),
|
||||
style = TextStyle(color = Color.White, fontSize = 22.sp)
|
||||
val styleKm = TextStyle(
|
||||
fontSize = 12.sp,
|
||||
color = Color.White,
|
||||
)
|
||||
onDrawBehind {
|
||||
val textLayoutSpeed = remember(speed) {
|
||||
textMeasurerSpeed.measure(speed, styleSpeed)
|
||||
}
|
||||
val textLayoutKm = remember(kmh) {
|
||||
textMeasurerSpeed.measure(kmh, styleKm)
|
||||
}
|
||||
Canvas(modifier = Modifier.fillMaxSize()) {
|
||||
drawCircle(
|
||||
Color.Black, radius = 30.dp.toPx(), center = Offset(15f, 12f)
|
||||
center = Offset(
|
||||
x = center.x,
|
||||
y = center.y
|
||||
),
|
||||
radius = radius.toFloat(),
|
||||
color = SpeedColor,
|
||||
)
|
||||
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,
|
||||
)
|
||||
)
|
||||
drawText(measuredText)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun getPaddingValues(height: Int, preView: Boolean): PaddingValues {
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
// )
|
||||
@@ -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) {
|
||||
when (previewDistance) {
|
||||
in 0.0..10.0 -> {
|
||||
return 14.0
|
||||
return 13.0
|
||||
}
|
||||
in 10.0..20.0 -> {
|
||||
return 12.0
|
||||
}
|
||||
in 20.0..30.0 -> {
|
||||
return 11.0
|
||||
}
|
||||
}
|
||||
}
|
||||
in 20.0..30.0 -> {
|
||||
return 10.0
|
||||
}
|
||||
}
|
||||
return 9.0
|
||||
}
|
||||
|
||||
fun setPreViewDistance(): Double {
|
||||
return previewDistance
|
||||
}
|
||||
|
||||
companion
|
||||
object {
|
||||
private const val TAG = "MapRenderer"
|
||||
|
||||
@@ -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,
|
||||
@@ -49,40 +53,39 @@ class NavigationScreen(
|
||||
|
||||
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<String> { route ->
|
||||
if (route.isNotEmpty()) {
|
||||
routeModel.startNavigation(route)
|
||||
surfaceRenderer.setRouteData()
|
||||
recentPlaceActive = false
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
val recentObserver = Observer<Place> { 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,13 +144,42 @@ class NavigationScreen(
|
||||
.setMapActionStrip(mapActionStripBuilder().build())
|
||||
.build()
|
||||
} else {
|
||||
return NavigationTemplate.Builder()
|
||||
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()
|
||||
@@ -198,11 +216,105 @@ 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(zoomPlus())
|
||||
.addAction(zoomMinus())
|
||||
if (surfaceRenderer.panView) {
|
||||
actionStripBuilder
|
||||
.addAction(
|
||||
Action.Builder()
|
||||
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(
|
||||
@@ -215,9 +327,10 @@ class NavigationScreen(
|
||||
surfaceRenderer.handleScale(1)
|
||||
}
|
||||
.build()
|
||||
)
|
||||
.addAction(
|
||||
Action.Builder()
|
||||
}
|
||||
|
||||
private fun zoomMinus(): Action {
|
||||
return Action.Builder()
|
||||
.setIcon(
|
||||
CarIcon.Builder(
|
||||
IconCompat.createWithResource(
|
||||
@@ -229,10 +342,11 @@ class NavigationScreen(
|
||||
).setOnClickListener {
|
||||
surfaceRenderer.handleScale(-1)
|
||||
}
|
||||
.build())
|
||||
if (surfaceRenderer.panView) {
|
||||
actionStripBuilder.addAction(
|
||||
Action.Builder()
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun panAction(): Action {
|
||||
return Action.Builder()
|
||||
.setIcon(
|
||||
CarIcon.Builder(
|
||||
IconCompat.createWithResource(
|
||||
@@ -245,9 +359,6 @@ class NavigationScreen(
|
||||
surfaceRenderer.panView = false
|
||||
}
|
||||
.build()
|
||||
)
|
||||
}
|
||||
return actionStripBuilder
|
||||
}
|
||||
|
||||
private fun getSuggestion(title: Int, subtitle: Int, icon: CarIcon): Suggestion {
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,16 +68,9 @@ 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
vieModel.previewRoute.observe(this, observer)
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ class SearchScreen(
|
||||
lateinit var searchResult: List<SearchResult>
|
||||
|
||||
val observer = Observer<List<SearchResult>> { newSearch ->
|
||||
println(newSearch)
|
||||
searchResult = newSearch
|
||||
invalidate()
|
||||
}
|
||||
|
||||
@@ -364,4 +364,5 @@
|
||||
<string name="route_preview">Routen</string>
|
||||
<string name="recent_destinations">Letzte Ziele</string>
|
||||
<string name="contacts">Kontakte</string>
|
||||
<string name="drive_now">Jetzt losfahren</string>
|
||||
</resources>
|
||||
|
||||
@@ -491,4 +491,5 @@
|
||||
<string name="route_preview">Routes</string>
|
||||
<string name="recent_destinations">Recent</string>
|
||||
<string name="contacts">Contacts</string>
|
||||
<string name="drive_now">Drive now</string>
|
||||
</resources>
|
||||
|
||||
@@ -15,6 +15,7 @@ android {
|
||||
compileSdk = 36
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 33
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
@@ -5,3 +5,5 @@ import androidx.compose.ui.graphics.Color
|
||||
val NavigationColor = Color(0xFF052086)
|
||||
|
||||
val RouteColor = Color(0xFF5582D0)
|
||||
|
||||
val SpeedColor = Color(0xFF262525)
|
||||
@@ -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<Place> {
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<String>()
|
||||
}
|
||||
|
||||
val recentPlace: MutableLiveData<Place> by lazy {
|
||||
MutableLiveData<Place>()
|
||||
}
|
||||
val places: MutableLiveData<List<Place>> by lazy {
|
||||
MutableLiveData<List<Place>>()
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user