Distance settings

This commit is contained in:
Dimitris
2026-03-03 16:34:03 +01:00
parent e1af3e19fa
commit 11e9dbb21e
39 changed files with 753 additions and 128 deletions

View File

@@ -20,4 +20,4 @@ data class NavigationState (
val carConnection: Int = 0,
val routingEngine: Int = 0,
val nextStep: Boolean = false,
)
)

View File

@@ -21,11 +21,11 @@ private const val DATASTORE_NAME = "navigation_settings"
class DataStoreManager(private val context: Context) {
companion object {
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = DATASTORE_NAME)
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = DATASTORE_NAME)
}
// Keys
private object PreferencesKeys {
object PreferencesKeys {
val SHOW_3D = booleanPreferencesKey("Show3D")
@@ -45,7 +45,7 @@ class DataStoreManager(private val context: Context) {
val RECENT_PLACES = stringPreferencesKey("RecentPlaces")
val FAVORITES = stringPreferencesKey("Favorites")
val DISTANCE_MODE = intPreferencesKey("DistanceMode")
}
@@ -79,7 +79,7 @@ class DataStoreManager(private val context: Context) {
val routingEngineFlow: Flow<Int> =
context.dataStore.data.map { preferences ->
preferences[PreferencesKeys.ROUTING_ENGINE]
?: 0
?: 2
}
val lastRouteFlow: Flow<String> =
@@ -100,10 +100,11 @@ class DataStoreManager(private val context: Context) {
?: ""
}
val favoritesFlow: Flow<String> =
val distanceModeFlow: Flow<Int> =
context.dataStore.data.map { preferences ->
preferences[PreferencesKeys.FAVORITES]
?: ""
preferences[PreferencesKeys.DISTANCE_MODE]
?: 0
}
// Save values
@@ -161,9 +162,10 @@ class DataStoreManager(private val context: Context) {
}
}
suspend fun setFavorites(apiKey: String) {
suspend fun setDistanceMode(mode: Int) {
context.dataStore.edit { prefs ->
prefs[PreferencesKeys.FAVORITES] = apiKey
prefs[PreferencesKeys.DISTANCE_MODE] = mode
}
}
}

View File

@@ -2,7 +2,11 @@ package com.kouros.navigation.data.route
data class Summary(
// sec
var duration : Double = 0.0,
// km
var distance : Double = 0.0,
var duration: Double = 0.0,
// m
var distance: Double = 0.0,
// sec
var trafficDelay: Double = 0.0,
// m
var trafficLength: Double = 0.0,
)

View File

@@ -25,7 +25,9 @@ class TomTomRoute {
var points = listOf<List<Double>>()
val summary = Summary(
route.summary.travelTimeInSeconds.toDouble(),
route.summary.lengthInMeters.toDouble()
route.summary.lengthInMeters.toDouble(),
route.summary.trafficDelayInSeconds.toDouble(),
route.summary.trafficLengthInMeters.toDouble()
)
route.legs.forEach { leg ->
points = decodePolyline(leg.encodedPolyline, leg.encodedPolylinePrecision)

View File

@@ -3,6 +3,7 @@ package com.kouros.navigation.model
//import com.kouros.navigation.data.Preferences.boxStore
import android.content.Context
import android.location.Location
import android.util.Log
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.platform.isDebugInspectorInfoEnabled

View File

@@ -69,7 +69,7 @@ class RouteCalculator(var routeModel: RouteModel) {
distance
}
}
return (leftDistance / 10.0).roundToInt() * 10.0
return leftDistance.toDouble()
}
/** Returns the left distance in m. */

View File

@@ -1,7 +1,10 @@
package com.kouros.navigation.model
import androidx.datastore.preferences.core.edit
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.kouros.navigation.data.datastore.DataStoreManager.Companion.dataStore
import com.kouros.navigation.data.datastore.DataStoreManager.PreferencesKeys
import com.kouros.navigation.repository.SettingsRepository
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn
@@ -63,6 +66,12 @@ class SettingsViewModel(private val repository: SettingsRepository) : ViewModel(
""
)
val distanceMode = repository.distanceModeFlow.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
0
)
fun onShow3DChanged(enabled: Boolean) {
viewModelScope.launch { repository.setShow3D(enabled) }
}
@@ -94,4 +103,9 @@ class SettingsViewModel(private val repository: SettingsRepository) : ViewModel(
fun onTomTomApiKeyChanged(key: String) {
viewModelScope.launch { repository.setTomTomApiKey(key) }
}
fun onDistanceModeChanged(mode: Int) {
viewModelScope.launch { repository.setDistanceMode(mode) }
}
}

View File

@@ -33,8 +33,8 @@ class SettingsRepository(
val recentPlacesFlow: Flow<String> =
dataStoreManager.recentPlacesFlow
val favoritesFlow: Flow<String> =
dataStoreManager.favoritesFlow
val distanceModeFlow: Flow<Int> =
dataStoreManager.distanceModeFlow
suspend fun setShow3D(enabled: Boolean) {
@@ -73,7 +73,9 @@ class SettingsRepository(
dataStoreManager.setRecentPlaces(places)
}
suspend fun setFavorites(favorites: String) {
dataStoreManager.setFavorites(favorites)
suspend fun setDistanceMode(mode: Int) {
dataStoreManager.setDistanceMode(mode)
}
}

View File

@@ -3,6 +3,7 @@ package com.kouros.navigation.utils
import android.content.Context
import android.location.Location
import android.location.LocationManager
import androidx.car.app.model.Distance
import com.kouros.navigation.data.RouteEngine
import com.kouros.navigation.data.osrm.OsrmRepository
import com.kouros.navigation.data.tomtom.TomTomRepository
@@ -16,6 +17,7 @@ import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.util.Locale
import kotlin.math.absoluteValue
import kotlin.math.pow
import kotlin.math.roundToInt
@@ -109,4 +111,34 @@ fun duration(preview: Boolean, bearing: Double, lastBearing: Double): Duration {
1.seconds
}
return cameraDuration
}
}
fun isMetricSystem(): Boolean {
val country = Locale.getDefault().country
// Return true for metric, false for imperial
return !setOf("US", "UK", "LR", "MM").contains(country)
}
fun formattedDistance(distanceMode : Int, distance: Double): Pair<Double, Int> {
var currentDistance = distance
var displayUnit: Int
if (distanceMode == 1 || distanceMode == 0 && isMetricSystem()) {
displayUnit = if (currentDistance > 1000.0) {
currentDistance /= 1000.0
Distance.UNIT_KILOMETERS
} else {
currentDistance = (currentDistance / 10.0).roundToInt() * 10.0
Distance.UNIT_METERS
}
} else {
currentDistance *= 0.621371
displayUnit = if (currentDistance > 1000.0) {
currentDistance /= 1000.0
Distance.UNIT_MILES
} else {
currentDistance = (currentDistance / 10.0).roundToInt() * 10.0
Distance.UNIT_FEET
}
}
return Pair(currentDistance, displayUnit)
}

View File

@@ -2,6 +2,7 @@ package com.kouros.navigation.utils
import android.content.Context
import androidx.car.app.CarContext
import androidx.car.app.model.Distance
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.ViewModel
@@ -13,6 +14,9 @@ import com.kouros.navigation.model.SettingsViewModel
import com.kouros.navigation.repository.SettingsRepository
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import java.text.NumberFormat
import java.util.Locale
import kotlin.math.roundToInt
@Composable

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -36,8 +36,8 @@
<string name="use_telephon_settings">Verwende Telefon Einstellungen</string>
<string name="threed_building">3D Gebäude</string>
<string name="drive_now">Losfahren</string>
<string name="avoid_tolls_row_title" msgid="5194057244144831024">"Mautstraßen meiden"</string>
<string name="avoid_highways_row_title" msgid="4711913426200490304">"Autobahnen meiden"</string>
<string name="avoid_tolls_row_title" msgid="5194057244144831024">"Mautstraßen vermeiden"</string>
<string name="avoid_highways_row_title" msgid="4711913426200490304">"Autobahnen vermeiden"</string>
<string name="recent_destinations">Letzte Ziele</string>
<string name="contacts">Kontakte</string>
<string name="route_preview">Route Vorschau</string>
@@ -54,5 +54,8 @@
<string name="use_car_settings">Verwende Auto Einstellungen</string>
<string name="exit_number">Ausfahrt nummer</string>
<string name="navigation_icon_description">Navigations Icon</string>
<string name="distance_units">Entfernungseinheiten</string>
<string name="automaticaly">Automatisch</string>
<string name="kilometer">Kilometer</string>
<string name="miles">Meilen</string>
</resources>

View File

@@ -18,7 +18,7 @@
<string name="avoid_highways_row_title">Avoid highways</string>
<string name="avoid_tolls_row_title">Avoid tolls rows</string>
<string name="no_places">No places</string>
<string name="recent_destinations">Recent destination</string>
<string name="recent_destinations">Recent destinations</string>
<string name="contacts">Contacts</string>
<string name="favorites">Favorites</string>
<string name="recent_Item_deleted">Recent item deleted</string>
@@ -40,4 +40,8 @@
<string name="use_car_settings">Use car settings</string>
<string name="exit_number">Exit number</string>
<string name="navigation_icon_description">Navigation icon</string>
<string name="distance_units">Distance units</string>
<string name="automaticaly">Automaticaly</string>
<string name="kilometer">Kilometer</string>
<string name="miles">Miles</string>
</resources>

View File

@@ -35,33 +35,33 @@ class IconMapperTest {
@Test
fun `addLanes returns correct lane direction`() {
val stepDataNormalLeft = StepData("", 0.0, Maneuver.TYPE_TURN_NORMAL_LEFT, 0, 0L, 0.0)
val stepDataNormalLeft = StepData("", "", 0.0, Maneuver.TYPE_TURN_NORMAL_LEFT, 0, 0L, 0.0)
assertEquals(LaneDirection.SHAPE_NORMAL_LEFT, iconMapper.addLanes("left_straight", stepDataNormalLeft))
assertEquals(LaneDirection.SHAPE_NORMAL_LEFT, iconMapper.addLanes("left", stepDataNormalLeft))
assertEquals(LaneDirection.SHAPE_SLIGHT_LEFT, iconMapper.addLanes("left_slight", stepDataNormalLeft))
assertEquals(LaneDirection.SHAPE_SLIGHT_LEFT, iconMapper.addLanes("slight_left", stepDataNormalLeft))
val stepDataStraight = StepData("", 0.0, Maneuver.TYPE_STRAIGHT, 0, 0L, 0.0)
val stepDataStraight = StepData("", "", 0.0, Maneuver.TYPE_STRAIGHT, 0, 0L, 0.0)
assertEquals(LaneDirection.SHAPE_STRAIGHT, iconMapper.addLanes("left_straight", stepDataStraight))
assertEquals(LaneDirection.SHAPE_STRAIGHT, iconMapper.addLanes("straight", stepDataStraight))
assertEquals(LaneDirection.SHAPE_STRAIGHT, iconMapper.addLanes("right_straight", stepDataStraight))
val stepDataKeepLeft = StepData("", 0.0, Maneuver.TYPE_KEEP_LEFT, 0, 0L, 0.0)
val stepDataKeepLeft = StepData("", "", 0.0, Maneuver.TYPE_KEEP_LEFT, 0, 0L, 0.0)
assertEquals(LaneDirection.SHAPE_STRAIGHT, iconMapper.addLanes("straight", stepDataKeepLeft))
assertEquals(LaneDirection.SHAPE_SLIGHT_LEFT, iconMapper.addLanes("left_slight", stepDataKeepLeft))
val stepDataKeepRight = StepData("", 0.0, Maneuver.TYPE_KEEP_RIGHT, 0, 0L, 0.0)
val stepDataKeepRight = StepData("", "", 0.0, Maneuver.TYPE_KEEP_RIGHT, 0, 0L, 0.0)
assertEquals(LaneDirection.SHAPE_STRAIGHT, iconMapper.addLanes("straight", stepDataKeepRight))
val stepDataNormalRight = StepData("", 0.0, Maneuver.TYPE_TURN_NORMAL_RIGHT, 0, 0L, 0.0)
val stepDataNormalRight = StepData("", "", 0.0, Maneuver.TYPE_TURN_NORMAL_RIGHT, 0, 0L, 0.0)
assertEquals(LaneDirection.SHAPE_NORMAL_RIGHT, iconMapper.addLanes("right", stepDataNormalRight))
assertEquals(LaneDirection.SHAPE_NORMAL_RIGHT, iconMapper.addLanes("right_straight", stepDataNormalRight))
val stepDataSlightRight = StepData("", 0.0, Maneuver.TYPE_TURN_SLIGHT_RIGHT, 0, 0L, 0.0)
val stepDataSlightRight = StepData("", "", 0.0, Maneuver.TYPE_TURN_SLIGHT_RIGHT, 0, 0L, 0.0)
assertEquals(LaneDirection.SHAPE_NORMAL_RIGHT, iconMapper.addLanes("right_slight", stepDataSlightRight))
assertEquals(LaneDirection.SHAPE_NORMAL_RIGHT, iconMapper.addLanes("slight_right", stepDataSlightRight))
val stepDataUnknown = StepData("", 0.0, Maneuver.TYPE_UNKNOWN, 0, 0L, 0.0)
val stepDataUnknown = StepData("", "", 0.0, Maneuver.TYPE_UNKNOWN, 0, 0L, 0.0)
assertEquals(LaneDirection.SHAPE_UNKNOWN, iconMapper.addLanes("left_straight", stepDataUnknown))
assertEquals(LaneDirection.SHAPE_UNKNOWN, iconMapper.addLanes("left", stepDataUnknown))
assertEquals(LaneDirection.SHAPE_UNKNOWN, iconMapper.addLanes("straight", stepDataUnknown))
@@ -74,24 +74,24 @@ class IconMapperTest {
@Test
fun `laneToResource returns correct resource string`() {
val stepDataNormalLeft = StepData("", 0.0, Maneuver.TYPE_TURN_NORMAL_LEFT, 0, 0L, 0.0)
val stepDataNormalLeft = StepData("", "", 0.0, Maneuver.TYPE_TURN_NORMAL_LEFT, 0, 0L, 0.0)
assertEquals("left_o_straight_x", iconMapper.laneToResource(listOf("left", "straight"), stepDataNormalLeft))
assertEquals("left_o", iconMapper.laneToResource(listOf("left"), stepDataNormalLeft))
assertEquals("slight_left_o", iconMapper.laneToResource(listOf("slight_left"), stepDataNormalLeft))
val stepDataStraight = StepData("", 0.0, Maneuver.TYPE_STRAIGHT, 0, 0L, 0.0)
val stepDataStraight = StepData("", "", 0.0, Maneuver.TYPE_STRAIGHT, 0, 0L, 0.0)
assertEquals("left_x_straight_o", iconMapper.laneToResource(listOf("left", "straight"), stepDataStraight))
assertEquals("straight_o", iconMapper.laneToResource(listOf("straight"), stepDataStraight))
assertEquals("right_x_straight_o", iconMapper.laneToResource(listOf("right_straight"), stepDataStraight))
val stepDataNormalRight = StepData("", 0.0, Maneuver.TYPE_TURN_NORMAL_RIGHT, 0, 0L, 0.0)
val stepDataNormalRight = StepData("", "", 0.0, Maneuver.TYPE_TURN_NORMAL_RIGHT, 0, 0L, 0.0)
assertEquals("right_x_straight_x", iconMapper.laneToResource(listOf("right_straight"), stepDataNormalRight))
assertEquals("right_o", iconMapper.laneToResource(listOf("right"), stepDataNormalRight))
val stepDataSlightRight = StepData("", 0.0, Maneuver.TYPE_TURN_SLIGHT_RIGHT, 0, 0L, 0.0)
val stepDataSlightRight = StepData("", "", 0.0, Maneuver.TYPE_TURN_SLIGHT_RIGHT, 0, 0L, 0.0)
assertEquals("right_o_straight_o", iconMapper.laneToResource(listOf("right_straight"), stepDataSlightRight))
val stepDataUnknown = StepData("", 0.0, Maneuver.TYPE_UNKNOWN, 0, 0L, 0.0)
val stepDataUnknown = StepData("", "", 0.0, Maneuver.TYPE_UNKNOWN, 0, 0L, 0.0)
assertEquals("left_x_straight_x", iconMapper.laneToResource(listOf("left", "straight"), stepDataUnknown))
assertEquals("", iconMapper.laneToResource(listOf("invalid"), stepDataUnknown))
}