Lanes
This commit is contained in:
@@ -43,6 +43,7 @@ import com.kouros.data.R
|
||||
import com.kouros.navigation.MainApplication.Companion.navigationViewModel
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE
|
||||
import com.kouros.navigation.data.Constants.home2Location
|
||||
import com.kouros.navigation.data.Constants.homeLocation
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.model.BaseStyleModel
|
||||
@@ -61,6 +62,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.joda.time.DateTime
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import org.maplibre.compose.camera.CameraPosition
|
||||
import org.maplibre.compose.location.DesiredAccuracy
|
||||
import org.maplibre.compose.location.Location
|
||||
@@ -76,7 +78,7 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
val routeModel = RouteModel()
|
||||
var tilt = 50.0
|
||||
val useMock = true
|
||||
val useMock = false
|
||||
val stepData: MutableLiveData<StepData> by lazy {
|
||||
MutableLiveData<StepData>()
|
||||
}
|
||||
@@ -90,7 +92,7 @@ class MainActivity : ComponentActivity() {
|
||||
routeData.value = routeModel.route.routeGeoJson
|
||||
simulate()
|
||||
//test()
|
||||
//gpx(applicationContext)
|
||||
///gpx(applicationContext)
|
||||
}
|
||||
}
|
||||
val cameraPosition = MutableLiveData(
|
||||
@@ -130,8 +132,8 @@ class MainActivity : ComponentActivity() {
|
||||
if (useMock) {
|
||||
mock = MockLocation(locationManager)
|
||||
mock.setMockLocation(
|
||||
location?.latitude ?: homeLocation.latitude,
|
||||
location?.longitude ?: homeLocation.longitude
|
||||
home2Location.latitude,
|
||||
home2Location.longitude
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -153,6 +155,10 @@ class MainActivity : ComponentActivity() {
|
||||
requiredPermissions = listOf(permissions.first()),
|
||||
onGranted = {
|
||||
Content()
|
||||
// auto navigate
|
||||
if (useMock) {
|
||||
//navigationViewModel.loadRoute(applicationContext, homeLocation, home2Location, 0F)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -172,7 +178,7 @@ class MainActivity : ComponentActivity() {
|
||||
)
|
||||
val userLocationState = rememberUserLocationState(locationProvider)
|
||||
val locationState = locationProvider.location.collectAsState()
|
||||
updateLocation(locationState.value)
|
||||
updateLocation(locationState.value)
|
||||
var latitude by remember { mutableDoubleStateOf(0.0) }
|
||||
if (locationState.value != null) {
|
||||
latitude = locationState.value!!.position.latitude
|
||||
@@ -271,7 +277,7 @@ class MainActivity : ComponentActivity() {
|
||||
)
|
||||
lastLocation = currentLocation
|
||||
if (!loadRecentPlaces) {
|
||||
navigationViewModel.loadRecentPlaces(applicationContext, lastLocation)
|
||||
navigationViewModel.loadRecentPlaces(applicationContext, lastLocation, 0F)
|
||||
loadRecentPlaces = true
|
||||
}
|
||||
}
|
||||
@@ -333,21 +339,34 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
fun test() {
|
||||
for ((index, step) in routeModel.legs.steps.withIndex()) {
|
||||
for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) {
|
||||
routeModel.updateLocation(location(waypoint[0], waypoint[1]), navigationViewModel)
|
||||
val step = routeModel.currentStep()
|
||||
println("Street: ${step.instruction} Dist: ${step.leftStepDistance} ${step.currentManeuverType}")
|
||||
if (index + 1 <= routeModel.legs.steps.size) {
|
||||
//nextStepData.value = routeModel.nextStep()
|
||||
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()
|
||||
if (step.leftStepDistance == 70.0) {
|
||||
println("")
|
||||
}
|
||||
if (index + 1 <= routeModel.legs.steps.size) {
|
||||
//nextStepData.value = routeModel.nextStep()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test2() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// Balanstr.
|
||||
mock.setMockLocation( 48.119357, 11.599130)
|
||||
}
|
||||
}
|
||||
fun gpx(context: Context) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val parser = GPXParser()
|
||||
val input = context.resources.openRawResource(R.raw.vh)
|
||||
val input = context.resources.openRawResource(R.raw.hv)
|
||||
val parsedGpx: Gpx? = parser.parse(input) // consider using a background thread
|
||||
parsedGpx?.let {
|
||||
val tracks = parsedGpx.tracks
|
||||
|
||||
@@ -96,7 +96,7 @@ fun Home(
|
||||
Button(onClick = {
|
||||
val places = viewModel.loadRecentPlace()
|
||||
val toLocation = location(places.first()!!.longitude, places.first()!!.latitude)
|
||||
viewModel.loadRoute(applicationContext, location, toLocation)
|
||||
viewModel.loadRoute(applicationContext, location, toLocation, 0F)
|
||||
closeSheet()
|
||||
}) {
|
||||
Icon(
|
||||
@@ -207,7 +207,7 @@ private fun SearchPlaces(
|
||||
viewModel.saveRecent(pl)
|
||||
val toLocation =
|
||||
location(place.lon.toDouble(), place.lat.toDouble())
|
||||
viewModel.loadRoute(context, location, toLocation)
|
||||
viewModel.loadRoute(context, location, toLocation, 0F)
|
||||
closeSheet()
|
||||
}
|
||||
.fillMaxWidth()
|
||||
@@ -245,7 +245,7 @@ private fun RecentPlaces(
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
val toLocation = location(place.longitude, place.latitude)
|
||||
viewModel.loadRoute(context, location, toLocation)
|
||||
viewModel.loadRoute(context, location, toLocation, 0F)
|
||||
closeSheet()
|
||||
}
|
||||
.fillMaxWidth()
|
||||
|
||||
@@ -18,6 +18,7 @@ import androidx.car.app.hardware.common.CarValue
|
||||
import androidx.car.app.hardware.common.OnCarDataAvailableListener
|
||||
import androidx.car.app.hardware.info.CarHardwareLocation
|
||||
import androidx.car.app.hardware.info.CarSensors
|
||||
import androidx.car.app.hardware.info.Compass
|
||||
import androidx.car.app.hardware.info.Speed
|
||||
import androidx.core.location.LocationListenerCompat
|
||||
import androidx.core.net.toUri
|
||||
@@ -104,6 +105,17 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
val carCompassListener: OnCarDataAvailableListener<Compass?> =
|
||||
OnCarDataAvailableListener { data ->
|
||||
if (data.orientations.status == CarValue.STATUS_SUCCESS) {
|
||||
val orientation = data.orientations.value
|
||||
if (orientation != null) {
|
||||
surfaceRenderer.carOrientation = orientation[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val carSpeedListener = OnCarDataAvailableListener<Speed> { data ->
|
||||
if (data.displaySpeedMetersPerSecond.status == CarValue.STATUS_SUCCESS) {
|
||||
val speed = data.displaySpeedMetersPerSecond.value
|
||||
@@ -172,6 +184,9 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
val useCarLocation = getBooleanKeyValue(carContext, CAR_LOCATION)
|
||||
if (useCarLocation) {
|
||||
val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors
|
||||
carSensors.addCompassListener(CarSensors.UPDATE_RATE_FASTEST,
|
||||
carContext.mainExecutor,
|
||||
carCompassListener)
|
||||
carSensors.addCarHardwareLocationListener(
|
||||
CarSensors.UPDATE_RATE_FASTEST,
|
||||
carContext.mainExecutor,
|
||||
@@ -191,8 +206,7 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
SearchScreen(
|
||||
carContext,
|
||||
surfaceRenderer,
|
||||
location,
|
||||
navigationViewModel,
|
||||
navigationViewModel
|
||||
// TODO: Uri
|
||||
)
|
||||
) { obj: Any? ->
|
||||
@@ -229,7 +243,7 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
carContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
|
||||
if (location != null) {
|
||||
navigationViewModel.loadRecentPlace(location = location, carContext)
|
||||
navigationViewModel.loadRecentPlace(location = location, surfaceRenderer.carOrientation, carContext)
|
||||
updateLocation(location)
|
||||
locationManager.requestLocationUpdates(
|
||||
LocationManager.GPS_PROVIDER,
|
||||
|
||||
@@ -54,6 +54,8 @@ class SurfaceRenderer(
|
||||
) : DefaultLifecycleObserver {
|
||||
|
||||
var lastLocation = location(0.0, 0.0)
|
||||
|
||||
var carOrientation = 0F
|
||||
private val cameraPosition = MutableLiveData(
|
||||
CameraPosition(
|
||||
zoom = 15.0,
|
||||
@@ -303,7 +305,7 @@ class SurfaceRenderer(
|
||||
routeData.value = route
|
||||
updateCameraPosition(
|
||||
0.0,
|
||||
12.0,
|
||||
14.0,
|
||||
target = Position(location.longitude, location.latitude)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -160,8 +160,10 @@ fun AmenityLayer(routeData: String?) {
|
||||
if (routeData != null && routeData.isNotEmpty()) {
|
||||
val color = if (routeData.contains(Constants.PHARMACY)) {
|
||||
const(Color.Red)
|
||||
} else if (routeData.contains(Constants.CHARGING_STATION)) {
|
||||
const(Color.Blue)
|
||||
} else {
|
||||
const(Color.Green)
|
||||
const(Color.Black)
|
||||
}
|
||||
val routes = rememberGeoJsonSource(GeoJsonData.JsonString(routeData))
|
||||
SymbolLayer(
|
||||
@@ -169,6 +171,7 @@ fun AmenityLayer(routeData: String?) {
|
||||
source = routes,
|
||||
iconImage = image(painterResource(R.drawable.ev_station_48px), drawAsSdf = true),
|
||||
iconColor = color,
|
||||
iconOpacity = const(2.0f),
|
||||
iconSize = const(3.0f),
|
||||
)
|
||||
}
|
||||
@@ -188,10 +191,10 @@ fun SpeedCameraLayer(speedCameras: String?) {
|
||||
interpolate(
|
||||
type = exponential(1.2f),
|
||||
input = zoom(),
|
||||
5 to const(0.4f),
|
||||
6 to const(0.7f),
|
||||
7 to const(1.75f),
|
||||
20 to const(3f),
|
||||
5 to const(0.7f),
|
||||
6 to const(1.0f),
|
||||
7 to const(2.0f),
|
||||
20 to const(4f),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -58,7 +58,9 @@ class RouteCarModel() : RouteModel() {
|
||||
.setIcon(createCarIcon(carContext, stepData.icon))
|
||||
.build()
|
||||
)
|
||||
.setRoad(destination.street!!)
|
||||
if (destination.street != null) {
|
||||
step.setRoad(destination.street!!)
|
||||
}
|
||||
if (stepData.lane.isNotEmpty()) {
|
||||
addLanes(carContext, step, stepData)
|
||||
}
|
||||
@@ -222,13 +224,17 @@ class RouteCarModel() : RouteModel() {
|
||||
|
||||
fun showSpeedCamera(carContext: CarContext, distance: Double, maxSpeed: String?) {
|
||||
carContext.getCarService<AppManager?>(AppManager::class.java)
|
||||
.showAlert(createAlert(carContext, distance, maxSpeed))
|
||||
.showAlert(createAlert(carContext, distance, maxSpeed, createCarIcon(carContext, R.drawable.speed_camera_24px)))
|
||||
}
|
||||
|
||||
fun createAlert(carContext: CarContext, distance: Double, maxSpeed: String?): Alert {
|
||||
fun createAlert(
|
||||
carContext: CarContext,
|
||||
distance: Double,
|
||||
maxSpeed: String?,
|
||||
icon: CarIcon
|
||||
): Alert {
|
||||
val title = createCarText(carContext, R.string.speed_camera)
|
||||
val subtitle = CarText.create(maxSpeed!!)
|
||||
val icon = CarIcon.ALERT
|
||||
|
||||
val dismissAction: Action = createToastAction(
|
||||
carContext,
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.core.graphics.drawable.IconCompat
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
import com.kouros.navigation.car.ViewStyle
|
||||
import com.kouros.navigation.car.navigation.RouteCarModel
|
||||
import com.kouros.navigation.data.Category
|
||||
import com.kouros.navigation.data.Constants.CHARGING_STATION
|
||||
import com.kouros.navigation.data.Constants.FUEL_STATION
|
||||
@@ -23,8 +24,7 @@ import com.kouros.navigation.model.ViewModel
|
||||
class CategoriesScreen(
|
||||
private val carContext: CarContext,
|
||||
private val surfaceRenderer: SurfaceRenderer,
|
||||
private val location: Location,
|
||||
private val viewModel: ViewModel
|
||||
private val viewModel: ViewModel,
|
||||
) : Screen(carContext) {
|
||||
|
||||
var categories: List<Category> = listOf(
|
||||
@@ -47,7 +47,6 @@ class CategoriesScreen(
|
||||
CategoryScreen(
|
||||
carContext,
|
||||
surfaceRenderer,
|
||||
location,
|
||||
it.id,
|
||||
viewModel
|
||||
)
|
||||
|
||||
@@ -19,8 +19,9 @@ import androidx.lifecycle.Observer
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
import com.kouros.navigation.car.navigation.NavigationMessage
|
||||
import com.kouros.navigation.car.navigation.RouteCarModel
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.overpass.Elements
|
||||
import com.kouros.navigation.model.ViewModel
|
||||
import com.kouros.navigation.utils.GeoUtils.createPointCollection
|
||||
@@ -31,9 +32,8 @@ import kotlin.math.min
|
||||
class CategoryScreen(
|
||||
private val carContext: CarContext,
|
||||
private val surfaceRenderer: SurfaceRenderer,
|
||||
location: Location,
|
||||
private val category: String,
|
||||
private val viewModel: ViewModel
|
||||
private val viewModel: ViewModel,
|
||||
) : Screen(carContext) {
|
||||
|
||||
var elements = listOf<Elements>()
|
||||
@@ -58,7 +58,7 @@ class CategoryScreen(
|
||||
|
||||
init {
|
||||
viewModel.elements.observe(this, observer)
|
||||
viewModel.getAmenities(category, location)
|
||||
viewModel.getAmenities(category, surfaceRenderer.lastLocation)
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,28 @@ class CategoryScreen(
|
||||
} else {
|
||||
row.addText(carText("${it.tags.openingHours}"))
|
||||
}
|
||||
val navigationMessage = NavigationMessage(carContext)
|
||||
row.addAction(
|
||||
Action.Builder()
|
||||
.setOnClickListener {
|
||||
viewModel.loadRoute(
|
||||
carContext,
|
||||
currentLocation = surfaceRenderer.lastLocation,
|
||||
location(it.lon!!, it.lat!!),
|
||||
surfaceRenderer.carOrientation
|
||||
)
|
||||
setResult(
|
||||
Place(
|
||||
name = name,
|
||||
category = Constants.CHARGING_STATION,
|
||||
latitude = it.lat!!,
|
||||
longitude = it.lon!!
|
||||
)
|
||||
)
|
||||
finish()
|
||||
}
|
||||
.setIcon(navigationMessage.createCarIcon(R.drawable.navigation_48px))
|
||||
.build())
|
||||
return row.build()
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ class NavigationScreen(
|
||||
surfaceRenderer.speedCamerasData.value = speedData
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
viewModel.route.observe(this, observer)
|
||||
viewModel.recentPlace.observe(this, recentObserver)
|
||||
@@ -297,7 +298,12 @@ class NavigationScreen(
|
||||
)
|
||||
.setOnClickListener {
|
||||
val navigateTo = location(recentPlace.longitude, recentPlace.latitude)
|
||||
viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, navigateTo)
|
||||
viewModel.loadRoute(
|
||||
carContext,
|
||||
surfaceRenderer.lastLocation,
|
||||
navigateTo,
|
||||
surfaceRenderer.carOrientation
|
||||
)
|
||||
routeModel.destination = recentPlace
|
||||
}
|
||||
.build()
|
||||
@@ -394,7 +400,11 @@ class NavigationScreen(
|
||||
private fun startSearchScreen() {
|
||||
screenManager
|
||||
.pushForResult(
|
||||
SearchScreen(carContext, surfaceRenderer, surfaceRenderer.lastLocation, viewModel)
|
||||
SearchScreen(
|
||||
carContext,
|
||||
surfaceRenderer,
|
||||
viewModel
|
||||
)
|
||||
) { obj: Any? ->
|
||||
if (obj != null) {
|
||||
val place = obj as Place
|
||||
@@ -416,7 +426,12 @@ class NavigationScreen(
|
||||
val location = location(place.longitude, place.latitude)
|
||||
viewModel.saveRecent(place)
|
||||
currentNavigationLocation = location
|
||||
viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, location)
|
||||
viewModel.loadRoute(
|
||||
carContext,
|
||||
surfaceRenderer.lastLocation,
|
||||
location,
|
||||
surfaceRenderer.carOrientation
|
||||
)
|
||||
routeModel.destination = place
|
||||
invalidate()
|
||||
}
|
||||
@@ -447,7 +462,12 @@ class NavigationScreen(
|
||||
|
||||
fun reRoute(destination: Place) {
|
||||
val dest = location(destination.longitude, destination.latitude)
|
||||
viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, dest)
|
||||
viewModel.loadRoute(
|
||||
carContext,
|
||||
surfaceRenderer.lastLocation,
|
||||
dest,
|
||||
surfaceRenderer.carOrientation
|
||||
)
|
||||
}
|
||||
|
||||
fun updateTrip(location: Location) {
|
||||
@@ -495,10 +515,10 @@ class NavigationScreen(
|
||||
val bearingSpeedCamera = location.bearingTo(location(camera.lon!!, camera.lat!!))
|
||||
val bearingRoute = surfaceRenderer.lastLocation.bearingTo(location)
|
||||
|
||||
if (camera.distance < 80
|
||||
&& (bearingSpeedCamera.absoluteValue - bearingRoute.absoluteValue).absoluteValue < 15.0
|
||||
) {
|
||||
routeModel.showSpeedCamera(carContext, camera.distance, camera.tags.maxspeed)
|
||||
if (camera.distance < 80) {
|
||||
if ((bearingSpeedCamera.absoluteValue - bearingRoute.absoluteValue).absoluteValue < 20.0) {
|
||||
routeModel.showSpeedCamera(carContext, camera.distance, camera.tags.maxspeed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.kouros.navigation.model.ViewModel
|
||||
class PlaceListScreen(
|
||||
private val carContext: CarContext,
|
||||
private val surfaceRenderer: SurfaceRenderer,
|
||||
private val location: Location,
|
||||
private val category: String,
|
||||
private val viewModel: ViewModel
|
||||
) : Screen(carContext) {
|
||||
@@ -63,13 +62,21 @@ class PlaceListScreen(
|
||||
|
||||
fun loadPlaces() {
|
||||
if (category == RECENT) {
|
||||
viewModel.loadRecentPlaces(carContext, location)
|
||||
viewModel.loadRecentPlaces(
|
||||
carContext,
|
||||
surfaceRenderer.lastLocation,
|
||||
surfaceRenderer.carOrientation
|
||||
)
|
||||
}
|
||||
if (category == CONTACTS) {
|
||||
viewModel.loadContacts(carContext)
|
||||
}
|
||||
if (category == FAVORITES) {
|
||||
viewModel.loadFavorites(carContext, location)
|
||||
viewModel.loadFavorites(
|
||||
carContext,
|
||||
surfaceRenderer.lastLocation,
|
||||
surfaceRenderer.carOrientation
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,9 +84,14 @@ class PlaceListScreen(
|
||||
val itemListBuilder = ItemList.Builder()
|
||||
.setNoItemsMessage(carContext.getString(R.string.no_places))
|
||||
places.forEach {
|
||||
val street = if (it.street != null) {
|
||||
it.street
|
||||
} else {
|
||||
""
|
||||
}
|
||||
val row = Row.Builder()
|
||||
.setImage(contactIcon(it.avatar, it.category))
|
||||
.setTitle("${it.street!!} ${it.city}")
|
||||
.setTitle("$street ${it.city}")
|
||||
.setOnClickListener {
|
||||
val place = Place(
|
||||
0,
|
||||
|
||||
@@ -61,7 +61,12 @@ class RoutePreviewScreen(
|
||||
init {
|
||||
viewModel.previewRoute.observe(this, observer)
|
||||
val location = location(destination.longitude, destination.latitude)
|
||||
viewModel.loadPreviewRoute(carContext, surfaceRenderer.lastLocation, location)
|
||||
viewModel.loadPreviewRoute(
|
||||
carContext,
|
||||
surfaceRenderer.lastLocation,
|
||||
location,
|
||||
surfaceRenderer.carOrientation
|
||||
)
|
||||
}
|
||||
|
||||
override fun onGetTemplate(): Template {
|
||||
@@ -173,7 +178,8 @@ class RoutePreviewScreen(
|
||||
|
||||
private fun createRouteText(): CarText {
|
||||
val time = routeModel.route.summary!!.duration
|
||||
val length = BigDecimal(routeModel.route.summary!!.distance).setScale(1, RoundingMode.HALF_EVEN)
|
||||
val length =
|
||||
BigDecimal(routeModel.route.summary!!.distance).setScale(1, RoundingMode.HALF_EVEN)
|
||||
val firstRoute = SpannableString(" \u00b7 $length km")
|
||||
firstRoute.setSpan(
|
||||
DurationSpan.create(time.toLong()), 0, 1, 0
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.kouros.navigation.car.screen
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.location.Location
|
||||
import android.net.Uri
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.model.Action
|
||||
@@ -17,9 +16,9 @@ import androidx.lifecycle.Observer
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
import com.kouros.navigation.car.ViewStyle
|
||||
import com.kouros.navigation.car.navigation.RouteCarModel
|
||||
import com.kouros.navigation.data.Category
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.nominatim.SearchResult
|
||||
import com.kouros.navigation.model.ViewModel
|
||||
@@ -28,8 +27,7 @@ import com.kouros.navigation.model.ViewModel
|
||||
class SearchScreen(
|
||||
carContext: CarContext,
|
||||
private var surfaceRenderer: SurfaceRenderer,
|
||||
private var location: Location,
|
||||
private val viewModel: ViewModel
|
||||
private val viewModel: ViewModel,
|
||||
) : Screen(carContext) {
|
||||
|
||||
var isSearchComplete: Boolean = false
|
||||
@@ -73,7 +71,6 @@ class SearchScreen(
|
||||
CategoriesScreen(
|
||||
carContext,
|
||||
surfaceRenderer,
|
||||
location,
|
||||
viewModel
|
||||
)
|
||||
) { obj: Any? ->
|
||||
@@ -89,7 +86,6 @@ class SearchScreen(
|
||||
PlaceListScreen(
|
||||
carContext,
|
||||
surfaceRenderer,
|
||||
location,
|
||||
it.id,
|
||||
viewModel
|
||||
)
|
||||
@@ -119,7 +115,7 @@ class SearchScreen(
|
||||
object : SearchCallback {
|
||||
override fun onSearchSubmitted(searchTerm: String) {
|
||||
isSearchComplete = true
|
||||
viewModel.searchPlaces(searchTerm, location)
|
||||
viewModel.searchPlaces(searchTerm, surfaceRenderer.lastLocation)
|
||||
}
|
||||
})
|
||||
.setHeaderAction(Action.BACK)
|
||||
|
||||
@@ -37,10 +37,10 @@ abstract class NavigationRepository {
|
||||
private val nominatimUrl = "https://kouros-online.de/nominatim/"
|
||||
|
||||
|
||||
abstract fun getRoute(currentLocation: Location, location: Location, searchFilter: SearchFilter): String
|
||||
abstract fun getRoute(currentLocation: Location, location: Location, carOrientation: Float, searchFilter: SearchFilter): String
|
||||
|
||||
fun getRouteDistance(currentLocation: Location, location: Location, searchFilter: SearchFilter, context: Context): Double {
|
||||
val route = getRoute(currentLocation, location, searchFilter)
|
||||
fun getRouteDistance(currentLocation: Location, location: Location, carOrientation : Float, searchFilter: SearchFilter, context: Context): Double {
|
||||
val route = getRoute(currentLocation, location, carOrientation, searchFilter)
|
||||
val routeModel = RouteModel()
|
||||
routeModel.startNavigation(route, context)
|
||||
return routeModel.route.summary!!.distance
|
||||
|
||||
@@ -46,7 +46,6 @@ data class Route(
|
||||
this.routeGeoJson = routeGeoJson
|
||||
centerLocation = createCenterLocation(routeGeoJson)
|
||||
}
|
||||
|
||||
fun routeEngine(routeEngine: Int) = apply { this.routeEngine = routeEngine }
|
||||
fun waypoints(waypoints: List<List<Double>>) = apply { this.waypoints = waypoints }
|
||||
fun route(route: String) = apply {
|
||||
|
||||
@@ -10,6 +10,7 @@ class OsrmRepository : NavigationRepository() {
|
||||
override fun getRoute(
|
||||
currentLocation: Location,
|
||||
location: Location,
|
||||
carOrientation: Float,
|
||||
searchFilter: SearchFilter
|
||||
): String {
|
||||
|
||||
@@ -20,7 +21,7 @@ class OsrmRepository : NavigationRepository() {
|
||||
if (searchFilter.avoidTollway) {
|
||||
exclude = "$exclude&exclude=toll"
|
||||
}
|
||||
val routeLocation = "${currentLocation.longitude},${currentLocation.latitude};${location.longitude},${location.latitude}?steps=true"
|
||||
val routeLocation = "${currentLocation.longitude},${currentLocation.latitude};${location.longitude},${location.latitude}?steps=true&alternatives=2"
|
||||
return fetchUrl(routeUrl + routeLocation + exclude, true)
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,7 @@ class OsrmRoute {
|
||||
}
|
||||
}
|
||||
val leg = Leg(steps)
|
||||
|
||||
builder
|
||||
.routeType(1)
|
||||
.summary(summary)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
package com.kouros.navigation.data.route
|
||||
|
||||
class Routes (
|
||||
var legs : List<Leg> = arrayListOf()
|
||||
)
|
||||
@@ -12,7 +12,12 @@ private const val routeUrl = "https://kouros-online.de/valhalla/route?json="
|
||||
|
||||
class ValhallaRepository : NavigationRepository() {
|
||||
|
||||
override fun getRoute(currentLocation: Location, location: Location, searchFilter: SearchFilter): String {
|
||||
override fun getRoute(
|
||||
currentLocation: Location,
|
||||
location: Location,
|
||||
carOrientation: Float,
|
||||
searchFilter: SearchFilter
|
||||
): String {
|
||||
|
||||
var exclude = ""
|
||||
if (searchFilter.avoidMotorway) {
|
||||
@@ -23,7 +28,11 @@ class ValhallaRepository : NavigationRepository() {
|
||||
}
|
||||
|
||||
val vLocation = listOf(
|
||||
Locations(lat = currentLocation.latitude, lon = currentLocation.longitude, search_filter = exclude),
|
||||
Locations(
|
||||
lat = currentLocation.latitude,
|
||||
lon = currentLocation.longitude,
|
||||
search_filter = exclude
|
||||
),
|
||||
Locations(lat = location.latitude, lon = location.longitude, search_filter = exclude)
|
||||
)
|
||||
val valhallaLocation = ValhallaLocation(
|
||||
|
||||
@@ -114,8 +114,8 @@ open class RouteModel() {
|
||||
val interBearing = location.bearingTo(location(it.location[0], it.location[1]))
|
||||
if (distance < nearestDistance) {
|
||||
nearestDistance = distance
|
||||
if (distance <= NEXT_STEP_THRESHOLD) {
|
||||
if ((interBearing.absoluteValue - route.currentStep().maneuver.bearingAfter.absoluteValue).absoluteValue < 10) {
|
||||
if (distance <= NEXT_STEP_THRESHOLD * 3) {
|
||||
if ((interBearing.absoluteValue - route.currentStep().maneuver.bearingAfter.absoluteValue).absoluteValue < 20) {
|
||||
inter = it
|
||||
}
|
||||
}
|
||||
@@ -171,11 +171,11 @@ open class RouteModel() {
|
||||
val maneuverIcon = maneuverIcon(curManeuverType)
|
||||
maneuverType = curManeuverType
|
||||
|
||||
val lanes = if (shouldAdvance) {
|
||||
currentLanes(location)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
val lanes = currentLanes(location)
|
||||
|
||||
if (lanes.isNotEmpty())
|
||||
println("Street: $streetName Dist: $distanceToNextStep Lane: ${lanes.size}")
|
||||
|
||||
// Construct and return the final StepData object
|
||||
return StepData(
|
||||
streetName,
|
||||
@@ -186,6 +186,7 @@ open class RouteModel() {
|
||||
travelLeftDistance(),
|
||||
lanes
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -334,7 +335,7 @@ open class RouteModel() {
|
||||
fun createLaneIcon(context: Context, stepData: StepData): IconCompat {
|
||||
val bitmaps = mutableListOf<Bitmap>()
|
||||
stepData.lane.forEach {
|
||||
if (it.indications.isNotEmpty()) { //&& it.valid) {
|
||||
if (it.indications.isNotEmpty()) {
|
||||
Collections.sort<String>(it.indications)
|
||||
val resource = laneToResource(it.indications, stepData)
|
||||
if (resource.isNotEmpty()) {
|
||||
@@ -357,7 +358,7 @@ open class RouteModel() {
|
||||
return bitmaps.first()
|
||||
}
|
||||
val bmOverlay = createBitmap(
|
||||
bitmaps.first().getWidth() * (bitmaps.size),
|
||||
bitmaps.first().getWidth() * (bitmaps.size * 1.5).toInt(),
|
||||
bitmaps.first().getHeight(),
|
||||
bitmaps.first().getConfig()!!
|
||||
)
|
||||
|
||||
@@ -73,7 +73,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
fun loadRecentPlace(location: Location, context: Context) {
|
||||
fun loadRecentPlace(location: Location, carOrientation: Float, context: Context) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
@@ -85,7 +85,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
query.close()
|
||||
for (place in results) {
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
val distance = repository.getRouteDistance(location, plLocation, SearchFilter(), context)
|
||||
val distance = repository.getRouteDistance(location, plLocation, carOrientation, SearchFilter(), context)
|
||||
place.distance = distance.toFloat()
|
||||
if (place.distance > 1F) {
|
||||
recentPlace.postValue(place)
|
||||
@@ -98,7 +98,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadRecentPlaces(context: Context, location: Location) {
|
||||
fun loadRecentPlaces(context: Context, location: Location, carOrientation : Float) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
@@ -115,6 +115,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
repository.getRouteDistance(
|
||||
location,
|
||||
plLocation,
|
||||
carOrientation,
|
||||
getSearchFilter(context), context
|
||||
)
|
||||
place.distance = distance.toFloat()
|
||||
@@ -127,7 +128,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadFavorites(context: Context, location: Location) {
|
||||
fun loadFavorites(context: Context, location: Location, carOrientation: Float) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
@@ -140,7 +141,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
for (place in results) {
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
val distance =
|
||||
repository.getRouteDistance(location, plLocation, getSearchFilter(context), context)
|
||||
repository.getRouteDistance(location, plLocation, carOrientation, getSearchFilter(context), context)
|
||||
place.distance = distance.toFloat()
|
||||
}
|
||||
favorites.postValue(results)
|
||||
@@ -150,13 +151,14 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadRoute(context: Context, currentLocation: Location, location: Location) {
|
||||
fun loadRoute(context: Context, currentLocation: Location, location: Location, carOrientation : Float) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
route.postValue(
|
||||
repository.getRoute(
|
||||
currentLocation,
|
||||
location,
|
||||
carOrientation,
|
||||
getSearchFilter(context)
|
||||
)
|
||||
)
|
||||
@@ -166,13 +168,14 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadPreviewRoute(context: Context, currentLocation: Location, location: Location) {
|
||||
fun loadPreviewRoute(context: Context, currentLocation: Location, location: Location, carOrientation: Float) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
previewRoute.postValue(
|
||||
repository.getRoute(
|
||||
currentLocation,
|
||||
location,
|
||||
carOrientation,
|
||||
getSearchFilter(context)
|
||||
)
|
||||
)
|
||||
@@ -369,7 +372,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
}
|
||||
|
||||
|
||||
fun loadPlaces2(context: Context, location: Location): SnapshotStateList<Place?> {
|
||||
fun loadPlaces2(context: Context, location: Location, carOrientation: Float): SnapshotStateList<Place?> {
|
||||
val results = listOf<Place>()
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
@@ -382,7 +385,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
for (place in results) {
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
val distance =
|
||||
repository.getRouteDistance(location, plLocation, getSearchFilter(context), context)
|
||||
repository.getRouteDistance(location, plLocation, carOrientation, getSearchFilter(context), context)
|
||||
place.distance = distance.toFloat()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M340,760L440,600L380,600L380,480L280,640L340,640L340,760ZM240,400L480,400L480,200Q480,200 480,200Q480,200 480,200L240,200Q240,200 240,200Q240,200 240,200L240,400ZM240,760L480,760L480,480L240,480L240,760ZM160,840L160,200Q160,167 183.5,143.5Q207,120 240,120L480,120Q513,120 536.5,143.5Q560,167 560,200L560,480L610,480Q639,480 659.5,500.5Q680,521 680,550L680,735Q680,752 694,766Q708,780 725,780Q743,780 756.5,766Q770,752 770,735L770,360L760,360Q743,360 731.5,348.5Q720,337 720,320L720,240L740,240L740,180L780,180L780,240L820,240L820,180L860,180L860,240L880,240L880,320Q880,337 868.5,348.5Q857,360 840,360L830,360L830,735Q830,777 799.5,808.5Q769,840 725,840Q682,840 651,808.5Q620,777 620,735L620,550Q620,545 617.5,542.5Q615,540 610,540L560,540L560,840L160,840ZM480,760L240,760L240,760L480,760Z"/>
|
||||
</vector>
|
||||
@@ -6,5 +6,5 @@
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M337,746L425,606L372,606L372,501L285,641L337,641L337,746ZM220,408L489,408L489,180Q489,180 489,180Q489,180 489,180L220,180Q220,180 220,180Q220,180 220,180L220,408ZM220,780L489,780L489,468L220,468L220,780ZM160,840L160,180Q160,156 178,138Q196,120 220,120L489,120Q513,120 531,138Q549,156 549,180L549,468L614,468Q634.71,468 649.36,482.64Q664,497.29 664,518L664,737Q664,759 681.5,773.5Q699,788 722,788Q745,788 765,773.5Q785,759 785,737L785,350L770,350Q757.25,350 748.63,341.37Q740,332.75 740,320L740,230L760,230L760,180L790,180L790,230L830,230L830,180L860,180L860,230L880,230L880,320Q880,332.75 871.38,341.37Q862.75,350 850,350L835,350L835,736.69Q835,780 801,810Q767,840 721.82,840Q677.66,840 645.83,810Q614,780 614,737L614,518Q614,518 614,518Q614,518 614,518L549,518L549,840L160,840ZM489,780L220,780L220,780L489,780Z"/>
|
||||
android:pathData="M220,408L489,408L489,180Q489,180 489,180Q489,180 489,180L220,180Q220,180 220,180Q220,180 220,180L220,408ZM160,840L160,180Q160,156 178,138Q196,120 220,120L489,120Q513,120 531,138Q549,156 549,180L549,468L614,468Q634.71,468 649.36,482.64Q664,497.29 664,518L664,737Q664,759 681.5,773.5Q699,788 722,788Q745,788 765,773.5Q785,759 785,737L785,350L770,350Q757.25,350 748.63,341.37Q740,332.75 740,320L740,230L760,230L760,180L790,180L790,230L830,230L830,180L860,180L860,230L880,230L880,320Q880,332.75 871.38,341.37Q862.75,350 850,350L835,350L835,736.69Q835,780 801,810Q767,840 721.82,840Q677.66,840 645.83,810Q614,780 614,737L614,518Q614,518 614,518Q614,518 614,518L549,518L549,840L160,840ZM337,746L425,606L372,606L372,501L285,641L337,641L337,746Z"/>
|
||||
</vector>
|
||||
|
||||
Reference in New Issue
Block a user