Testing, Remove ObjectBox
This commit is contained in:
@@ -2,9 +2,9 @@ package com.kouros.navigation.data
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val NavigationColor = Color(0xFF0730B2)
|
||||
val NavigationColor = Color(0xFF16BBB6)
|
||||
|
||||
val RouteColor = Color(0xFF5582D0)
|
||||
val RouteColor = Color(0xFF7B06E1)
|
||||
|
||||
val SpeedColor = Color(0xFF262525)
|
||||
|
||||
|
||||
@@ -16,13 +16,9 @@
|
||||
|
||||
package com.kouros.navigation.data
|
||||
|
||||
import android.location.Location
|
||||
import android.location.LocationManager
|
||||
import android.net.Uri
|
||||
import com.kouros.navigation.data.route.Lane
|
||||
import com.kouros.navigation.utils.location
|
||||
import io.objectbox.annotation.Entity
|
||||
import io.objectbox.annotation.Id
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
data class Category(
|
||||
@@ -30,9 +26,13 @@ data class Category(
|
||||
val name: String,
|
||||
)
|
||||
|
||||
@Entity
|
||||
|
||||
data class Places(
|
||||
val places: List<Place>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Place(
|
||||
@Id
|
||||
var id: Long = 0,
|
||||
var name: String? = null,
|
||||
var category: String? = null,
|
||||
@@ -42,8 +42,7 @@ data class Place(
|
||||
var city: String? = null,
|
||||
var street: String? = null,
|
||||
var distance: Float = 0F,
|
||||
@Transient
|
||||
var avatar: Uri? = null,
|
||||
//var avatar: Uri? = null,
|
||||
var lastDate: Long = 0
|
||||
)
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ abstract class NavigationRepository {
|
||||
carOrientation: Float,
|
||||
context: Context
|
||||
): Double {
|
||||
if (currentLocation.latitude == 0.0)
|
||||
return 0.0
|
||||
val osrm = OsrmRepository()
|
||||
val route = osrm.getRoute(context, currentLocation, location, carOrientation, SearchFilter())
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
|
||||
@@ -18,4 +18,6 @@ data class NavigationState (
|
||||
val currentRouteIndex: Int = 0,
|
||||
val destination: Place = Place(),
|
||||
val carConnection: Int = 0,
|
||||
var routingEngine: Int = 0,
|
||||
|
||||
)
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.kouros.navigation.data
|
||||
|
||||
import android.content.Context
|
||||
import com.kouros.navigation.data.MyObjectBox
|
||||
import io.objectbox.BoxStore
|
||||
|
||||
/**
|
||||
* Singleton to keep BoxStore reference.
|
||||
*/
|
||||
object ObjectBox {
|
||||
|
||||
lateinit var boxStore: BoxStore
|
||||
private set
|
||||
|
||||
fun init(context: Context) {
|
||||
try {
|
||||
boxStore = MyObjectBox.builder().androidContext(context.applicationContext).build()
|
||||
} catch (e: Exception) {
|
||||
println(e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,11 @@ class DataStoreManager(private val context: Context) {
|
||||
val LAST_ROUTE = stringPreferencesKey("LastRoute")
|
||||
|
||||
val TOMTOM_APIKEY = stringPreferencesKey("TomTomApiKey")
|
||||
|
||||
val RECENT_PLACES = stringPreferencesKey("RecentPlaces")
|
||||
|
||||
val FAVORITES = stringPreferencesKey("Favorites")
|
||||
|
||||
}
|
||||
|
||||
// Read values
|
||||
@@ -89,6 +94,18 @@ class DataStoreManager(private val context: Context) {
|
||||
?: ""
|
||||
}
|
||||
|
||||
val recentPlacesFlow: Flow<String> =
|
||||
context.dataStore.data.map { preferences ->
|
||||
preferences[PreferencesKeys.RECENT_PLACES]
|
||||
?: ""
|
||||
}
|
||||
|
||||
val favoritesFlow: Flow<String> =
|
||||
context.dataStore.data.map { preferences ->
|
||||
preferences[PreferencesKeys.FAVORITES]
|
||||
?: ""
|
||||
}
|
||||
|
||||
// Save values
|
||||
suspend fun setShow3D(enabled: Boolean) {
|
||||
context.dataStore.edit { preferences ->
|
||||
@@ -137,4 +154,16 @@ class DataStoreManager(private val context: Context) {
|
||||
prefs[PreferencesKeys.TOMTOM_APIKEY] = apiKey
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun setRecentPlaces(apiKey: String) {
|
||||
context.dataStore.edit { prefs ->
|
||||
prefs[PreferencesKeys.RECENT_PLACES] = apiKey
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun setFavorites(apiKey: String) {
|
||||
context.dataStore.edit { prefs ->
|
||||
prefs[PreferencesKeys.FAVORITES] = apiKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,13 @@ class TomTomRepository : NavigationRepository() {
|
||||
val routeJsonString = routeJson.bufferedReader().use { it.readText() }
|
||||
return routeJsonString
|
||||
}
|
||||
var filter = ""
|
||||
if (searchFilter.avoidMotorway) {
|
||||
filter = "$filter&avoid=motorways"
|
||||
}
|
||||
if (searchFilter.avoidTollway) {
|
||||
filter = "$filter&avoid=tollRoads"
|
||||
}
|
||||
val repository = getSettingsRepository(context)
|
||||
val tomtomApiKey = runBlocking { repository.tomTomApiKeyFlow.first() }
|
||||
val url =
|
||||
@@ -42,7 +49,7 @@ class TomTomRepository : NavigationRepository() {
|
||||
"&vehicleMaxSpeed=120&vehicleCommercial=false" +
|
||||
"&instructionsType=text&language=en-GB§ionType=lanes" +
|
||||
"&routeRepresentation=encodedPolyline" +
|
||||
"&vehicleEngineType=combustion&key=$tomtomApiKey"
|
||||
"&vehicleEngineType=combustion$filter&key=$tomtomApiKey"
|
||||
return fetchUrl(
|
||||
url,
|
||||
false
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
package com.kouros.navigation.model
|
||||
|
||||
//import com.kouros.navigation.data.Preferences.boxStore
|
||||
import android.content.Context
|
||||
import android.location.Location
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.ObjectBox.boxStore
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.Place_
|
||||
import com.kouros.navigation.data.Places
|
||||
import com.kouros.navigation.data.SearchFilter
|
||||
import com.kouros.navigation.data.nominatim.Search
|
||||
import com.kouros.navigation.data.nominatim.SearchResult
|
||||
import com.kouros.navigation.data.overpass.Elements
|
||||
import com.kouros.navigation.data.overpass.Overpass
|
||||
import com.kouros.navigation.utils.Levenshtein
|
||||
import com.kouros.navigation.utils.NavigationUtils
|
||||
import com.kouros.navigation.utils.getSettingsRepository
|
||||
import com.kouros.navigation.utils.getSettingsViewModel
|
||||
import com.kouros.navigation.utils.location
|
||||
import io.objectbox.kotlin.boxFor
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -111,20 +108,18 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
||||
|
||||
|
||||
/**
|
||||
* Loads the most recent place from ObjectBox and calculates its distance.
|
||||
* Loads the most recent place from Preferences and calculates its distance.
|
||||
* Posts the result to recentPlace LiveData if distance > 1km.
|
||||
*/
|
||||
fun loadRecentPlace(location: Location, carOrientation: Float, context: Context) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
val query = placeBox
|
||||
.query(Place_.name.notEqual(""))
|
||||
.orderDesc(Place_.lastDate)
|
||||
.build()
|
||||
val results = query.find()
|
||||
query.close()
|
||||
for (place in results) {
|
||||
val settingsRepository = getSettingsRepository(context)
|
||||
val recentPlaces = settingsRepository.recentPlacesFlow.first()
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
val places = gson.fromJson(recentPlaces, Places::class.java)
|
||||
val place = places.places.minByOrNull { it.lastDate.dec() }
|
||||
if (place != null) {
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
val distance = repository.getRouteDistance(
|
||||
location,
|
||||
@@ -145,33 +140,39 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all recent places from ObjectBox and calculates distances.
|
||||
* Loads all recent places from Preferences and calculates distances.
|
||||
* Posts the sorted list to places LiveData.
|
||||
*/
|
||||
fun loadRecentPlaces(context: Context, location: Location, carOrientation: Float) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
val query = placeBox
|
||||
.query(Place_.name.notEqual("").and(Place_.category.equal(Constants.RECENT)))
|
||||
.orderDesc(Place_.lastDate)
|
||||
.build()
|
||||
val results = query.find()
|
||||
query.close()
|
||||
for (place in results) {
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
if (place.latitude != 0.0) {
|
||||
val distance =
|
||||
repository.getRouteDistance(
|
||||
location,
|
||||
plLocation,
|
||||
carOrientation,
|
||||
context
|
||||
)
|
||||
place.distance = distance.toFloat()
|
||||
val settingsRepository = getSettingsRepository(context)
|
||||
val rp = settingsRepository.recentPlacesFlow.first()
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
val recentPlaces = gson.fromJson(rp, Places::class.java)
|
||||
val pl = mutableListOf<Place>()
|
||||
var id : Long = 0
|
||||
if (rp.isNotEmpty()) {
|
||||
for (place in recentPlaces.places) {
|
||||
if (place.category.equals(Constants.RECENT)) {
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
if (place.latitude != 0.0) {
|
||||
val distance =
|
||||
repository.getRouteDistance(
|
||||
location,
|
||||
plLocation,
|
||||
carOrientation,
|
||||
context
|
||||
)
|
||||
place.distance = distance.toFloat()
|
||||
place.id = id
|
||||
id += 1
|
||||
}
|
||||
pl.add(place)
|
||||
}
|
||||
}
|
||||
}
|
||||
places.postValue(results)
|
||||
places.postValue(pl)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
@@ -179,32 +180,36 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads favorite places from ObjectBox and calculates distances.
|
||||
* Loads favorite places from Preferences and calculates distances.
|
||||
* Posts the sorted list to favorites LiveData.
|
||||
*/
|
||||
fun loadFavorites(context: Context, location: Location, carOrientation: Float) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
val query = placeBox
|
||||
.query(Place_.name.notEqual("").and(Place_.category.equal(Constants.FAVORITES)))
|
||||
.orderDesc(Place_.lastDate)
|
||||
.build()
|
||||
val results = query.find()
|
||||
query.close()
|
||||
for (place in results) {
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
val distance =
|
||||
repository.getRouteDistance(
|
||||
location,
|
||||
plLocation,
|
||||
carOrientation,
|
||||
|
||||
context
|
||||
)
|
||||
place.distance = distance.toFloat()
|
||||
val settingsRepository = getSettingsRepository(context)
|
||||
val rp = settingsRepository.recentPlacesFlow.first()
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
val recentPlaces = gson.fromJson(rp, Places::class.java)
|
||||
val pl = mutableListOf<Place>()
|
||||
if (rp.isNotEmpty()) {
|
||||
for (place in recentPlaces.places) {
|
||||
if (place.category.equals(Constants.FAVORITES)) {
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
if (place.latitude != 0.0) {
|
||||
val distance =
|
||||
repository.getRouteDistance(
|
||||
location,
|
||||
plLocation,
|
||||
carOrientation,
|
||||
context
|
||||
)
|
||||
place.distance = distance.toFloat()
|
||||
}
|
||||
pl.add(place)
|
||||
}
|
||||
}
|
||||
}
|
||||
favorites.postValue(results)
|
||||
favorites.postValue(pl)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
@@ -335,7 +340,7 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
||||
Constants.CONTACTS,
|
||||
street = addressLines[0],
|
||||
city = addressLines[1],
|
||||
avatar = address.avatar,
|
||||
//avatar = address.avatar,
|
||||
longitude = 0.0,
|
||||
latitude = 0.0,
|
||||
distance = 0F,
|
||||
@@ -417,7 +422,7 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
||||
val distAmenities = mutableListOf<Elements>()
|
||||
amenities.forEach {
|
||||
val plLocation =
|
||||
location(longitude = it.lon!!, latitude = it.lat!!)
|
||||
location(longitude = it.lon, latitude = it.lat)
|
||||
val distance = plLocation.distanceTo(location)
|
||||
it.distance = distance.toDouble()
|
||||
distAmenities.add(it)
|
||||
@@ -470,18 +475,18 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a place as a favorite in ObjectBox.
|
||||
* Saves a place as a favorite in Preferences.
|
||||
*/
|
||||
fun saveFavorite(place: Place) {
|
||||
fun saveFavorite(context: Context, place: Place) {
|
||||
place.category = Constants.FAVORITES
|
||||
savePlace(place)
|
||||
savePlace(context, place)
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a place to recent destinations in ObjectBox.
|
||||
* Saves a place to recent destinations in Preferences.
|
||||
* Skips fuel stations, charging stations, and pharmacies.
|
||||
*/
|
||||
fun saveRecent(place: Place) {
|
||||
fun saveRecent(context: Context, place: Place) {
|
||||
if (place.category == Constants.FUEL_STATION
|
||||
|| place.category == Constants.CHARGING_STATION
|
||||
|| place.category == Constants.PHARMACY
|
||||
@@ -489,30 +494,36 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
||||
return
|
||||
}
|
||||
place.category = Constants.RECENT
|
||||
savePlace(place)
|
||||
savePlace(context, place)
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a place to ObjectBox, removing existing duplicates first.
|
||||
* Saves a place to Preferences, removing existing duplicates first.
|
||||
* Updates the timestamp to current time.
|
||||
*/
|
||||
private fun savePlace(place: Place) {
|
||||
private fun savePlace(context: Context, place: Place) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
val query = placeBox
|
||||
.query(
|
||||
Place_.name.equal(place.name!!).and(Place_.category.equal(place.category!!))
|
||||
)
|
||||
.build()
|
||||
val results = query.find()
|
||||
query.close()
|
||||
if (results.isNotEmpty()) {
|
||||
placeBox.remove(results.first())
|
||||
val places = mutableListOf<Place>()
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
val settingsRepository = getSettingsRepository(context)
|
||||
val rp = settingsRepository.recentPlacesFlow.first()
|
||||
var id : Long = 0
|
||||
if (rp.isNotEmpty()) {
|
||||
val recentPlaces =
|
||||
gson.fromJson(rp, Places::class.java).places.sortedBy { it.lastDate }
|
||||
for (curPlace in recentPlaces) {
|
||||
if (curPlace.name != place.name || curPlace.category != place.category) {
|
||||
curPlace.id = id
|
||||
places.add(curPlace)
|
||||
id += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
val current = LocalDateTime.now(ZoneOffset.UTC)
|
||||
place.lastDate = current.atZone(ZoneOffset.UTC).toEpochSecond()
|
||||
placeBox.put(place)
|
||||
places.add(place)
|
||||
settingsRepository.setRecentPlaces(gson.toJson(Places(places)))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
@@ -520,37 +531,40 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a place from favorites in ObjectBox.
|
||||
* Deletes a place from favorites in Preferences.
|
||||
*/
|
||||
fun deleteFavorite(place: Place) {
|
||||
fun deleteFavorite(context: Context, place: Place) {
|
||||
place.category = Constants.FAVORITES
|
||||
deletePlace(place)
|
||||
deletePlace(context, place)
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a place from recent destinations in ObjectBox.
|
||||
* Deletes a place from recent destinations in Preferences.
|
||||
*/
|
||||
fun deleteRecent(place: Place) {
|
||||
fun deleteRecent(context: Context, place: Place) {
|
||||
place.category = Constants.RECENT
|
||||
deletePlace(place)
|
||||
deletePlace(context, place)
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a place from ObjectBox matching name and category.
|
||||
* Deletes a place from Preferences matching name and category.
|
||||
*/
|
||||
fun deletePlace(place: Place) {
|
||||
fun deletePlace(context: Context, place: Place) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
val query = placeBox
|
||||
.query(
|
||||
Place_.name.equal(place.name!!).and(Place_.category.equal(place.category!!))
|
||||
)
|
||||
.build()
|
||||
val results = query.find()
|
||||
query.close()
|
||||
if (results.isNotEmpty()) {
|
||||
placeBox.remove(results.first())
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
val settingsRepository = getSettingsRepository(context)
|
||||
val rp = settingsRepository.recentPlacesFlow.first()
|
||||
val places = mutableListOf<Place>()
|
||||
if (rp.isNotEmpty()) {
|
||||
val recentPlaces =
|
||||
gson.fromJson(rp, Places::class.java).places.sortedBy { it.lastDate }
|
||||
for (curPlace in recentPlaces) {
|
||||
if (curPlace.name != place.name || curPlace.category != place.category) {
|
||||
places.add(curPlace)
|
||||
}
|
||||
}
|
||||
settingsRepository.setRecentPlaces(gson.toJson(Places(places)))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
@@ -569,59 +583,23 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
||||
return SearchFilter(avoidMotorway, avoidTollway)
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads recent places with calculated distances for Compose state.
|
||||
* @return SnapshotStateList of recent places with distances
|
||||
*/
|
||||
fun loadPlaces2(
|
||||
context: Context,
|
||||
location: Location,
|
||||
carOrientation: Float
|
||||
): SnapshotStateList<Place?> {
|
||||
val results = listOf<Place>()
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
val query = placeBox
|
||||
.query(Place_.name.notEqual("").and(Place_.category.equal(Constants.RECENT)))
|
||||
.orderDesc(Place_.lastDate)
|
||||
.build()
|
||||
val results = query.find()
|
||||
query.close()
|
||||
for (place in results) {
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
val distance =
|
||||
repository.getRouteDistance(
|
||||
location,
|
||||
plLocation,
|
||||
carOrientation,
|
||||
context
|
||||
)
|
||||
place.distance = distance.toFloat()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return results.toMutableStateList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads recent places as Compose SnapshotStateList.
|
||||
* @return SnapshotStateList of recent places
|
||||
*/
|
||||
fun loadRecentPlace(): SnapshotStateList<Place?> {
|
||||
val results = listOf<Place>()
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
val query = placeBox
|
||||
.query(Place_.name.notEqual("").and(Place_.category.equal(Constants.RECENT)))
|
||||
.orderDesc(Place_.lastDate)
|
||||
.build()
|
||||
val results = query.find()
|
||||
query.close()
|
||||
return results.toMutableStateList()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
fun loadRecentPlace(context: Context): SnapshotStateList<Place?> {
|
||||
val pl = mutableListOf<Place>()
|
||||
val settingsRepository = getSettingsRepository(context)
|
||||
val rp = runBlocking { settingsRepository.recentPlacesFlow.first()}
|
||||
if (rp.isNotEmpty()) {
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
val recentPlaces = gson.fromJson(rp, Places::class.java).places.sortedBy { it.lastDate }
|
||||
for (place in recentPlaces) {
|
||||
if (place.category == Constants.RECENT) {
|
||||
pl.add(place)
|
||||
}
|
||||
}
|
||||
}
|
||||
return results.toMutableStateList()
|
||||
return pl.toMutableStateList()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,17 @@
|
||||
package com.kouros.navigation.model
|
||||
|
||||
import android.content.Context
|
||||
import android.location.Location
|
||||
import androidx.car.app.connection.CarConnection.CONNECTION_TYPE_NATIVE
|
||||
import androidx.car.app.connection.CarConnection.CONNECTION_TYPE_PROJECTION
|
||||
import androidx.car.app.navigation.model.Maneuver
|
||||
import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD
|
||||
import com.kouros.navigation.data.NavigationState
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.Route
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.data.datastore.DataStoreManager
|
||||
import com.kouros.navigation.data.route.Lane
|
||||
import com.kouros.navigation.data.route.Leg
|
||||
import com.kouros.navigation.data.route.Routes
|
||||
import com.kouros.navigation.repository.SettingsRepository
|
||||
import com.kouros.navigation.utils.getSettingsRepository
|
||||
import com.kouros.navigation.utils.getSettingsViewModel
|
||||
import com.kouros.navigation.utils.location
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
open class RouteModel {
|
||||
@@ -37,40 +29,40 @@ open class RouteModel {
|
||||
val curLeg: Leg
|
||||
get() = navState.route.routes[navState.currentRouteIndex].legs.first()
|
||||
|
||||
fun startNavigation(routeString: String, context: Context) {
|
||||
val repository = getSettingsRepository(context)
|
||||
val routingEngine = runBlocking { repository.routingEngineFlow.first() }
|
||||
fun startNavigation(routeString: String) {
|
||||
navState = navState.copy(
|
||||
route = Route.Builder()
|
||||
.routeEngine(routingEngine)
|
||||
.routeEngine(navState.routingEngine)
|
||||
.route(routeString)
|
||||
.build()
|
||||
)
|
||||
if (hasLegs()) {
|
||||
navState = navState.copy(navigating = true)
|
||||
getSettingsViewModel(context).onLastRouteChanged(routeString)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasLegs(): Boolean {
|
||||
fun hasLegs(): Boolean {
|
||||
return navState.route.routes.isNotEmpty() && navState.route.routes[0].legs.isNotEmpty()
|
||||
}
|
||||
|
||||
fun stopNavigation(context: Context) {
|
||||
fun stopNavigation() {
|
||||
navState = navState.copy(
|
||||
route = Route.Builder().buildEmpty(),
|
||||
navigating = false,
|
||||
arrived = false,
|
||||
maneuverType = Maneuver.TYPE_UNKNOWN
|
||||
)
|
||||
getSettingsViewModel(context).onLastRouteChanged("")
|
||||
}
|
||||
|
||||
fun updateLocation(context: Context, curLocation: Location, viewModel: NavigationViewModel) {
|
||||
fun updateLocation(curLocation: Location, viewModel: NavigationViewModel) {
|
||||
if (curLocation.hasBearing()) {
|
||||
navState = navState.copy(routeBearing = curLocation.bearing)
|
||||
}
|
||||
navState = navState.copy(currentLocation = curLocation)
|
||||
routeCalculator.findStep(curLocation)
|
||||
if (navState.carConnection == CONNECTION_TYPE_PROJECTION
|
||||
|| navState.carConnection == CONNECTION_TYPE_NATIVE) {
|
||||
|| navState.carConnection == CONNECTION_TYPE_NATIVE
|
||||
) {
|
||||
routeCalculator.updateSpeedLimit(curLocation, viewModel)
|
||||
}
|
||||
navState = navState.copy(lastLocation = navState.currentLocation)
|
||||
@@ -80,15 +72,11 @@ open class RouteModel {
|
||||
val distanceToNextStep = routeCalculator.leftStepDistance()
|
||||
// Determine the maneuver type and corresponding icon
|
||||
val currentStep = navState.route.nextStep(0)
|
||||
val streetName = if (distanceToNextStep > NEXT_STEP_THRESHOLD) {
|
||||
currentStep.street
|
||||
} else {
|
||||
currentStep.maneuver.street
|
||||
}
|
||||
val curManeuverType = if (distanceToNextStep > NEXT_STEP_THRESHOLD) {
|
||||
Maneuver.TYPE_STRAIGHT
|
||||
} else {
|
||||
currentStep.maneuver.type
|
||||
var streetName = currentStep.maneuver.street
|
||||
var curManeuverType = currentStep.maneuver.type
|
||||
if (distanceToNextStep > NEXT_STEP_THRESHOLD) {
|
||||
streetName = currentStep.street
|
||||
curManeuverType = Maneuver.TYPE_STRAIGHT
|
||||
}
|
||||
val exitNumber = currentStep.maneuver.exit
|
||||
val maneuverIcon = navState.iconMapper.maneuverIcon(curManeuverType)
|
||||
@@ -108,13 +96,14 @@ open class RouteModel {
|
||||
|
||||
fun nextStep(): StepData {
|
||||
val distanceToNextStep = routeCalculator.leftStepDistance()
|
||||
val step = navState.route.nextStep(1)
|
||||
val streetName = if (distanceToNextStep < NEXT_STEP_THRESHOLD) {
|
||||
step.maneuver.street
|
||||
} else {
|
||||
step.street
|
||||
val currentStep = navState.route.nextStep(0)
|
||||
val nextStep = navState.route.nextStep(1)
|
||||
var streetName = nextStep.street
|
||||
var maneuverType = currentStep.maneuver.type
|
||||
if (distanceToNextStep < NEXT_STEP_THRESHOLD) {
|
||||
streetName = nextStep.maneuver.street
|
||||
maneuverType = nextStep.maneuver.type
|
||||
}
|
||||
val maneuverType = step.maneuver.type
|
||||
|
||||
val maneuverIcon = navState.iconMapper.maneuverIcon(maneuverType)
|
||||
// Construct and return the final StepData object
|
||||
@@ -125,7 +114,7 @@ open class RouteModel {
|
||||
icon = maneuverIcon,
|
||||
arrivalTime = routeCalculator.arrivalTime(),
|
||||
leftDistance = routeCalculator.travelLeftDistance(),
|
||||
exitNumber = step.maneuver.exit
|
||||
exitNumber = nextStep.maneuver.exit
|
||||
)
|
||||
}
|
||||
|
||||
@@ -138,7 +127,9 @@ open class RouteModel {
|
||||
navState.lastLocation.distanceTo(location(it.location[0], it.location[1]))
|
||||
val sectionBearing =
|
||||
navState.lastLocation.bearingTo(location(it.location[0], it.location[1]))
|
||||
if (distance < NEXT_STEP_THRESHOLD && (navState.routeBearing.absoluteValue - sectionBearing.absoluteValue).absoluteValue < 10) {
|
||||
val bearingDeviation =
|
||||
(navState.routeBearing.absoluteValue - sectionBearing.absoluteValue).absoluteValue
|
||||
if (distance < NEXT_STEP_THRESHOLD && bearingDeviation < 10) {
|
||||
lanes = it.lane
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,14 @@ class SettingsRepository(
|
||||
val tomTomApiKeyFlow: Flow<String> =
|
||||
dataStoreManager.tomTomApiKeyFlow
|
||||
|
||||
|
||||
val recentPlacesFlow: Flow<String> =
|
||||
dataStoreManager.recentPlacesFlow
|
||||
|
||||
val favoritesFlow: Flow<String> =
|
||||
dataStoreManager.favoritesFlow
|
||||
|
||||
|
||||
suspend fun setShow3D(enabled: Boolean) {
|
||||
dataStoreManager.setShow3D(enabled)
|
||||
}
|
||||
@@ -61,4 +69,11 @@ class SettingsRepository(
|
||||
dataStoreManager.setTomtomApiKey(apiKey)
|
||||
}
|
||||
|
||||
suspend fun setRecentPlaces(places: String) {
|
||||
dataStoreManager.setRecentPlaces(places)
|
||||
}
|
||||
|
||||
suspend fun setFavorites(favorites: String) {
|
||||
dataStoreManager.setFavorites(favorites)
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,6 @@ object GeoUtils {
|
||||
|
||||
fun decodePolyline(encoded: String, precision: Int = 6): List<List<Double>> {
|
||||
val factor = 10.0.pow(precision)
|
||||
|
||||
var lat = 0
|
||||
var lng = 0
|
||||
val coordinates = mutableListOf<List<Double>>()
|
||||
|
||||
Reference in New Issue
Block a user