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() routeModel = RouteCarModel()
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated) 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(), shouldUseCarLocationFlow = carSensorManager.shouldUseCarLocation(),
onLocationUpdate = ::updateLocation, onLocationUpdate = ::updateLocation,
onInitialLocation = { location -> onInitialLocation = { location ->
navigationViewModel.loadCurrentLocation(location)
navigationViewModel.loadRecentPlaces( navigationViewModel.loadRecentPlaces(
carContext, carContext,
location, location,
@@ -753,12 +758,6 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
lastTrafficDate = current lastTrafficDate = current
navigationViewModel.loadTraffic(carContext, location, surfaceRenderer.carOrientation) 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 android.util.Log
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.kouros.data.BuildConfig import com.kouros.data.BuildConfig
import com.kouros.navigation.data.ApplicationConfig
import com.kouros.navigation.utils.GeoUtils.getBoundingBox import com.kouros.navigation.utils.GeoUtils.getBoundingBox
import java.io.OutputStreamWriter import java.io.OutputStreamWriter
import java.net.Authenticator 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( fun getAmenities(
type: String, type: String,
category: String, category: String,
@@ -10,7 +10,6 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.kouros.navigation.data.ApplicationConfig
import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Constants.SPEED_BEARING_DEVIATION import com.kouros.navigation.data.Constants.SPEED_BEARING_DEVIATION
import com.kouros.navigation.data.Constants.SPEED_UPDATE_DISTANCE 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.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.FuelPrices
import com.kouros.navigation.data.nominatim.Search import com.kouros.navigation.data.nominatim.Search
import com.kouros.navigation.data.nominatim.SearchResult 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.utils.GeoUtils.snapLocation
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
@@ -37,7 +38,7 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.maplibre.geojson.FeatureCollection import org.maplibre.geojson.FeatureCollection
import org.maplibre.geojson.LineString import org.maplibre.geojson.Point
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.ZoneOffset import java.time.ZoneOffset
import kotlin.collections.first import kotlin.collections.first
@@ -125,6 +126,10 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
MutableLiveData() MutableLiveData()
} }
val initialSnapLocation: MutableLiveData<Location> by lazy {
MutableLiveData()
}
val gson: Gson = GsonBuilder().create() 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. * Saves a place as a favorite in Preferences.
@@ -652,4 +672,31 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
} }
return pl.toMutableStateList() 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 lastLocationUpdate: LocalDateTime
): Duration { ): Duration {
if (viewStyle == ViewStyle.PREVIEW || if (viewStyle == ViewStyle.PREVIEW ||
viewStyle == ViewStyle.PAN_VIEW) { viewStyle == ViewStyle.PAN_VIEW ||
viewStyle == ViewStyle.AMENITY_VIEW) {
return 100.milliseconds return 100.milliseconds
} }
val cameraDuration = if ((lastBearing - bearing).absoluteValue > 20.0) { val cameraDuration = if ((lastBearing - bearing).absoluteValue > 20.0) {
+2 -2
View File
@@ -8,12 +8,12 @@ koinAndroid = "4.2.1"
koinAndroidxCompose = "4.2.1" koinAndroidxCompose = "4.2.1"
koinComposeViewmodel = "4.2.1" koinComposeViewmodel = "4.2.1"
koinCore = "4.2.1" koinCore = "4.2.1"
kotlin = "2.3.20" kotlin = "2.3.21"
coreKtx = "1.18.0" coreKtx = "1.18.0"
junit = "4.13.2" junit = "4.13.2"
junitVersion = "1.3.0" junitVersion = "1.3.0"
espressoCore = "3.7.0" espressoCore = "3.7.0"
kotlinxSerializationJson = "1.10.0" kotlinxSerializationJson = "1.11.0"
lifecycleRuntimeKtx = "2.10.0" lifecycleRuntimeKtx = "2.10.0"
composeBom = "2026.04.01" composeBom = "2026.04.01"
appcompat = "1.7.1" appcompat = "1.7.1"