Fuel, Snap initial location

This commit is contained in:
Dimitris
2026-04-30 15:50:23 +02:00
parent 3926bbf1f9
commit 60cd6abc35
8 changed files with 160 additions and 12 deletions
@@ -273,6 +273,10 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
routeModel = RouteCarModel()
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)
navigationViewModel.initialSnapLocation.observe(this, Observer {
surfaceRenderer.updateLocation(it, "")
})
}
/**
@@ -315,6 +319,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
shouldUseCarLocationFlow = carSensorManager.shouldUseCarLocation(),
onLocationUpdate = ::updateLocation,
onInitialLocation = { location ->
navigationViewModel.loadCurrentLocation(location)
navigationViewModel.loadRecentPlaces(
carContext,
location,
@@ -753,12 +758,6 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
lastTrafficDate = current
navigationViewModel.loadTraffic(carContext, location, surfaceRenderer.carOrientation)
}
if (updateLocationIndex % 4 == 0) {
// navigationViewModel.updateTrafficMessages(
// surfaceRenderer.lastLocation,
// surfaceRenderer.trafficData.value!!
// )
}
}
/**
@@ -0,0 +1,9 @@
package com.kouros.navigation.data.fuel
data class FuelPrice(
val `data`: String,
val license: String,
val ok: Boolean,
val stations: List<Station>,
val status: String
)
@@ -0,0 +1,53 @@
package com.kouros.navigation.data.fuel
import android.content.Context
import android.location.Location
import android.util.Log
import com.google.gson.GsonBuilder
import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.data.SearchFilter
import com.kouros.navigation.data.overpass.Amenity
import java.io.OutputStreamWriter
import java.net.Authenticator
import java.net.HttpURLConnection
import java.net.PasswordAuthentication
import java.net.URL
const val tankerKoenigUrl = "https://creativecommons.tankerkoenig.de/json/list.php?"
private val gson = GsonBuilder().serializeNulls().create()
const val sort = "&sort=dist&type=all"
const val apiKey = "&apikey=fc9900c9-8f02-4b28-990d-dc6067228c59"
class FuelPrices : NavigationRepository() {
fun getFuelPrices(location: Location, radius: Int) : List<Station> {
val url = "${tankerKoenigUrl}lat=${location.latitude}&lng=${location.longitude}&rad=${radius}$sort$apiKey"
val prices = fetchUrl(
url,
false
)
return gson.fromJson(prices, FuelPrice::class.java).stations
}
override fun getRoute(
context: Context,
currentLocation: Location,
location: List<Location>,
carOrientation: Float,
searchFilter: SearchFilter
): String {
TODO("Not yet implemented")
}
override fun getTraffic(
context: Context,
location: Location,
carOrientation: Float
): String {
TODO("Not yet implemented")
}
}
@@ -0,0 +1,18 @@
package com.kouros.navigation.data.fuel
data class Station(
val brand: String,
val diesel: Double,
val dist: Double,
val e10: Double,
val e5: Double,
val houseNumber: String,
val id: String,
val isOpen: Boolean,
val lat: Double,
val lng: Double,
val name: String,
val place: String,
val postCode: Int,
val street: String
)
@@ -4,7 +4,6 @@ import android.location.Location
import android.util.Log
import com.google.gson.GsonBuilder
import com.kouros.data.BuildConfig
import com.kouros.navigation.data.ApplicationConfig
import com.kouros.navigation.utils.GeoUtils.getBoundingBox
import java.io.OutputStreamWriter
import java.net.Authenticator
@@ -69,6 +68,28 @@ class Overpass {
}
fun getStreet(location: Location): List<Elements> {
val lineString = "${location.latitude},${location.longitude}"
val searchLocation ="way[\"highway\"~\"^(primary|secondary|tertiary|residential|motorway)$\"][name](around:50, $lineString)";
val searchQuery = """
|[out:json];
|(
| ${searchLocation};
|);
|out body geom;
""".trimMargin()
val connection = (URL(overpassUrl).openConnection() as HttpURLConnection).apply {
requestMethod = "POST"
setRequestProperty("Accept", "application/json")
doOutput = true
}
return overpassApi(connection, searchQuery)
}
fun getAmenities(
type: String,
category: String,
@@ -10,7 +10,6 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.kouros.navigation.data.ApplicationConfig
import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Constants.SPEED_BEARING_DEVIATION
import com.kouros.navigation.data.Constants.SPEED_UPDATE_DISTANCE
@@ -19,11 +18,13 @@ import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.data.Place
import com.kouros.navigation.data.Places
import com.kouros.navigation.data.SearchFilter
import com.kouros.navigation.data.fuel.FuelPrices
import com.kouros.navigation.data.nominatim.Search
import com.kouros.navigation.data.nominatim.SearchResult
import com.kouros.navigation.data.overpass.ElementSearch
import com.kouros.navigation.data.overpass.Elements
import com.kouros.navigation.data.overpass.Overpass
import com.kouros.navigation.utils.GeoUtils.snapLocation
import com.kouros.navigation.utils.bearingPositive
import com.kouros.navigation.utils.countryCodeSpeedLimit
import com.kouros.navigation.utils.getSettingsRepository
@@ -37,7 +38,7 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.maplibre.geojson.FeatureCollection
import org.maplibre.geojson.LineString
import org.maplibre.geojson.Point
import java.time.LocalDateTime
import java.time.ZoneOffset
import kotlin.collections.first
@@ -125,6 +126,10 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
MutableLiveData()
}
val initialSnapLocation: MutableLiveData<Location> by lazy {
MutableLiveData()
}
val gson: Gson = GsonBuilder().create()
/**
@@ -528,6 +533,21 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
}
}
/**
* Queries Tankerkoenig API for fuel prices on current road.
*
*/
fun updateFuelPrices(
location: Location,
) {
viewModelScope.launch(Dispatchers.IO) {
synchronized(this) {
val stations =
FuelPrices().getFuelPrices(location, 3)
Log.d(TAG, "FuelPrices $stations")
}
}
}
/**
* Saves a place as a favorite in Preferences.
@@ -652,4 +672,31 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
}
return pl.toMutableStateList()
}
/**
* Loads current location nearest street
* and snap to location to street
*/
fun loadCurrentLocation(location: Location) {
viewModelScope.launch(Dispatchers.IO) {
synchronized(this) {
val elements = Overpass().getStreet(location)
if (elements.isNotEmpty()) {
val points = mutableListOf<Point>()
elements.first().geometry.forEach {
points.add(Point.fromLngLat(it.lon, it.lat))
}
val snappedLocation = snapLocation(location, points)
if (points.size > 1) {
val bearing = location(
points.first().longitude(),
points.first().latitude()
).bearingPositive(location(points[1].longitude(), points[1].latitude()))
snappedLocation.bearing = bearing
}
initialSnapLocation.postValue(snappedLocation)
}
}
}
}
}
@@ -151,7 +151,8 @@ fun duration(
lastLocationUpdate: LocalDateTime
): Duration {
if (viewStyle == ViewStyle.PREVIEW ||
viewStyle == ViewStyle.PAN_VIEW) {
viewStyle == ViewStyle.PAN_VIEW ||
viewStyle == ViewStyle.AMENITY_VIEW) {
return 100.milliseconds
}
val cameraDuration = if ((lastBearing - bearing).absoluteValue > 20.0) {
+2 -2
View File
@@ -8,12 +8,12 @@ koinAndroid = "4.2.1"
koinAndroidxCompose = "4.2.1"
koinComposeViewmodel = "4.2.1"
koinCore = "4.2.1"
kotlin = "2.3.20"
kotlin = "2.3.21"
coreKtx = "1.18.0"
junit = "4.13.2"
junitVersion = "1.3.0"
espressoCore = "3.7.0"
kotlinxSerializationJson = "1.10.0"
kotlinxSerializationJson = "1.11.0"
lifecycleRuntimeKtx = "2.10.0"
composeBom = "2026.04.01"
appcompat = "1.7.1"