Restaurants

This commit is contained in:
Dimitris
2026-05-05 14:27:00 +02:00
parent 202c2dfcea
commit 25ba7d7bf6
19 changed files with 134 additions and 83 deletions
+2 -2
View File
@@ -17,8 +17,8 @@ android {
applicationId = "com.kouros.navigation" applicationId = "com.kouros.navigation"
minSdk = 33 minSdk = 33
targetSdk = 37 targetSdk = 37
versionCode = 107 versionCode = 108
versionName = "0.3.0.107" versionName = "0.3.0.108"
base.archivesName = "navi-$versionName" base.archivesName = "navi-$versionName"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -755,7 +755,11 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
val duration = Duration.between(current, lastTrafficDate) val duration = Duration.between(current, lastTrafficDate)
if (showTraffic && duration.abs().seconds > TRAFFIC_UPDATE) { if (showTraffic && duration.abs().seconds > TRAFFIC_UPDATE) {
lastTrafficDate = current lastTrafficDate = current
navigationViewModel.loadTraffic(carContext, location, surfaceRenderer.carOrientation) navigationViewModel.loadTraffic(
carContext,
location,
surfaceRenderer.carOrientation
)
} }
} }
@@ -28,12 +28,20 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.kouros.data.R import com.kouros.data.R
import com.kouros.navigation.data.ClosedColor
import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Constants.homeVogelhart import com.kouros.navigation.data.Constants.homeVogelhart
import com.kouros.navigation.data.HeavyColor
import com.kouros.navigation.data.LaneColor
import com.kouros.navigation.data.NavigationColorDark import com.kouros.navigation.data.NavigationColorDark
import com.kouros.navigation.data.NavigationColorLight import com.kouros.navigation.data.NavigationColorLight
import com.kouros.navigation.data.PharmacyColor
import com.kouros.navigation.data.QueuingColor
import com.kouros.navigation.data.RoadworksColor
import com.kouros.navigation.data.RouteColor import com.kouros.navigation.data.RouteColor
import com.kouros.navigation.data.SlowColor
import com.kouros.navigation.data.SpeedColor import com.kouros.navigation.data.SpeedColor
import com.kouros.navigation.data.StationaryColor
import com.kouros.navigation.data.ViewStyle import com.kouros.navigation.data.ViewStyle
import com.kouros.navigation.utils.GeoUtils.createEndCollection import com.kouros.navigation.utils.GeoUtils.createEndCollection
import com.kouros.navigation.utils.GeoUtils.createPointCollection import com.kouros.navigation.utils.GeoUtils.createPointCollection
@@ -180,6 +188,12 @@ fun RouteLayer(routeData: String?) {
fun TrafficLayer(trafficData: Map<String, String>) { fun TrafficLayer(trafficData: Map<String, String>) {
trafficData.forEach { trafficData.forEach {
val traffic = rememberGeoJsonSource(GeoJsonData.JsonString(it.value)) val traffic = rememberGeoJsonSource(GeoJsonData.JsonString(it.value))
LineLayer(
id = "traffic-${it.key}-casing",
source = traffic,
color = const(Color.White),
width = routeLineWidth(base = 2.dp, isCasing = true),
)
LineLayer( LineLayer(
id = "traffic-${it.key}", id = "traffic-${it.key}",
source = traffic, source = traffic,
@@ -289,13 +303,13 @@ fun trafficImage(key: String): Expression<ImageValue> {
fun trafficColor(key: String): Expression<ColorValue> { fun trafficColor(key: String): Expression<ColorValue> {
when (key) { when (key) {
"queuing" -> return const(Color(0xFFC46E53)) "queuing" -> return const(QueuingColor)
"slow" -> return const(Color(0xFFC43E3E)) "slow" -> return const(SlowColor)
"stationary" -> return const(Color(0xFF910A0A)) "stationary" -> return const(StationaryColor)
"heavy" -> return const(Color(0xFF6B0404)) "heavy" -> return const(HeavyColor)
"roadworks" -> return const(Color(0xFFDAA707)) "roadworks" -> return const(RoadworksColor)
"closed" -> return const(Color(0xFF210C0F)) "closed" -> return const(ClosedColor)
"lane" -> return const(Color(0xFFEFBAC1)) "lane" -> return const(LaneColor)
} }
return const(Color.Blue) return const(Color.Blue)
} }
@@ -306,11 +320,14 @@ fun AmenityLayer(routeData: String?) {
var color = const(Color.Red) var color = const(Color.Red)
var img = image(painterResource(R.drawable.local_pharmacy_24px), drawAsSdf = true) var img = image(painterResource(R.drawable.local_pharmacy_24px), drawAsSdf = true)
if (routeData.contains(Constants.CHARGING_STATION)) { if (routeData.contains(Constants.CHARGING_STATION)) {
color = const(Color(0xFF054603)) color = const(PharmacyColor)
img = image(painterResource(R.drawable.ev_station_24px), drawAsSdf = true) img = image(painterResource(R.drawable.ev_station_24px), drawAsSdf = true)
} else if (routeData.contains(Constants.FUEL_STATION)) { } else if (routeData.contains(Constants.FUEL_STATION)) {
color = const(Color.Blue) color = const(Color.Blue)
img = image(painterResource(R.drawable.local_gas_station_24), drawAsSdf = true) img = image(painterResource(R.drawable.local_gas_station_24), drawAsSdf = true)
} else if (routeData.contains(Constants.RESTAURANT)) {
color = const(Color.Magenta)
img = image(painterResource(R.drawable.restaurant_24px), drawAsSdf = true)
} }
val routes = rememberGeoJsonSource(GeoJsonData.JsonString(routeData)) val routes = rememberGeoJsonSource(GeoJsonData.JsonString(routeData))
SymbolLayer( SymbolLayer(
@@ -4,6 +4,8 @@ import androidx.car.app.CarContext
import androidx.car.app.Screen import androidx.car.app.Screen
import androidx.car.app.model.Action import androidx.car.app.model.Action
import androidx.car.app.model.CarIcon import androidx.car.app.model.CarIcon
import androidx.car.app.model.GridItem
import androidx.car.app.model.GridTemplate
import androidx.car.app.model.Header import androidx.car.app.model.Header
import androidx.car.app.model.ItemList import androidx.car.app.model.ItemList
import androidx.car.app.model.ListTemplate import androidx.car.app.model.ListTemplate
@@ -16,6 +18,7 @@ import com.kouros.navigation.data.Category
import com.kouros.navigation.data.Constants.CHARGING_STATION import com.kouros.navigation.data.Constants.CHARGING_STATION
import com.kouros.navigation.data.Constants.FUEL_STATION import com.kouros.navigation.data.Constants.FUEL_STATION
import com.kouros.navigation.data.Constants.PHARMACY import com.kouros.navigation.data.Constants.PHARMACY
import com.kouros.navigation.data.Constants.RESTAURANT
import com.kouros.navigation.data.ViewStyle import com.kouros.navigation.data.ViewStyle
import com.kouros.navigation.model.NavigationViewModel import com.kouros.navigation.model.NavigationViewModel
@@ -30,22 +33,18 @@ class CategoriesScreen(
var categories: List<Category> = listOf( var categories: List<Category> = listOf(
Category(id = FUEL_STATION, name = carContext.getString(R.string.fuel_station)), Category(id = FUEL_STATION, name = carContext.getString(R.string.fuel_station)),
Category(id = PHARMACY, name = carContext.getString(R.string.pharmacy)), Category(id = PHARMACY, name = carContext.getString(R.string.pharmacy)),
Category(id = CHARGING_STATION, name = carContext.getString(R.string.charging_station)) Category(id = CHARGING_STATION, name = carContext.getString(R.string.charging_station)),
Category(id = RESTAURANT, name = carContext.getString(R.string.restaurant))
) )
init {
}
override fun onGetTemplate(): Template { override fun onGetTemplate(): Template {
val itemListBuilder = ItemList.Builder() val itemListBuilder = ItemList.Builder()
.setNoItemsMessage("No categories to show") .setNoItemsMessage("No categories to show")
categories.forEach { categories.forEach {
itemListBuilder.addItem( itemListBuilder.addItem(
Row.Builder() GridItem.Builder()
.setTitle(it.name)
.setImage(carIcon(carContext, it.id, -1)) .setImage(carIcon(carContext, it.id, -1))
.setTitle(it.name)
.setOnClickListener { .setOnClickListener {
category = it.id category = it.id
screenManager screenManager
@@ -55,7 +54,7 @@ class CategoriesScreen(
surfaceRenderer, surfaceRenderer,
category, category,
navigationViewModel, navigationViewModel,
) )
) { obj: Any? -> ) { obj: Any? ->
if (obj != null) { if (obj != null) {
setResult(obj) setResult(obj)
@@ -63,20 +62,19 @@ class CategoriesScreen(
} }
} }
} }
.setBrowsable(true)
.build() .build()
) )
} }
surfaceRenderer.viewStyle = ViewStyle.AMENITY_VIEW surfaceRenderer.viewStyle = ViewStyle.AMENITY_VIEW
val header = Header.Builder() return GridTemplate.Builder()
.setStartHeaderAction(Action.BACK) .setHeader(
.setTitle(carContext.getString(R.string.category_title)) Header.Builder()
.build() .setStartHeaderAction(Action.BACK)
.setTitle(carContext.getString(R.string.category_title))
return ListTemplate.Builder() .build()
.setHeader(header) )
.setSingleList(itemListBuilder.build()) .setSingleList(itemListBuilder.build())
.build() .build()
} }
@@ -88,7 +86,7 @@ fun carIcon(context: CarContext, category: String, index: Int): CarIcon {
CHARGING_STATION -> R.drawable.ev_station_24px CHARGING_STATION -> R.drawable.ev_station_24px
FUEL_STATION -> R.drawable.local_gas_station_24 FUEL_STATION -> R.drawable.local_gas_station_24
PHARMACY -> R.drawable.local_pharmacy_24px PHARMACY -> R.drawable.local_pharmacy_24px
else -> R.drawable.ic_place_white_24dp else -> R.drawable.restaurant_24px
} }
return CarIcon.Builder(IconCompat.createWithResource(context, resId)).build() return CarIcon.Builder(IconCompat.createWithResource(context, resId)).build()
} else { } else {
@@ -31,6 +31,7 @@ import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Constants.CHARGING_STATION import com.kouros.navigation.data.Constants.CHARGING_STATION
import com.kouros.navigation.data.Constants.FUEL_STATION import com.kouros.navigation.data.Constants.FUEL_STATION
import com.kouros.navigation.data.Constants.PHARMACY import com.kouros.navigation.data.Constants.PHARMACY
import com.kouros.navigation.data.Constants.RESTAURANT
import com.kouros.navigation.data.Constants.TAG import com.kouros.navigation.data.Constants.TAG
import com.kouros.navigation.data.Place import com.kouros.navigation.data.Place
import com.kouros.navigation.data.overpass.Elements import com.kouros.navigation.data.overpass.Elements
@@ -52,7 +53,6 @@ class CategoryScreen(
) : Screen(carContext), CategoryObserverCallback { ) : Screen(carContext), CategoryObserverCallback {
val repository = getSettingsRepository(carContext) val repository = getSettingsRepository(carContext)
val settingsViewModel = getSettingsViewModel(carContext) val settingsViewModel = getSettingsViewModel(carContext)
@@ -77,7 +77,6 @@ class CategoryScreen(
}) })
navigationViewModel.elements.observe(this, categoryObserver) navigationViewModel.elements.observe(this, categoryObserver)
//navigationViewModel.getAmenities(carContext, category, surfaceRenderer.lastLocation)
} }
override fun onGetTemplate(): Template { override fun onGetTemplate(): Template {
@@ -94,12 +93,10 @@ class CategoryScreen(
) )
) )
elements.forEach { elements.forEach {
if (it.tags.operator != null) { if (index++ < listLimit) {
if (index++ < listLimit) { listBuilder.addItem(
listBuilder.addItem( createItem(it, category, index)
createItem(it, category, index) )
)
}
} }
} }
} }
@@ -133,7 +130,7 @@ class CategoryScreen(
CHARGING_STATION -> R.string.charging_station CHARGING_STATION -> R.string.charging_station
FUEL_STATION -> R.string.fuel_station FUEL_STATION -> R.string.fuel_station
PHARMACY -> R.string.pharmacy PHARMACY -> R.string.pharmacy
else -> R.string.no_places else -> R.string.restaurant
} }
return carContext.getString(resId) return carContext.getString(resId)
} }
@@ -154,10 +151,10 @@ class CategoryScreen(
} }
.setTitle(name) .setTitle(name)
.setImage(carIcon(carContext, category, index)) .setImage(carIcon(carContext, category, index))
if (category == CHARGING_STATION) { when (category) {
row.addText("${it.tags.socketType2} X Typ 2 ${it.tags.socketType2Output}") CHARGING_STATION -> row.addText("${it.tags.socketType2} X Typ 2 ${it.tags.socketType2Output}")
} else { FUEL_STATION -> row.addText(carText("${it.e5} / ${it.e10}${it.tags.openingHours}"))
row.addText(carText(" ${it.e5} / ${it.e10}${it.tags.openingHours}")) RESTAURANT, PHARMACY ->row.addText(carText(it.tags.openingHours))
} }
if (it.distance < 1000) { if (it.distance < 1000) {
row.addText("${(it.distance).toInt()} m") row.addText("${(it.distance).toInt()} m")
@@ -3,7 +3,6 @@ package com.kouros.navigation.car.screen
import android.text.SpannableString import android.text.SpannableString
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.Spanned import android.text.Spanned
import android.util.Log
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.car.app.CarContext import androidx.car.app.CarContext
import androidx.car.app.CarToast import androidx.car.app.CarToast
@@ -13,7 +12,6 @@ import androidx.car.app.model.Action
import androidx.car.app.model.Action.FLAG_DEFAULT import androidx.car.app.model.Action.FLAG_DEFAULT
import androidx.car.app.model.Action.FLAG_IS_PERSISTENT import androidx.car.app.model.Action.FLAG_IS_PERSISTENT
import androidx.car.app.model.CarColor import androidx.car.app.model.CarColor
import androidx.car.app.model.CarIcon
import androidx.car.app.model.CarText import androidx.car.app.model.CarText
import androidx.car.app.model.DurationSpan import androidx.car.app.model.DurationSpan
import androidx.car.app.model.ForegroundCarColorSpan import androidx.car.app.model.ForegroundCarColorSpan
@@ -26,7 +24,6 @@ import androidx.car.app.model.Template
import androidx.car.app.navigation.model.MapController import androidx.car.app.navigation.model.MapController
import androidx.car.app.navigation.model.MapWithContentTemplate import androidx.car.app.navigation.model.MapWithContentTemplate
import androidx.car.app.versioning.CarAppApiLevels import androidx.car.app.versioning.CarAppApiLevels
import androidx.core.graphics.drawable.IconCompat
import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
@@ -35,7 +32,6 @@ import androidx.lifecycle.lifecycleScope
import com.kouros.data.R import com.kouros.data.R
import com.kouros.navigation.car.SurfaceRenderer import com.kouros.navigation.car.SurfaceRenderer
import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.data.Constants.TAG
import com.kouros.navigation.data.Place import com.kouros.navigation.data.Place
import com.kouros.navigation.data.ViewStyle import com.kouros.navigation.data.ViewStyle
import com.kouros.navigation.data.route.Routes import com.kouros.navigation.data.route.Routes
@@ -377,7 +373,6 @@ class RoutePreviewScreen(
surfaceRenderer.carOrientation surfaceRenderer.carOrientation
) )
} }
} }
enum class RoutePreviewType { enum class RoutePreviewType {
@@ -50,7 +50,7 @@ fun createNumberIcon(category: String, number: String): IconCompat {
CHARGING_STATION -> Color.GREEN CHARGING_STATION -> Color.GREEN
FUEL_STATION -> Color.BLUE FUEL_STATION -> Color.BLUE
PHARMACY -> Color.RED PHARMACY -> Color.RED
else -> Color.WHITE else -> Color.MAGENTA
} }
paint.color = color paint.color = color
canvas.drawCircle(size / 2f, size / 2f, size / 2f, paint) canvas.drawCircle(size / 2f, size / 2f, size / 2f, paint)
@@ -12,3 +12,13 @@ val SpeedColor = Color(0xFF262525)
val MaxSpeedColor = Color(0xFFB71515) val MaxSpeedColor = Color(0xFFB71515)
val PlaceColor = Color(0xFF868005) val PlaceColor = Color(0xFF868005)
val QueuingColor = Color(0xFFC46E53)
val SlowColor = Color(0xFFC43E3E)
val StationaryColor = Color(0xFF910A0A)
val HeavyColor = Color(0xFF6B0404)
val RoadworksColor = Color(0xFFDAA707)
val ClosedColor = Color(0xFF280C10)
val LaneColor = Color(0xFFEFBAC1)
val PharmacyColor = Color(0xFF054603)
@@ -122,6 +122,8 @@ object Constants {
const val CHARGING_STATION: String ="charging_station" const val CHARGING_STATION: String ="charging_station"
const val RESTAURANT: String ="restaurant"
/** The initial location to use as an anchor for searches. */ /** The initial location to use as an anchor for searches. */
val homeVogelhart = location(11.5793748, 48.185749) val homeVogelhart = location(11.5793748, 48.185749)
val homeHohenwaldeck = location( 11.594322, 48.1164817) val homeHohenwaldeck = location( 11.594322, 48.1164817)
@@ -75,7 +75,7 @@ abstract class NavigationRepository {
"Accept", "Accept",
"application/json" "application/json"
) // The format of response we want to get from the server ) // The format of response we want to get from the server
httpURLConnection.setRequestProperty("User-Agent", "email=nominatim@kouros-online.de") httpURLConnection.setRequestProperty("User-Agent", "email=online@kouros-online.de")
httpURLConnection.requestMethod = "GET" httpURLConnection.requestMethod = "GET"
val responseCode = httpURLConnection.responseCode val responseCode = httpURLConnection.responseCode
if (responseCode == HttpURLConnection.HTTP_OK) { if (responseCode == HttpURLConnection.HTTP_OK) {
@@ -136,6 +136,7 @@ class Overpass {
} }
} }
Log.w("OverpassApi", searchQuery)
val responseCode = connection.responseCode val responseCode = connection.responseCode
if (responseCode == HttpURLConnection.HTTP_OK) { if (responseCode == HttpURLConnection.HTTP_OK) {
val response = connection.inputStream.bufferedReader().use { it.readText() } val response = connection.inputStream.bufferedReader().use { it.readText() }
@@ -21,7 +21,7 @@ data class Tags(
val capacity: String = "", val capacity: String = "",
val motorcar: String = "", val motorcar: String = "",
val network: String = "", val network: String = "",
val openingHours: String = "", @SerializedName("opening_hours") val openingHours: String = "",
val operator: String = "", val operator: String = "",
val operatorShort: String = "", val operatorShort: String = "",
val operatorWikidata: String = "", val operatorWikidata: String = "",
@@ -19,7 +19,6 @@ import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.data.Place import com.kouros.navigation.data.Place
import com.kouros.navigation.data.Places import com.kouros.navigation.data.Places
import com.kouros.navigation.data.SearchFilter import com.kouros.navigation.data.SearchFilter
import com.kouros.navigation.data.fuel.FuelPrice
import com.kouros.navigation.data.fuel.FuelPrices import com.kouros.navigation.data.fuel.FuelPrices
import com.kouros.navigation.data.fuel.Station import com.kouros.navigation.data.fuel.Station
import com.kouros.navigation.data.fuel.Stations import com.kouros.navigation.data.fuel.Stations
@@ -28,15 +27,14 @@ import com.kouros.navigation.data.nominatim.SearchResult
import com.kouros.navigation.data.overpass.ElementSearch import com.kouros.navigation.data.overpass.ElementSearch
import com.kouros.navigation.data.overpass.Elements import com.kouros.navigation.data.overpass.Elements
import com.kouros.navigation.data.overpass.Overpass import com.kouros.navigation.data.overpass.Overpass
import com.kouros.navigation.repository.SettingsRepository
import com.kouros.navigation.utils.GeoUtils.snapLocation import com.kouros.navigation.utils.GeoUtils.snapLocation
import com.kouros.navigation.utils.GeoUtils.transferCoordinates import com.kouros.navigation.utils.GeoUtils.transferCoordinates
import com.kouros.navigation.utils.bearingPositive import com.kouros.navigation.utils.bearingPositive
import com.kouros.navigation.utils.countryCodeSpeedLimit import com.kouros.navigation.utils.countryCodeSpeedLimit
import com.kouros.navigation.utils.getSettingsRepository import com.kouros.navigation.utils.getSettingsRepository
import com.kouros.navigation.utils.getSettingsViewModel
import com.kouros.navigation.utils.isNumeric import com.kouros.navigation.utils.isNumeric
import com.kouros.navigation.utils.location import com.kouros.navigation.utils.location
import com.kouros.navigation.utils.settingsViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@@ -220,7 +218,11 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
* Fetches traffic incident data and categorizes by severity. * Fetches traffic incident data and categorizes by severity.
* Posts categorized traffic map to traffic LiveData. * Posts categorized traffic map to traffic LiveData.
*/ */
fun loadTraffic(context: Context, currentLocation: Location, carOrientation: Float) { fun loadTraffic(
context: Context,
currentLocation: Location,
carOrientation: Float,
) {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
val data = repository.getTraffic( val data = repository.getTraffic(
@@ -400,18 +402,8 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
fun getAmenities(carContext: Context, category: String, location: Location, lastFuelUpdate: Long = 0) { fun getAmenities(carContext: Context, category: String, location: Location, lastFuelUpdate: Long = 0) {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
val repository = getSettingsRepository(carContext) val repository = getSettingsRepository(carContext)
var fuelPrices: List<Station>
val amenities = Overpass().getAmenities("amenity", category, location, 5.0) val amenities = Overpass().getAmenities("amenity", category, location, 5.0)
val now = System.currentTimeMillis() val fuelPrices = fuelStations(category, lastFuelUpdate, location, repository)
if (category == Constants.FUEL_STATION && ((now - lastFuelUpdate) > TANKER_KOENIG_DELAY)) {
fuelPrices = FuelPrices().getFuelPrices(location, 5)
repository.setLastFuelPrices(System.currentTimeMillis())
repository.setFuelPrices(gson.toJson(Stations(fuelPrices)))
} else {
val fuels = repository.fuelPricesFlow.first()
fuelPrices =
gson.fromJson(fuels, Stations::class.java).stations
}
val distAmenities = mutableListOf<Elements>() val distAmenities = mutableListOf<Elements>()
amenities.forEach { amenities.forEach {
val plLocation = val plLocation =
@@ -428,6 +420,28 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
} }
} }
private suspend fun fuelStations(
category: String,
lastFuelUpdate: Long,
location: Location,
repository: SettingsRepository
): List<Station> {
var fuelPrices = emptyList<Station>()
if (category == Constants.FUEL_STATION) {
val now = System.currentTimeMillis()
if ((now - lastFuelUpdate) > TANKER_KOENIG_DELAY) {
fuelPrices = FuelPrices().getFuelPrices(location, 5)
repository.setLastFuelPrices(System.currentTimeMillis())
repository.setFuelPrices(gson.toJson(Stations(fuelPrices)))
} else {
val fuels = repository.fuelPricesFlow.first()
fuelPrices =
gson.fromJson(fuels, Stations::class.java).stations
}
}
return fuelPrices
}
fun addFuelPrice(fuel: Elements, fuelPrices: List<Station>, location: Location) { fun addFuelPrice(fuel: Elements, fuelPrices: List<Station>, location: Location) {
fuelPrices.forEach { fuelPrices.forEach {
if (fuel.tags.name.equals(it.brand, ignoreCase = true)) { if (fuel.tags.name.equals(it.brand, ignoreCase = true)) {
@@ -1,7 +1,6 @@
package com.kouros.navigation.utils package com.kouros.navigation.utils
import android.location.Location import android.location.Location
import android.util.Log
import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put import kotlinx.serialization.json.put
import org.maplibre.geojson.FeatureCollection import org.maplibre.geojson.FeatureCollection
@@ -24,6 +23,8 @@ import kotlin.math.sin
object GeoUtils { object GeoUtils {
const val EARTH_RADIUS = 6371.0 // in km
fun snapLocation(location: Location, stepCoordinates: List<Point>): Location { fun snapLocation(location: Location, stepCoordinates: List<Point>): Location {
val newLocation = Location(location) val newLocation = Location(location)
val oldPoint = Point.fromLngLat(location.longitude, location.latitude) val oldPoint = Point.fromLngLat(location.longitude, location.latitude)
@@ -151,11 +152,10 @@ object GeoUtils {
* @return latMin, latMax, lngMin, lngMax * @return latMin, latMax, lngMin, lngMax
*/ */
fun calculateSquareRadius(lat: Double, lng: Double, radius: Double): String { fun calculateSquareRadius(lat: Double, lng: Double, radius: Double): String {
val earthRadius = 6371.0 // earth radius in km val latMin = lat - toDegrees(radius / EARTH_RADIUS)
val latMin = lat - toDegrees(radius / earthRadius) val latMax = lat + toDegrees(radius / EARTH_RADIUS)
val latMax = lat + toDegrees(radius / earthRadius) val lngMin = lng - toDegrees(radius / EARTH_RADIUS / cos(toRadians(lat)))
val lngMin = lng - toDegrees(radius / earthRadius / cos(toRadians(lat))) val lngMax = lng + toDegrees(radius / EARTH_RADIUS / cos(toRadians(lat)))
val lngMax = lng + toDegrees(radius / earthRadius / cos(toRadians(lat)))
return "$lngMin,$latMin,$lngMax,$latMax" return "$lngMin,$latMin,$lngMax,$latMax"
} }
@@ -165,11 +165,10 @@ object GeoUtils {
lon: Double, lon: Double,
radius: Double radius: Double
): String { ): String {
val earthRadius = 6371.0 val maxLat = lat + toDegrees(radius / EARTH_RADIUS)
val maxLat = lat + toDegrees(radius / earthRadius) val minLat = lat - toDegrees(radius / EARTH_RADIUS)
val minLat = lat - toDegrees(radius / earthRadius) val maxLon = lon + toDegrees(radius / EARTH_RADIUS / cos(toRadians(lat)))
val maxLon = lon + toDegrees(radius / earthRadius / cos(toRadians(lat))) val minLon = lon - toDegrees(radius / EARTH_RADIUS / cos(toRadians(lat)))
val minLon = lon - toDegrees(radius / earthRadius / cos(toRadians(lat)))
return "$minLat,$minLon,$maxLat,$maxLon" return "$minLat,$minLon,$maxLat,$maxLon"
} }
@@ -229,21 +228,21 @@ object GeoUtils {
fun movePoint( fun movePoint(
latitude: Double, latitude: Double,
longitude: Double, longitude: Double,
distanceMeters: Double = 7.0, distanceMeters: Double = 8.0,
bearingDegrees: Double = 0.0 bearingDegrees: Double = 0.0
): org.maplibre.spatialk.geojson.Point { ): org.maplibre.spatialk.geojson.Point {
val earthRadius = 6371000.0 // meters val radius = EARTH_RADIUS * 1000 // meters
val bearingRadians = toRadians(bearingDegrees) val bearingRadians = toRadians(bearingDegrees)
val lat1 = toRadians(latitude) val lat1 = toRadians(latitude)
val lon1 = toRadians(longitude) val lon1 = toRadians(longitude)
val lat2 = asin( val lat2 = asin(
sin(lat1) * cos(distanceMeters / earthRadius) + sin(lat1) * cos(distanceMeters / radius) +
cos(lat1) * sin(distanceMeters / earthRadius) * cos(bearingRadians) cos(lat1) * sin(distanceMeters / radius) * cos(bearingRadians)
) )
val lon2 = lon1 + atan2( val lon2 = lon1 + atan2(
sin(bearingRadians) * sin(distanceMeters / earthRadius) * cos(lat1), sin(bearingRadians) * sin(distanceMeters / radius) * cos(lat1),
cos(distanceMeters / earthRadius) - sin(lat1) * sin(lat2) cos(distanceMeters / radius) - sin(lat1) * sin(lat2)
) )
return org.maplibre.spatialk.geojson.Point(toDegrees(lon2), toDegrees(lat2)) return org.maplibre.spatialk.geojson.Point(toDegrees(lon2), toDegrees(lat2))
} }
@@ -0,0 +1,10 @@
<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="M280,880L280,514Q229,500 194.5,458Q160,416 160,360L160,80L240,80L240,360L280,360L280,80L360,80L360,360L400,360L400,80L480,80L480,360Q480,416 445.5,458Q411,500 360,514L360,880L280,880ZM680,880L680,560L560,560L560,280Q560,197 618.5,138.5Q677,80 760,80L760,880L680,880Z"/>
</vector>
@@ -73,4 +73,5 @@
<string name="engine_type">Motortyp</string> <string name="engine_type">Motortyp</string>
<string name="alternative_routes">Alternative Routen</string> <string name="alternative_routes">Alternative Routen</string>
<string name="wait">Warten</string> <string name="wait">Warten</string>
<string name="restaurant">Restaurant</string>
</resources> </resources>
@@ -57,4 +57,5 @@
<string name="engine_type">Τύπος κινητήρα</string> <string name="engine_type">Τύπος κινητήρα</string>
<string name="alternative_routes">Εναλλακτικές διαδρομές</string> <string name="alternative_routes">Εναλλακτικές διαδρομές</string>
<string name="wait">Περιμένετε</string> <string name="wait">Περιμένετε</string>
<string name="restaurant">Restaurant</string>
</resources> </resources>
@@ -57,4 +57,5 @@
<string name="engine_type">Typ silnika</string> <string name="engine_type">Typ silnika</string>
<string name="alternative_routes">Alternatywne trasy</string> <string name="alternative_routes">Alternatywne trasy</string>
<string name="wait">Czekaj</string> <string name="wait">Czekaj</string>
<string name="restaurant">Restaurant</string>
</resources> </resources>
@@ -60,4 +60,5 @@
<string name="engine_type">Engine type</string> <string name="engine_type">Engine type</string>
<string name="alternative_routes">Alternative routes</string> <string name="alternative_routes">Alternative routes</string>
<string name="wait">Wait</string> <string name="wait">Wait</string>
<string name="restaurant">Restaurant</string>
</resources> </resources>