App DrawItem and Search
This commit is contained in:
@@ -151,8 +151,8 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
updateLocation(location)
|
||||
locationManager.requestLocationUpdates(
|
||||
LocationManager.GPS_PROVIDER,
|
||||
/* minTimeMs= */ 500,
|
||||
/* minDistanceM= */ 0f,
|
||||
/* minTimeMs= */ 1000,
|
||||
/* minDistanceM= */ 5f,
|
||||
mLocationListener
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.Lifecycle
|
||||
@@ -25,6 +27,11 @@ import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.setViewTreeLifecycleOwner
|
||||
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
||||
import com.kouros.navigation.car.map.BuildingLayer
|
||||
import com.kouros.navigation.car.map.DrawImage
|
||||
import com.kouros.navigation.car.map.RouteLayer
|
||||
import com.kouros.navigation.car.map.cameraState
|
||||
import com.kouros.navigation.car.map.getPaddingValues
|
||||
import com.kouros.navigation.car.navigation.RouteCarModel
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING
|
||||
@@ -33,9 +40,12 @@ import com.kouros.navigation.model.RouteModel
|
||||
import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue
|
||||
import com.kouros.navigation.utils.bearing
|
||||
import com.kouros.navigation.utils.calculateZoom
|
||||
import com.kouros.navigation.utils.previewZoom
|
||||
import org.maplibre.compose.camera.CameraPosition
|
||||
import org.maplibre.compose.camera.CameraState
|
||||
import org.maplibre.compose.map.MapOptions
|
||||
import org.maplibre.compose.map.MaplibreMap
|
||||
import org.maplibre.compose.map.OrnamentOptions
|
||||
import org.maplibre.compose.sources.getBaseSource
|
||||
import org.maplibre.compose.style.BaseStyle
|
||||
import org.maplibre.spatialk.geojson.Position
|
||||
@@ -77,7 +87,7 @@ class SurfaceRenderer(
|
||||
lateinit var mapView: ComposeView
|
||||
|
||||
var panView = false
|
||||
val tilt = 55.0
|
||||
var tilt = 55.0
|
||||
|
||||
var previewDistance = 0.0
|
||||
val mSurfaceCallback: SurfaceCallback = object : SurfaceCallback {
|
||||
@@ -164,11 +174,12 @@ class SurfaceRenderer(
|
||||
}
|
||||
|
||||
fun onConnectionStateUpdated(connectionState: Int) {
|
||||
when(connectionState) {
|
||||
when (connectionState) {
|
||||
CarConnection.CONNECTION_TYPE_NATIVE -> ObjectBox.init(carContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun MapView() {
|
||||
val stateWidth = visibleArea.observeAsState()
|
||||
@@ -178,21 +189,29 @@ class SurfaceRenderer(
|
||||
val paddingValues = getPaddingValues(width - stateWidth.value!!.width(), height, preview)
|
||||
val cameraState = cameraState(paddingValues, position, tilt)
|
||||
|
||||
val baseStyle =if (isSystemInDarkTheme()) BaseStyle.Uri(Constants.STYLE_DARK) else BaseStyle.Uri(
|
||||
Constants.STYLE
|
||||
)
|
||||
MaplibreMap(
|
||||
cameraState = cameraState,
|
||||
baseStyle = baseStyle,
|
||||
) {
|
||||
getBaseSource(id = "openmaptiles")?.let { tiles ->
|
||||
if (!getBooleanKeyValue(context = carContext, SHOW_THREED_BUILDING)) {
|
||||
BuildingLayer(tiles)
|
||||
}
|
||||
RouteLayer(route, previewRoute)
|
||||
}
|
||||
//Puck(cameraState, lastLocation)
|
||||
val baseStyle = remember {
|
||||
mutableStateOf(BaseStyle.Uri(Constants.STYLE))
|
||||
}
|
||||
baseStyle.value =
|
||||
(if (isSystemInDarkTheme()) BaseStyle.Uri(Constants.STYLE_DARK) else BaseStyle.Uri(
|
||||
Constants.STYLE
|
||||
))
|
||||
|
||||
MaplibreMap(
|
||||
options = MapOptions(
|
||||
ornamentOptions =
|
||||
OrnamentOptions(isScaleBarEnabled = false)),
|
||||
cameraState = cameraState,
|
||||
baseStyle = baseStyle.value
|
||||
) {
|
||||
getBaseSource(id = "openmaptiles")?.let { tiles ->
|
||||
if (!getBooleanKeyValue(context = carContext, SHOW_THREED_BUILDING)) {
|
||||
BuildingLayer(tiles)
|
||||
}
|
||||
RouteLayer(route, previewRoute, position!!.zoom)
|
||||
}
|
||||
//Puck(cameraState, lastLocation)
|
||||
}
|
||||
ShowPosition(cameraState, position, paddingValues)
|
||||
}
|
||||
|
||||
@@ -215,7 +234,7 @@ class SurfaceRenderer(
|
||||
}
|
||||
} else {
|
||||
bearing = 0.0
|
||||
zoom = previewZoom()
|
||||
zoom = previewZoom(previewDistance)
|
||||
target = Position(centerLocation.longitude, centerLocation.latitude)
|
||||
localTilt = 0.0
|
||||
}
|
||||
@@ -261,11 +280,19 @@ class SurfaceRenderer(
|
||||
} else {
|
||||
cameraPosition.value!!.zoom + 1.0
|
||||
}
|
||||
cameraPosition.postValue(
|
||||
cameraPosition.value!!.copy(
|
||||
zoom = newZoom,
|
||||
target = cameraPosition.value!!.target
|
||||
)
|
||||
tilt = if (newZoom < 13) {
|
||||
0.0
|
||||
} else {
|
||||
if (tilt == 0.0) {
|
||||
55.0
|
||||
} else {
|
||||
tilt
|
||||
}
|
||||
}
|
||||
updateCameraPosition(
|
||||
cameraPosition.value!!.bearing,
|
||||
newZoom,
|
||||
cameraPosition.value!!.target,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -273,7 +300,7 @@ class SurfaceRenderer(
|
||||
fun updateLocation(location: Location) {
|
||||
synchronized(this) {
|
||||
if (!preview) {
|
||||
val bearing = bearing(lastLocation, location)
|
||||
val bearing = bearing(lastLocation, location, cameraPosition.value!!.bearing)
|
||||
val zoom = if (!panView) {
|
||||
calculateZoom(location.speed.toDouble())
|
||||
} else {
|
||||
@@ -287,10 +314,9 @@ class SurfaceRenderer(
|
||||
lastBearing = cameraPosition.value!!.bearing
|
||||
lastLocation = location
|
||||
} else {
|
||||
val zoom = previewZoom()
|
||||
updateCameraPosition(
|
||||
0.0,
|
||||
zoom,
|
||||
previewZoom(previewDistance),
|
||||
Position(centerLocation.longitude, centerLocation.latitude)
|
||||
)
|
||||
}
|
||||
@@ -302,7 +328,7 @@ class SurfaceRenderer(
|
||||
cameraPosition.value!!.copy(
|
||||
bearing = bearing,
|
||||
zoom = zoom,
|
||||
tilt = 0.0,
|
||||
tilt = tilt,
|
||||
padding = getPaddingValues(width - visibleArea.value!!.width(), height, preview),
|
||||
target = target
|
||||
)
|
||||
@@ -323,28 +349,6 @@ class SurfaceRenderer(
|
||||
previewDistance = routeModel.route.distance
|
||||
}
|
||||
|
||||
|
||||
private fun previewZoom(): Double {
|
||||
when (previewDistance) {
|
||||
in 0.0..10.0 -> {
|
||||
return 13.0
|
||||
}
|
||||
|
||||
in 10.0..20.0 -> {
|
||||
return 11.0
|
||||
}
|
||||
|
||||
in 20.0..30.0 -> {
|
||||
return 10.0
|
||||
}
|
||||
}
|
||||
return 9.0
|
||||
}
|
||||
|
||||
fun setPreViewDistance(): Double {
|
||||
return previewDistance
|
||||
}
|
||||
|
||||
companion
|
||||
object {
|
||||
private const val TAG = "MapRenderer"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.kouros.navigation.car
|
||||
package com.kouros.navigation.car.map
|
||||
|
||||
import android.location.Location
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.kouros.navigation.car
|
||||
package com.kouros.navigation.car.map
|
||||
|
||||
import android.location.Location
|
||||
import androidx.compose.foundation.Canvas
|
||||
@@ -17,9 +17,8 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.drawscope.scale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.drawText
|
||||
import androidx.compose.ui.text.rememberTextMeasurer
|
||||
@@ -67,7 +66,8 @@ fun cameraState(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RouteLayer(routeData: String?, previewRoute: String?) {
|
||||
fun RouteLayer(routeData: String?, previewRoute: String?, zoom: Double) {
|
||||
val width = zoom - 2
|
||||
if (routeData!!.isNotEmpty()) {
|
||||
val routes =
|
||||
rememberGeoJsonSource(GeoJsonData.JsonString(routeData))
|
||||
@@ -75,13 +75,13 @@ fun RouteLayer(routeData: String?, previewRoute: String?) {
|
||||
id = "routes-casing",
|
||||
source = routes,
|
||||
color = const(Color.White),
|
||||
width = const(16.dp),
|
||||
width = const((width+2).dp),
|
||||
)
|
||||
LineLayer(
|
||||
id = "routes",
|
||||
source = routes,
|
||||
color = const(RouteColor),
|
||||
width = const(14.dp),
|
||||
width = const(width.dp),
|
||||
)
|
||||
}
|
||||
if (previewRoute!!.isNotEmpty()) {
|
||||
@@ -122,10 +122,7 @@ fun DrawImage(padding: PaddingValues, location: Location, width: Int, height: In
|
||||
|
||||
@Composable
|
||||
fun NavigationImage(padding: PaddingValues, width: Int, height: Int, street: String) {
|
||||
|
||||
val imageSize = (height/6)
|
||||
println("Image Size: $imageSize")
|
||||
val vector = ImageVector.vectorResource(id = R.drawable.assistant_navigation_48px)
|
||||
val color = remember { NavigationColor }
|
||||
BadgedBox(
|
||||
modifier = Modifier
|
||||
@@ -134,19 +131,18 @@ fun NavigationImage(padding: PaddingValues, width: Int, height: Int, street: Str
|
||||
Badge()
|
||||
}
|
||||
) {
|
||||
Canvas(modifier =Modifier
|
||||
.size(imageSize.dp, imageSize.dp)) {
|
||||
scale(scaleX = 1f, scaleY = 0.7f) {
|
||||
drawCircle(Color.DarkGray.copy(alpha = 0.2f))
|
||||
}
|
||||
}
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.navigation),
|
||||
"Navigation",
|
||||
tint = color,
|
||||
tint = color.copy(alpha = 1f),
|
||||
modifier = Modifier.size(imageSize.dp, imageSize.dp),
|
||||
)
|
||||
|
||||
// Icon(
|
||||
// modifier = Modifier.size(72.dp, 72.dp),
|
||||
// imageVector = vector,
|
||||
// contentDescription = "Navigation",
|
||||
// tint = color
|
||||
// )
|
||||
if (street.isNotEmpty())
|
||||
Text(text = street)
|
||||
}
|
||||
@@ -81,7 +81,7 @@ class RouteCarModel() : RouteModel() {
|
||||
val maneuverType = maneuver.type
|
||||
val routing = routingData(maneuverType, carContext)
|
||||
var text = ""
|
||||
val distanceLeft = leftStepDistance() * 1000
|
||||
val distanceLeft = leftStepDistance()
|
||||
|
||||
when (distanceLeft) {
|
||||
in 0.0..NEXT_STEP_THRESHOLD -> {
|
||||
@@ -178,7 +178,7 @@ class RouteCarModel() : RouteModel() {
|
||||
|| maneuverType == ManeuverType.DestinationLeft.value
|
||||
}
|
||||
|
||||
fun travelEstimate(carContext: CarContext): TravelEstimate {
|
||||
fun travelEstimate(): TravelEstimate {
|
||||
val timeLeft = travelLeftTime()
|
||||
// Calculate the time to destination from the current time.
|
||||
val nowUtcMillis = System.currentTimeMillis()
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.kouros.android.cars.carappservice.R
|
||||
import com.kouros.navigation.car.NavigationCarAppService
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
import com.kouros.navigation.car.navigation.RouteCarModel
|
||||
import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.model.ViewModel
|
||||
@@ -102,7 +103,7 @@ class NavigationScreen(
|
||||
.setNavigationInfo(
|
||||
getRoutingInfo()
|
||||
)
|
||||
.setDestinationTravelEstimate(routeModel.travelEstimate(carContext))
|
||||
.setDestinationTravelEstimate(routeModel.travelEstimate())
|
||||
.setActionStrip(actionStripBuilder.build())
|
||||
.setMapActionStrip(mapActionStripBuilder().build())
|
||||
.setBackgroundColor(CarColor.GREEN)
|
||||
@@ -182,27 +183,11 @@ class NavigationScreen(
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
fun navigationRerouteTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
|
||||
fun navigationRerouteTemplate(actionStripBuilder: ActionStrip.Builder): Template {
|
||||
return NavigationTemplate.Builder()
|
||||
.setNavigationInfo(
|
||||
MessageInfo.Builder(
|
||||
carContext.getString(R.string.new_route)
|
||||
)
|
||||
.setText(routeModel.destination.street.toString())
|
||||
.setImage(
|
||||
CarIcon.Builder(
|
||||
IconCompat.createWithResource(
|
||||
carContext,
|
||||
R.drawable.navigation_48px
|
||||
)
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.setBackgroundColor(CarColor.SECONDARY)
|
||||
.setNavigationInfo(RoutingInfo.Builder().setLoading(true).build())
|
||||
.setActionStrip(actionStripBuilder.build())
|
||||
.setMapActionStrip(mapActionStripBuilder().build())
|
||||
.setBackgroundColor(CarColor.GREEN)
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -447,8 +432,12 @@ class NavigationScreen(
|
||||
}
|
||||
|
||||
fun updateTrip(location: Location) {
|
||||
val start = System.currentTimeMillis()
|
||||
routeModel.updateLocation(location)
|
||||
if (routeModel.maneuverType == Maneuver.TYPE_DESTINATION && routeModel.leftStepDistance() * 1000 < 25.0) {
|
||||
val end = System.currentTimeMillis()
|
||||
println("Time ${end-start}")
|
||||
if (routeModel.maneuverType == Maneuver.TYPE_DESTINATION
|
||||
&& routeModel.leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE) {
|
||||
routeModel.arrived = true
|
||||
routeModel.stopNavigation()
|
||||
}
|
||||
|
||||
@@ -2,11 +2,8 @@ package com.kouros.navigation.car.screen
|
||||
|
||||
import android.location.Location
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.CarToast
|
||||
import androidx.car.app.Screen
|
||||
@@ -25,7 +22,6 @@ import com.kouros.android.cars.carappservice.R
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
import com.kouros.navigation.car.navigation.RouteCarModel
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Constants.TAG
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.model.ViewModel
|
||||
@@ -66,7 +62,7 @@ class PlaceListScreen(
|
||||
|
||||
fun loadPlaces() {
|
||||
if (category == Constants.RECENT) {
|
||||
viewModel.loadPlaces(carContext, location)
|
||||
viewModel.loadRecentPlaces(carContext, location)
|
||||
}
|
||||
if (category == Constants.CONTACTS) {
|
||||
viewModel.loadContacts(carContext, location)
|
||||
|
||||
@@ -2,14 +2,17 @@ package com.kouros.navigation.car.screen
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.location.Location
|
||||
import android.net.Uri
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.model.Action
|
||||
import androidx.car.app.model.CarIcon
|
||||
import androidx.car.app.model.ItemList
|
||||
import androidx.car.app.model.Row
|
||||
import androidx.car.app.model.SearchTemplate
|
||||
import androidx.car.app.model.SearchTemplate.SearchCallback
|
||||
import androidx.car.app.model.Template
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import com.kouros.android.cars.carappservice.R
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
@@ -61,6 +64,7 @@ class SearchScreen(
|
||||
itemListBuilder.addItem(
|
||||
Row.Builder()
|
||||
.setTitle(it.name)
|
||||
.setImage(categoryIcon(it.id))
|
||||
.setOnClickListener {
|
||||
screenManager
|
||||
.pushForResult(
|
||||
@@ -104,6 +108,25 @@ class SearchScreen(
|
||||
.build()
|
||||
}
|
||||
|
||||
fun categoryIcon(category: String?): CarIcon {
|
||||
val resId : Int = when (category) {
|
||||
Constants.RECENT -> {
|
||||
R.drawable.ic_place_white_24dp
|
||||
}
|
||||
Constants.FAVORITES -> {
|
||||
R.drawable.ic_favorite_white_24dp
|
||||
}
|
||||
else -> {
|
||||
R.drawable.navigation
|
||||
}
|
||||
}
|
||||
return CarIcon.Builder(
|
||||
IconCompat.createWithResource(
|
||||
carContext, resId
|
||||
)
|
||||
).build()
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
fun doSearch(searchItemListBuilder: ItemList.Builder) {
|
||||
searchResult.forEach {
|
||||
|
||||
@@ -2,8 +2,10 @@ package com.kouros.navigation.data
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val NavigationColor = Color(0xFF368605)
|
||||
val NavigationColor = Color(0xFF052186)
|
||||
|
||||
val RouteColor = Color(0xFF5582D0)
|
||||
|
||||
val SpeedColor = Color(0xFF262525)
|
||||
val SpeedColor = Color(0xFF262525)
|
||||
|
||||
val PlaceColor = Color(0xFF868005)
|
||||
@@ -62,7 +62,6 @@ data class ContactData(
|
||||
data class StepData (
|
||||
var instruction: String,
|
||||
var leftDistance: Double,
|
||||
var bearing: Double
|
||||
)
|
||||
|
||||
|
||||
@@ -138,8 +137,6 @@ object Constants {
|
||||
const val STYLE: String = "https://kouros-online.de/liberty.json"
|
||||
const val STYLE_DARK: String = "https://kouros-online.de/liberty_night.json"
|
||||
//const val STYLE: String = "https://tiles.openfreemap.org/styles/liberty"
|
||||
|
||||
|
||||
const val TAG: String = "Navigation"
|
||||
|
||||
const val CONTACTS: String = "Contacts"
|
||||
@@ -175,6 +172,8 @@ object Constants {
|
||||
|
||||
const val MAXIMAL_ROUTE_DEVIATION = 100.0
|
||||
|
||||
const val DESTINATION_ARRIVAL_DISTANCE = 20.0
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -39,11 +39,11 @@ class NavigationRepository {
|
||||
// motorway, trunk, primary, secondary, tertiary, unclassified, residential, service_other.
|
||||
|
||||
// exclude_toll
|
||||
fun getRoute(currentLocation: Location, location: Location, SearchFilter: SearchFilter): String {
|
||||
fun getRoute(currentLocation: Location, location: Location, searchFilter: SearchFilter): String {
|
||||
SearchFilter
|
||||
val vLocation = listOf(
|
||||
Locations(lat = currentLocation.latitude, lon = currentLocation.longitude, search_filter = SearchFilter),
|
||||
Locations(lat = location.latitude, lon = location.longitude, search_filter = SearchFilter)
|
||||
Locations(lat = currentLocation.latitude, lon = currentLocation.longitude, search_filter = searchFilter),
|
||||
Locations(lat = location.latitude, lon = location.longitude, search_filter = searchFilter)
|
||||
)
|
||||
val valhallaLocation = ValhallaLocation(
|
||||
locations = vLocation,
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
"source": "openmaptiles",
|
||||
"source-layer": "park",
|
||||
"paint": {
|
||||
"fill-color": "#d8e8c8",
|
||||
"fill-color": "rgba(78, 100, 56, 1)",
|
||||
"fill-opacity": 0.7,
|
||||
"fill-outline-color": "rgba(95, 208, 100, 1)"
|
||||
"fill-outline-color": "rgba(39, 78, 40, 1)"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -101,7 +101,7 @@
|
||||
"filter": ["==", ["get", "class"], "grass"],
|
||||
"paint": {
|
||||
"fill-antialias": false,
|
||||
"fill-color": "rgba(176, 213, 154, 1)",
|
||||
"fill-color": "rgba(21, 32, 15, 1)",
|
||||
"fill-opacity": 0.3
|
||||
}
|
||||
},
|
||||
@@ -153,7 +153,7 @@
|
||||
"source": "openmaptiles",
|
||||
"source-layer": "landuse",
|
||||
"filter": ["==", ["get", "class"], "cemetery"],
|
||||
"paint": {"fill-color": "hsl(75,37%,81%)"}
|
||||
"paint": {"fill-color": "rgba(65, 74, 92, 1)"}
|
||||
},
|
||||
{
|
||||
"id": "landuse_hospital",
|
||||
@@ -169,7 +169,7 @@
|
||||
"source": "openmaptiles",
|
||||
"source-layer": "landuse",
|
||||
"filter": ["==", ["get", "class"], "school"],
|
||||
"paint": {"fill-color": "rgb(236,238,204)"}
|
||||
"paint": {"fill-color": "rgba(65, 74, 92, 1)"}
|
||||
},
|
||||
{
|
||||
"id": "waterway_tunnel",
|
||||
@@ -905,7 +905,6 @@
|
||||
],
|
||||
"layout": {"line-cap": "round", "line-join": "round"},
|
||||
"paint": {
|
||||
"line-color": "#cfcdca",
|
||||
"line-width": [
|
||||
"interpolate",
|
||||
["exponential", 1.2],
|
||||
@@ -916,7 +915,8 @@
|
||||
4,
|
||||
20,
|
||||
11
|
||||
]
|
||||
],
|
||||
"line-color": "rgba(65, 74, 92, 1)"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -975,7 +975,6 @@
|
||||
],
|
||||
"layout": {"line-cap": "round", "line-join": "round"},
|
||||
"paint": {
|
||||
"line-color": "#cfcdca",
|
||||
"line-opacity": ["interpolate", ["linear"], ["zoom"], 12, 0, 12.5, 1],
|
||||
"line-width": [
|
||||
"interpolate",
|
||||
@@ -989,7 +988,8 @@
|
||||
4,
|
||||
20,
|
||||
20
|
||||
]
|
||||
],
|
||||
"line-color": "rgba(65, 74, 92, 1)"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1095,7 +1095,7 @@
|
||||
],
|
||||
"layout": {"line-join": "round"},
|
||||
"paint": {
|
||||
"line-color": "hsl(0,0%,100%)",
|
||||
"line-color": "rgba(65, 74, 92, 1)",
|
||||
"line-dasharray": [1, 0.7],
|
||||
"line-width": [
|
||||
"interpolate",
|
||||
@@ -1219,7 +1219,6 @@
|
||||
],
|
||||
"layout": {"line-cap": "round", "line-join": "round"},
|
||||
"paint": {
|
||||
"line-color": "rgba(195, 190, 190, 1)",
|
||||
"line-width": [
|
||||
"interpolate",
|
||||
["exponential", 1.2],
|
||||
@@ -1230,7 +1229,8 @@
|
||||
2.5,
|
||||
20,
|
||||
18
|
||||
]
|
||||
],
|
||||
"line-color": "rgba(65, 74, 92, 1)"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -30,8 +30,6 @@ open class RouteModel() {
|
||||
|
||||
var distanceToStepEnd = 0F
|
||||
|
||||
var bearing = 0F
|
||||
|
||||
var beginIndex = 0
|
||||
|
||||
var endIndex = 0
|
||||
@@ -57,7 +55,7 @@ open class RouteModel() {
|
||||
val currentDistance: Double
|
||||
/** Returns the current [Step] with information such as the cue text and images. */
|
||||
get() {
|
||||
return ((leftStepDistance() * 1000).roundToInt().toDouble() / 10.0).roundToInt() * 10.0
|
||||
return ((leftStepDistance()).roundToInt().toDouble() / 10.0).roundToInt() * 10.0
|
||||
}
|
||||
|
||||
fun updateLocation(location: Location) {
|
||||
@@ -86,14 +84,7 @@ open class RouteModel() {
|
||||
route.pointLocations[currentShapeIndex].longitude(),
|
||||
route.pointLocations[currentShapeIndex].latitude()
|
||||
)
|
||||
// if (currentShapeIndex < route.pointLocations.size) {
|
||||
// val nextLocation = location(
|
||||
// route.pointLocations[currentShapeIndex + 1].latitude(),
|
||||
// route.pointLocations[currentShapeIndex + 1].longitude()
|
||||
// )
|
||||
// bearing = curLocation.bearingTo(nextLocation)
|
||||
// }
|
||||
val distanceStepLeft = leftStepDistance() * 1000
|
||||
val distanceStepLeft = leftStepDistance()
|
||||
when (distanceStepLeft) {
|
||||
in 0.0..NEXT_STEP_THRESHOLD -> {
|
||||
if (route.currentManeuverIndex < route.maneuvers.size) {
|
||||
@@ -104,7 +95,7 @@ open class RouteModel() {
|
||||
}
|
||||
}
|
||||
}
|
||||
return StepData(text, distanceStepLeft, bearing.toDouble())
|
||||
return StepData(text, distanceStepLeft)
|
||||
}
|
||||
|
||||
/** Calculates the index in a maneuver. */
|
||||
@@ -174,16 +165,17 @@ open class RouteModel() {
|
||||
return timeLeft
|
||||
}
|
||||
|
||||
/** Returns the current [Step] left distance in km. */
|
||||
/** Returns the current [Step] left distance in m. */
|
||||
fun leftStepDistance(): Double {
|
||||
val maneuver = route.currentManeuver()
|
||||
var leftDistance = maneuver.length
|
||||
if (endIndex > 0) {
|
||||
leftDistance = (distanceToStepEnd / 1000).toDouble()
|
||||
leftDistance = distanceToStepEnd.toDouble()
|
||||
}
|
||||
return leftDistance
|
||||
return leftDistance * 1000
|
||||
}
|
||||
|
||||
/** Returns the left distance in km. */
|
||||
fun travelLeftDistance(): Double {
|
||||
var leftDistance = 0.0
|
||||
for (i in route.currentManeuverIndex + 1..<route.maneuvers.size) {
|
||||
|
||||
@@ -3,11 +3,14 @@ package com.kouros.navigation.model
|
||||
import android.content.Context
|
||||
import android.location.Geocoder
|
||||
import android.location.Location
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
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.Locations
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.ObjectBox.boxStore
|
||||
import com.kouros.navigation.data.Place
|
||||
@@ -64,20 +67,21 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
val results = query.find()
|
||||
query.close()
|
||||
for (place in results) {
|
||||
val plLocation = location(place.longitude,place.latitude)
|
||||
// val distance = repository.getRouteDistance(location, plLocation)
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
//val distance = repository.getRouteDistance(location, plLocation, SearchFilter())
|
||||
//place.distance = distance.toFloat()
|
||||
if (place.distance == 0F) {
|
||||
recentPlace.postValue(place)
|
||||
return@launch
|
||||
}
|
||||
//if (place.distance == 0F) {
|
||||
recentPlace.postValue(place)
|
||||
return@launch
|
||||
//}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
fun loadPlaces(context: Context, location: Location) {
|
||||
|
||||
fun loadRecentPlaces(context: Context, location: Location) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
@@ -89,7 +93,8 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
query.close()
|
||||
for (place in results) {
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
val distance = repository.getRouteDistance(location, plLocation, getSearchFilter(context))
|
||||
val distance =
|
||||
repository.getRouteDistance(location, plLocation, getSearchFilter(context))
|
||||
place.distance = distance.toFloat()
|
||||
}
|
||||
places.postValue(results)
|
||||
@@ -110,8 +115,9 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
val results = query.find()
|
||||
query.close()
|
||||
for (place in results) {
|
||||
val plLocation = location(place.longitude, place.latitude )
|
||||
val distance = repository.getRouteDistance(location, plLocation, getSearchFilter(context))
|
||||
val plLocation = location(place.longitude, place.latitude)
|
||||
val distance =
|
||||
repository.getRouteDistance(location, plLocation, getSearchFilter(context))
|
||||
place.distance = distance.toFloat()
|
||||
}
|
||||
favorites.postValue(results)
|
||||
@@ -124,7 +130,13 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
fun loadRoute(context: Context, currentLocation: Location, location: Location) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
route.postValue(repository.getRoute(currentLocation, location, getSearchFilter(context)))
|
||||
route.postValue(
|
||||
repository.getRoute(
|
||||
currentLocation,
|
||||
location,
|
||||
getSearchFilter(context)
|
||||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
@@ -134,7 +146,13 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
fun loadPreviewRoute(context: Context, currentLocation: Location, location: Location) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
previewRoute.postValue(repository.getRoute(currentLocation, location, getSearchFilter(context)))
|
||||
previewRoute.postValue(
|
||||
repository.getRoute(
|
||||
currentLocation,
|
||||
location,
|
||||
getSearchFilter(context)
|
||||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
@@ -155,9 +173,13 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
) {
|
||||
for (adr in it) {
|
||||
if (addressLines.size > 1) {
|
||||
val plLocation = location( adr.longitude, adr.latitude)
|
||||
val plLocation = location(adr.longitude, adr.latitude)
|
||||
val distance =
|
||||
repository.getRouteDistance(currentLocation, plLocation, getSearchFilter(context))
|
||||
repository.getRouteDistance(
|
||||
currentLocation,
|
||||
plLocation,
|
||||
getSearchFilter(context)
|
||||
)
|
||||
contactList.add(
|
||||
Place(
|
||||
id = address.contactId,
|
||||
@@ -201,7 +223,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun reverseAddress(location: Location ): String {
|
||||
fun reverseAddress(location: Location): String {
|
||||
val address = repository.reverseAddress(location)
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
val place = gson.fromJson(address, SearchResult::class.java)
|
||||
@@ -213,16 +235,20 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
place.category = Constants.FAVORITES
|
||||
savePlace(place)
|
||||
}
|
||||
|
||||
fun saveRecent(place: Place) {
|
||||
place.category = Constants.RECENT
|
||||
savePlace(place)
|
||||
}
|
||||
|
||||
fun savePlace(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!!)))
|
||||
.query(
|
||||
Place_.name.equal(place.name!!).and(Place_.category.equal(place.category!!))
|
||||
)
|
||||
.build()
|
||||
val results = query.find()
|
||||
query.close()
|
||||
@@ -247,12 +273,15 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
place.category = Constants.RECENT
|
||||
deletePlace(place)
|
||||
}
|
||||
|
||||
fun deletePlace(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!!)))
|
||||
.query(
|
||||
Place_.name.equal(place.name!!).and(Place_.category.equal(place.category!!))
|
||||
)
|
||||
.build()
|
||||
val results = query.find()
|
||||
query.close()
|
||||
@@ -267,11 +296,11 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
|
||||
fun getSearchFilter(context: Context): SearchFilter {
|
||||
|
||||
val avoidMotorway = NavigationUtils.getBooleanKeyValue(
|
||||
val avoidMotorway = NavigationUtils.getBooleanKeyValue(
|
||||
context = context,
|
||||
Constants.AVOID_MOTORWAY
|
||||
)
|
||||
val avoidTollway = NavigationUtils.getBooleanKeyValue(
|
||||
val avoidTollway = NavigationUtils.getBooleanKeyValue(
|
||||
context = context,
|
||||
Constants.AVOID_TOLLWAY
|
||||
)
|
||||
@@ -280,5 +309,28 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
.avoidTollway(avoidTollway)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun loadPlaces2(context: Context, location: Location): 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, getSearchFilter(context))
|
||||
place.distance = distance.toFloat()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return results.toMutableStateList()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import com.kouros.navigation.data.GeoJsonLineString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.maplibre.geojson.Point
|
||||
import org.maplibre.turf.TurfMisc
|
||||
import org.maplibre.turf.TurfMeasurement
|
||||
import java.lang.Math.toDegrees
|
||||
import java.lang.Math.toRadians
|
||||
import kotlin.math.asin
|
||||
@@ -151,20 +150,38 @@ object NavigationUtils {
|
||||
|
||||
fun calculateZoom(speed: Double?): Double {
|
||||
if (speed == null) {
|
||||
return 18.0
|
||||
return 17.0
|
||||
}
|
||||
val zoom = when (speed.toInt()) {
|
||||
val speedKmh = (speed * 3.6).toInt()
|
||||
val zoom = when (speedKmh) {
|
||||
in 0..10 -> 17.0
|
||||
in 11..20 -> 17.0
|
||||
in 21..30 -> 17.0
|
||||
in 31..40 -> 16.0
|
||||
in 41..50 -> 15.0
|
||||
in 51..60 -> 14.0
|
||||
else -> 14
|
||||
in 11..30 -> 16.0
|
||||
in 31..50 -> 16.0
|
||||
in 51..60 -> 15.0
|
||||
else -> 15
|
||||
}
|
||||
return zoom.toDouble()
|
||||
}
|
||||
fun bearing(fromLocation: Location, toLocation: Location ) : Double {
|
||||
|
||||
fun previewZoom(previewDistance: Double): Double {
|
||||
when (previewDistance) {
|
||||
in 0.0..10.0 -> {
|
||||
return 13.0
|
||||
}
|
||||
in 10.0..20.0 -> {
|
||||
return 11.0
|
||||
}
|
||||
in 20.0..30.0 -> {
|
||||
return 10.0
|
||||
}
|
||||
}
|
||||
return 9.0
|
||||
}
|
||||
fun bearing(fromLocation: Location, toLocation: Location, oldBearing: Double) : Double {
|
||||
val distance = fromLocation.distanceTo(toLocation)
|
||||
if (distance < 1.0) {
|
||||
return oldBearing
|
||||
}
|
||||
val bearing = fromLocation.bearingTo(toLocation).toInt().toDouble()
|
||||
return bearing
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user