Stopover and Legs
This commit is contained in:
@@ -181,7 +181,7 @@ fun Categories(
|
|||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
val places = viewModel.loadRecentPlace(applicationContext)
|
val places = viewModel.loadRecentPlace(applicationContext)
|
||||||
val toLocation = location(places.first()!!.longitude, places.first()!!.latitude)
|
val toLocation = location(places.first()!!.longitude, places.first()!!.latitude)
|
||||||
viewModel.loadRoute(applicationContext, location, toLocation, 0F)
|
viewModel.loadRoute(applicationContext, location, listOf(toLocation), 0F)
|
||||||
closeSheet()
|
closeSheet()
|
||||||
}) {
|
}) {
|
||||||
Icon(
|
Icon(
|
||||||
@@ -248,7 +248,7 @@ private fun SearchPlaces(
|
|||||||
viewModel.saveRecent(context, pl)
|
viewModel.saveRecent(context, pl)
|
||||||
val toLocation =
|
val toLocation =
|
||||||
location(place.lon.toDouble(), place.lat.toDouble())
|
location(place.lon.toDouble(), place.lat.toDouble())
|
||||||
viewModel.loadRoute(context, location, toLocation, 0F)
|
viewModel.loadRoute(context, location, listOf(toLocation), 0F)
|
||||||
closeSheet()
|
closeSheet()
|
||||||
}
|
}
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ fun Home(
|
|||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
val places = viewModel.loadRecentPlace(applicationContext)
|
val places = viewModel.loadRecentPlace(applicationContext)
|
||||||
val toLocation = location(places.first()!!.longitude, places.first()!!.latitude)
|
val toLocation = location(places.first()!!.longitude, places.first()!!.latitude)
|
||||||
viewModel.loadRoute(applicationContext, location, toLocation, 0F)
|
viewModel.loadRoute(applicationContext, location, listOf(toLocation), 0F)
|
||||||
closeSheet()
|
closeSheet()
|
||||||
}) {
|
}) {
|
||||||
Icon(
|
Icon(
|
||||||
@@ -168,7 +168,7 @@ private fun RecentPlaces(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable {
|
.clickable {
|
||||||
val toLocation = location(place.longitude, place.latitude)
|
val toLocation = location(place.longitude, place.latitude)
|
||||||
viewModel.loadRoute(context, location, toLocation, 0F)
|
viewModel.loadRoute(context, location, listOf(toLocation), 0F)
|
||||||
closeSheet()
|
closeSheet()
|
||||||
}
|
}
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.location.LocationManager
|
|||||||
import androidx.car.app.navigation.model.Maneuver
|
import androidx.car.app.navigation.model.Maneuver
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import com.kouros.data.R
|
|
||||||
import com.kouros.navigation.data.Constants.homeHohenwaldeck
|
import com.kouros.navigation.data.Constants.homeHohenwaldeck
|
||||||
import com.kouros.navigation.data.RouteEngine
|
import com.kouros.navigation.data.RouteEngine
|
||||||
import com.kouros.navigation.data.tomtom.TomTomRepository
|
import com.kouros.navigation.data.tomtom.TomTomRepository
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ class NavigationSession : Session(), NavigationListener, NavigationObserverCallb
|
|||||||
init {
|
init {
|
||||||
lifecycle.addObserver(lifecycleObserver)
|
lifecycle.addObserver(lifecycleObserver)
|
||||||
repository.routingEngineFlow.asLiveData().observe(this, Observer {
|
repository.routingEngineFlow.asLiveData().observe(this, Observer {
|
||||||
|
onRoutingEngineStateUpdated(it)
|
||||||
routingEngine = it
|
routingEngine = it
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -199,13 +200,15 @@ class NavigationSession : Session(), NavigationListener, NavigationObserverCallb
|
|||||||
* Creates appropriate repository based on user selection.
|
* Creates appropriate repository based on user selection.
|
||||||
*/
|
*/
|
||||||
fun onRoutingEngineStateUpdated(routeEngine: Int) {
|
fun onRoutingEngineStateUpdated(routeEngine: Int) {
|
||||||
navigationViewModel = when (routeEngine) {
|
if (!::navigationViewModel.isInitialized || routeEngine != routingEngine) {
|
||||||
RouteEngine.VALHALLA.ordinal -> NavigationViewModel(ValhallaRepository())
|
navigationViewModel = when (routeEngine) {
|
||||||
RouteEngine.OSRM.ordinal -> NavigationViewModel(OsrmRepository())
|
RouteEngine.VALHALLA.ordinal -> NavigationViewModel(ValhallaRepository())
|
||||||
else -> NavigationViewModel(TomTomRepository())
|
RouteEngine.OSRM.ordinal -> NavigationViewModel(OsrmRepository())
|
||||||
|
else -> NavigationViewModel(TomTomRepository())
|
||||||
|
}
|
||||||
|
observerManager = NavigationObserverManager(navigationViewModel, this)
|
||||||
|
observerManager.attachAllObservers(this)
|
||||||
}
|
}
|
||||||
observerManager = NavigationObserverManager(navigationViewModel, this)
|
|
||||||
observerManager.attachAllObservers(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -578,6 +581,8 @@ class NavigationSession : Session(), NavigationListener, NavigationObserverCallb
|
|||||||
* Called when user starts navigation
|
* Called when user starts navigation
|
||||||
*/
|
*/
|
||||||
override fun startNavigation() {
|
override fun startNavigation() {
|
||||||
|
Log.d(TAG, "startNavigation")
|
||||||
|
surfaceRenderer.navigation = true
|
||||||
surfaceRenderer.viewStyle = ViewStyle.VIEW
|
surfaceRenderer.viewStyle = ViewStyle.VIEW
|
||||||
navigationManager.navigationStarted()
|
navigationManager.navigationStarted()
|
||||||
navigationManagerStarted = true
|
navigationManagerStarted = true
|
||||||
@@ -597,6 +602,8 @@ class NavigationSession : Session(), NavigationListener, NavigationObserverCallb
|
|||||||
* Called when user exits navigation or arrives at destination.
|
* Called when user exits navigation or arrives at destination.
|
||||||
*/
|
*/
|
||||||
override fun stopNavigation() {
|
override fun stopNavigation() {
|
||||||
|
Log.d(TAG, "stopNavigation")
|
||||||
|
surfaceRenderer.navigation = false
|
||||||
routeModel.stopNavigation()
|
routeModel.stopNavigation()
|
||||||
navigationManager.navigationEnded()
|
navigationManager.navigationEnded()
|
||||||
if (autoDriveEnabled) {
|
if (autoDriveEnabled) {
|
||||||
@@ -609,6 +616,7 @@ class NavigationSession : Session(), NavigationListener, NavigationObserverCallb
|
|||||||
navigationScreen.navigationType = NavigationType.VIEW
|
navigationScreen.navigationType = NavigationType.VIEW
|
||||||
if (notificationActive)
|
if (notificationActive)
|
||||||
notificationManager.stopNotificationService()
|
notificationManager.stopNotificationService()
|
||||||
|
Log.d(TAG, "end stopNavigation")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateTrip(trip: Trip) {
|
override fun updateTrip(trip: Trip) {
|
||||||
@@ -723,9 +731,20 @@ class NavigationSession : Session(), NavigationListener, NavigationObserverCallb
|
|||||||
* Loads a route to the specified place and sets it as the destination.
|
* Loads a route to the specified place and sets it as the destination.
|
||||||
*/
|
*/
|
||||||
override fun navigateToPlace(place: Place) {
|
override fun navigateToPlace(place: Place) {
|
||||||
|
Log.d(TAG, "navigateToPlace ${place.street}")
|
||||||
|
var prevDestination = Place()
|
||||||
|
if (surfaceRenderer.navigation) {
|
||||||
|
prevDestination = routeModel.navState.destination
|
||||||
|
stopNavigation()
|
||||||
|
}
|
||||||
val preview = place.route
|
val preview = place.route
|
||||||
navigationViewModel.previewRoute.value = ""
|
navigationViewModel.previewRoute.value = ""
|
||||||
val location = location(place.longitude, place.latitude)
|
val location = if (place.stopOver && prevDestination.latitude != 0.0) {
|
||||||
|
listOf(location(place.longitude, place.latitude), location(prevDestination.longitude, prevDestination.latitude))
|
||||||
|
} else {
|
||||||
|
listOf(location(place.longitude, place.latitude))
|
||||||
|
}
|
||||||
|
|
||||||
navigationViewModel.saveRecent(carContext, place)
|
navigationViewModel.saveRecent(carContext, place)
|
||||||
routeModel.navState = routeModel.navState.copy(destination = place)
|
routeModel.navState = routeModel.navState.copy(destination = place)
|
||||||
if (preview.isEmpty()) {
|
if (preview.isEmpty()) {
|
||||||
@@ -813,7 +832,7 @@ class NavigationSession : Session(), NavigationListener, NavigationObserverCallb
|
|||||||
navigationViewModel.loadRoute(
|
navigationViewModel.loadRoute(
|
||||||
carContext,
|
carContext,
|
||||||
location,
|
location,
|
||||||
destination,
|
listOf(destination),
|
||||||
surfaceRenderer.carOrientation
|
surfaceRenderer.carOrientation
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,17 +10,12 @@ import androidx.car.app.AppManager
|
|||||||
import androidx.car.app.CarContext
|
import androidx.car.app.CarContext
|
||||||
import androidx.car.app.SurfaceCallback
|
import androidx.car.app.SurfaceCallback
|
||||||
import androidx.car.app.SurfaceContainer
|
import androidx.car.app.SurfaceContainer
|
||||||
import androidx.compose.animation.core.LinearOutSlowInEasing
|
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
|
||||||
import androidx.compose.animation.core.tween
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.platform.ComposeView
|
import androidx.compose.ui.platform.ComposeView
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
@@ -54,7 +49,6 @@ import org.maplibre.compose.camera.CameraPosition
|
|||||||
import org.maplibre.compose.camera.CameraState
|
import org.maplibre.compose.camera.CameraState
|
||||||
import org.maplibre.compose.style.BaseStyle
|
import org.maplibre.compose.style.BaseStyle
|
||||||
import org.maplibre.spatialk.geojson.Position
|
import org.maplibre.spatialk.geojson.Position
|
||||||
import java.time.Duration
|
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
|
|
||||||
@@ -123,6 +117,9 @@ class SurfaceRenderer(
|
|||||||
// Current view mode (navigation, preview, etc.)
|
// Current view mode (navigation, preview, etc.)
|
||||||
var viewStyle = ViewStyle.VIEW
|
var viewStyle = ViewStyle.VIEW
|
||||||
|
|
||||||
|
// Flag to indicate if in navigation mode
|
||||||
|
var navigation = false
|
||||||
|
|
||||||
// Center location for route preview
|
// Center location for route preview
|
||||||
lateinit var centerLocation: Location
|
lateinit var centerLocation: Location
|
||||||
|
|
||||||
@@ -457,7 +454,7 @@ class SurfaceRenderer(
|
|||||||
with(routeModel) {
|
with(routeModel) {
|
||||||
routeData.value = curRoute.routeGeoJson
|
routeData.value = curRoute.routeGeoJson
|
||||||
centerLocation = curRoute.centerLocation
|
centerLocation = curRoute.centerLocation
|
||||||
previewDistance = curRoute.summary.distance
|
previewDistance = curLeg.summary.distance
|
||||||
}
|
}
|
||||||
tilt = 0.0
|
tilt = 0.0
|
||||||
updateCameraPosition(
|
updateCameraPosition(
|
||||||
@@ -473,8 +470,10 @@ class SurfaceRenderer(
|
|||||||
* Calculates appropriate zoom
|
* Calculates appropriate zoom
|
||||||
*/
|
*/
|
||||||
fun setStandardView() {
|
fun setStandardView() {
|
||||||
|
if (!navigation) {
|
||||||
|
setRouteData("")
|
||||||
|
}
|
||||||
viewStyle = ViewStyle.VIEW
|
viewStyle = ViewStyle.VIEW
|
||||||
setRouteData("")
|
|
||||||
val zoom = calculateZoom(0.0)
|
val zoom = calculateZoom(0.0)
|
||||||
tilt = calculateTilt(zoom, tilt)
|
tilt = calculateTilt(zoom, tilt)
|
||||||
updateCameraPosition(
|
updateCameraPosition(
|
||||||
|
|||||||
@@ -367,7 +367,7 @@ fun NavigationImage(
|
|||||||
x = topLeftX ,
|
x = topLeftX ,
|
||||||
y = topLeftY,
|
y = topLeftY,
|
||||||
),
|
),
|
||||||
color = if (darkMode) navigationColor else Color.White,
|
color = if (darkMode) NavigationColorLight else Color.White,
|
||||||
cornerRadius = CornerRadius(x = 10f, y = 10f),
|
cornerRadius = CornerRadius(x = 10f, y = 10f),
|
||||||
)
|
)
|
||||||
drawText(
|
drawText(
|
||||||
|
|||||||
@@ -20,14 +20,13 @@ import androidx.car.app.model.ForegroundCarColorSpan
|
|||||||
import androidx.car.app.navigation.model.Lane
|
import androidx.car.app.navigation.model.Lane
|
||||||
import androidx.car.app.navigation.model.LaneDirection
|
import androidx.car.app.navigation.model.LaneDirection
|
||||||
import androidx.car.app.navigation.model.Maneuver
|
import androidx.car.app.navigation.model.Maneuver
|
||||||
import androidx.car.app.navigation.model.Maneuver.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW
|
|
||||||
import androidx.car.app.navigation.model.Maneuver.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW
|
|
||||||
import androidx.car.app.navigation.model.Step
|
import androidx.car.app.navigation.model.Step
|
||||||
import androidx.car.app.navigation.model.TravelEstimate
|
import androidx.car.app.navigation.model.TravelEstimate
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import com.kouros.data.R
|
import com.kouros.data.R
|
||||||
import com.kouros.navigation.car.screen.createCarIcon
|
import com.kouros.navigation.car.screen.createCarIcon
|
||||||
import com.kouros.navigation.data.StepData
|
import com.kouros.navigation.data.StepData
|
||||||
|
import com.kouros.navigation.data.route.ManeuverType
|
||||||
import com.kouros.navigation.model.RouteModel
|
import com.kouros.navigation.model.RouteModel
|
||||||
import com.kouros.navigation.utils.formattedDistance
|
import com.kouros.navigation.utils.formattedDistance
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
@@ -47,17 +46,15 @@ class RouteCarModel : RouteModel() {
|
|||||||
|
|
||||||
val maneuver = Maneuver.Builder(stepData.currentManeuverType)
|
val maneuver = Maneuver.Builder(stepData.currentManeuverType)
|
||||||
.setIcon(createCarIcon(carContext, stepData.icon))
|
.setIcon(createCarIcon(carContext, stepData.icon))
|
||||||
if (stepData.currentManeuverType == TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW
|
if (stepData.currentManeuverType == ManeuverType.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW.ordinal
|
||||||
|| stepData.currentManeuverType == TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW
|
|| stepData.currentManeuverType == ManeuverType.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW.ordinal
|
||||||
) {
|
) {
|
||||||
maneuver.setRoundaboutExitNumber(stepData.exitNumber)
|
maneuver.setRoundaboutExitNumber(stepData.exitNumber)
|
||||||
}
|
}
|
||||||
val step =
|
val step =
|
||||||
Step.Builder(currentStepCueWithImage)
|
Step.Builder(currentStepCueWithImage)
|
||||||
|
|
||||||
if (navState.destination.street != null) {
|
step.setRoad(navState.destination.street!!)
|
||||||
step.setRoad(navState.destination.street!!)
|
|
||||||
}
|
|
||||||
if (stepData.lane.isNotEmpty()) {
|
if (stepData.lane.isNotEmpty()) {
|
||||||
val lanesAdded = addLanes(carContext, step, stepData)
|
val lanesAdded = addLanes(carContext, step, stepData)
|
||||||
if (lanesAdded) {
|
if (lanesAdded) {
|
||||||
@@ -77,8 +74,8 @@ class RouteCarModel : RouteModel() {
|
|||||||
createString(stepData.instruction)
|
createString(stepData.instruction)
|
||||||
val maneuver = Maneuver.Builder(stepData.currentManeuverType)
|
val maneuver = Maneuver.Builder(stepData.currentManeuverType)
|
||||||
.setIcon(createCarIcon(carContext, stepData.icon))
|
.setIcon(createCarIcon(carContext, stepData.icon))
|
||||||
if (stepData.currentManeuverType == TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW
|
if (stepData.currentManeuverType == ManeuverType.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW.ordinal
|
||||||
|| stepData.currentManeuverType == TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW
|
|| stepData.currentManeuverType == ManeuverType.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW.ordinal
|
||||||
) {
|
) {
|
||||||
maneuver.setRoundaboutExitNumber(stepData.exitNumber)
|
maneuver.setRoundaboutExitNumber(stepData.exitNumber)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ class Simulation {
|
|||||||
) {
|
) {
|
||||||
if (routeModel.navState.route.isRouteValid()) {
|
if (routeModel.navState.route.isRouteValid()) {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
gpxSimulation(routeModel, lifecycleScope, updateLocation)
|
//gpxSimulation(routeModel, lifecycleScope, updateLocation)
|
||||||
//currentSimulation(routeModel, lifecycleScope, updateLocation)
|
currentSimulation(routeModel, lifecycleScope, updateLocation)
|
||||||
} else {
|
} else {
|
||||||
currentSimulation(routeModel, lifecycleScope, updateLocation)
|
currentSimulation(routeModel, lifecycleScope, updateLocation)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ class CategoryScreen(
|
|||||||
navigationViewModel.loadRoute(
|
navigationViewModel.loadRoute(
|
||||||
carContext,
|
carContext,
|
||||||
currentLocation = surfaceRenderer.lastLocation,
|
currentLocation = surfaceRenderer.lastLocation,
|
||||||
location(it.lon, it.lat),
|
listOf(location(it.lon, it.lat)),
|
||||||
surfaceRenderer.carOrientation
|
surfaceRenderer.carOrientation
|
||||||
)
|
)
|
||||||
setResult(
|
setResult(
|
||||||
@@ -197,7 +197,7 @@ class CategoryScreen(
|
|||||||
@DrawableRes iconRes: Int,
|
@DrawableRes iconRes: Int,
|
||||||
scale: Int
|
scale: Int
|
||||||
): Action {
|
): Action {
|
||||||
return createAction(carContext, iconRes, FLAG_IS_PERSISTENT, {
|
return createAction(carContext, iconRes, FLAG_IS_PERSISTENT, {
|
||||||
surfaceRenderer.handleScale(scale)
|
surfaceRenderer.handleScale(scale)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,18 +117,18 @@ open class NavigationScreen(
|
|||||||
)
|
)
|
||||||
}, { settingsAction() })
|
}, { settingsAction() })
|
||||||
return when (navigationType) {
|
return when (navigationType) {
|
||||||
NavigationType.NAVIGATION -> navigationTemplate(actionStripBuilder)
|
NavigationType.NAVIGATION -> navigation(actionStripBuilder)
|
||||||
NavigationType.RECENT -> navigationRecentPlacesTemplate()
|
NavigationType.RECENT -> navigationRecentPlaces()
|
||||||
NavigationType.REROUTE -> navigationRerouteTemplate(actionStripBuilder)
|
NavigationType.REROUTE -> navigationReroute(actionStripBuilder)
|
||||||
NavigationType.ARRIVAL -> navigationEndTemplate(actionStripBuilder)
|
NavigationType.ARRIVAL -> navigationEnd(actionStripBuilder)
|
||||||
else -> navigationViewTemplate(actionStripBuilder)
|
else -> navigationView(actionStripBuilder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns a NavigationTemplate for the active navigation state.
|
* Creates and returns a NavigationTemplate for the active navigation state.
|
||||||
*/
|
*/
|
||||||
private fun navigationTemplate(actionStripBuilder: ActionStrip.Builder): Template {
|
private fun navigation(actionStripBuilder: ActionStrip.Builder): Template {
|
||||||
actionStripBuilder.addAction(
|
actionStripBuilder.addAction(
|
||||||
createAction(
|
createAction(
|
||||||
carContext,
|
carContext,
|
||||||
@@ -150,7 +150,7 @@ open class NavigationScreen(
|
|||||||
carContext = carContext, R.drawable.ic_pan_24,
|
carContext = carContext, R.drawable.ic_pan_24,
|
||||||
0,
|
0,
|
||||||
onClickAction = {
|
onClickAction = {
|
||||||
surfaceRenderer.viewStyle = ViewStyle.VIEW
|
surfaceRenderer.setStandardView()
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -163,7 +163,7 @@ open class NavigationScreen(
|
|||||||
/**
|
/**
|
||||||
* Creates and returns a template for the default view state.
|
* Creates and returns a template for the default view state.
|
||||||
*/
|
*/
|
||||||
private fun navigationViewTemplate(actionStripBuilder: ActionStrip.Builder): Template {
|
private fun navigationView(actionStripBuilder: ActionStrip.Builder): Template {
|
||||||
return NavigationTemplate.Builder()
|
return NavigationTemplate.Builder()
|
||||||
.setBackgroundColor(backGroundColor)
|
.setBackgroundColor(backGroundColor)
|
||||||
.setActionStrip(actionStripBuilder.build())
|
.setActionStrip(actionStripBuilder.build())
|
||||||
@@ -187,24 +187,24 @@ open class NavigationScreen(
|
|||||||
/**
|
/**
|
||||||
* Creates and returns a template for the arrival.
|
* Creates and returns a template for the arrival.
|
||||||
*/
|
*/
|
||||||
private fun navigationEndTemplate(actionStripBuilder: ActionStrip.Builder): Template {
|
private fun navigationEnd(actionStripBuilder: ActionStrip.Builder): Template {
|
||||||
arrivalTimer?.cancel()
|
arrivalTimer?.cancel()
|
||||||
arrivalTimer = object : CountDownTimer(8000, 1000) {
|
arrivalTimer = object : CountDownTimer(8000, 1000) {
|
||||||
override fun onTick(millisUntilFinished: Long) {}
|
override fun onTick(millisUntilFinished: Long) {}
|
||||||
override fun onFinish() {
|
override fun onFinish() {
|
||||||
// routeModel.navState = routeModel.navState.copy(arrived = false)
|
// routeModel.navState = routeModel.navState.copy(arrived = false)
|
||||||
navigationType = NavigationType.VIEW
|
navigationType = NavigationType.VIEW
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arrivalTimer?.start()
|
arrivalTimer?.start()
|
||||||
return navigationArrivedTemplate(actionStripBuilder)
|
return navigationArrived(actionStripBuilder)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns a NavigationTemplate specifically for when the destination is reached.
|
* Creates and returns a NavigationTemplate specifically for when the destination is reached.
|
||||||
*/
|
*/
|
||||||
fun navigationArrivedTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
|
fun navigationArrived(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
|
||||||
var street = ""
|
var street = ""
|
||||||
if (destinations.first().address != null) {
|
if (destinations.first().address != null) {
|
||||||
street = destinations.first().address.toString()
|
street = destinations.first().address.toString()
|
||||||
@@ -226,7 +226,7 @@ open class NavigationScreen(
|
|||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
// .setBackgroundColor(routeModel.backGroundColor())
|
.setBackgroundColor(backGroundColor)
|
||||||
.setActionStrip(actionStripBuilder.build())
|
.setActionStrip(actionStripBuilder.build())
|
||||||
.setMapActionStrip(
|
.setMapActionStrip(
|
||||||
mapActionStrip(
|
mapActionStrip(
|
||||||
@@ -247,10 +247,10 @@ open class NavigationScreen(
|
|||||||
/**
|
/**
|
||||||
* Creates and returns a template showing recent places or destinations.
|
* Creates and returns a template showing recent places or destinations.
|
||||||
*/
|
*/
|
||||||
fun navigationRecentPlacesTemplate(): Template {
|
fun navigationRecentPlaces(): Template {
|
||||||
if (!tripSuggestion || recentPlaces.isEmpty()) {
|
if (!tripSuggestion || recentPlaces.isEmpty()) {
|
||||||
navigationType = NavigationType.VIEW
|
navigationType = NavigationType.VIEW
|
||||||
return navigationViewTemplate(
|
return navigationView(
|
||||||
createActionStripBuilder(
|
createActionStripBuilder(
|
||||||
{
|
{
|
||||||
createAction(
|
createAction(
|
||||||
@@ -263,7 +263,7 @@ open class NavigationScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
val listBuilder = ItemList.Builder()
|
val listBuilder = ItemList.Builder()
|
||||||
recentPlaces.filter { it.category == Constants.RECENT && it.distance > 300F }.forEach {
|
recentPlaces.filter { it.category == Constants.RECENT && it.distance > 300F }.forEach {
|
||||||
val row = Row.Builder()
|
val row = Row.Builder()
|
||||||
.setTitle(it.name)
|
.setTitle(it.name)
|
||||||
.addAction(
|
.addAction(
|
||||||
@@ -316,7 +316,7 @@ open class NavigationScreen(
|
|||||||
/**
|
/**
|
||||||
* Creates and returns a template for when the route is being recalculated.
|
* Creates and returns a template for when the route is being recalculated.
|
||||||
*/
|
*/
|
||||||
fun navigationRerouteTemplate(actionStripBuilder: ActionStrip.Builder): Template {
|
fun navigationReroute(actionStripBuilder: ActionStrip.Builder): Template {
|
||||||
return NavigationTemplate.Builder()
|
return NavigationTemplate.Builder()
|
||||||
.setNavigationInfo(RoutingInfo.Builder().setLoading(true).build())
|
.setNavigationInfo(RoutingInfo.Builder().setLoading(true).build())
|
||||||
.setActionStrip(actionStripBuilder.build())
|
.setActionStrip(actionStripBuilder.build())
|
||||||
@@ -486,7 +486,7 @@ open class NavigationScreen(
|
|||||||
navigationViewModel.loadRoute(
|
navigationViewModel.loadRoute(
|
||||||
carContext,
|
carContext,
|
||||||
surfaceRenderer.lastLocation,
|
surfaceRenderer.lastLocation,
|
||||||
destination,
|
listOf(destination),
|
||||||
surfaceRenderer.carOrientation
|
surfaceRenderer.carOrientation
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.text.Spannable
|
|||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import androidx.car.app.CarContext
|
import androidx.car.app.CarContext
|
||||||
import androidx.car.app.CarToast
|
import androidx.car.app.CarToast
|
||||||
import androidx.car.app.OnScreenResultListener
|
|
||||||
import androidx.car.app.Screen
|
import androidx.car.app.Screen
|
||||||
import androidx.car.app.model.Action
|
import androidx.car.app.model.Action
|
||||||
import androidx.car.app.model.CarIcon
|
import androidx.car.app.model.CarIcon
|
||||||
@@ -28,7 +27,6 @@ import com.kouros.navigation.data.Constants.CONTACTS
|
|||||||
import com.kouros.navigation.data.Constants.FAVORITES
|
import com.kouros.navigation.data.Constants.FAVORITES
|
||||||
import com.kouros.navigation.data.Constants.RECENT
|
import com.kouros.navigation.data.Constants.RECENT
|
||||||
import com.kouros.navigation.data.Place
|
import com.kouros.navigation.data.Place
|
||||||
import com.kouros.navigation.data.ViewStyle
|
|
||||||
import com.kouros.navigation.model.NavigationViewModel
|
import com.kouros.navigation.model.NavigationViewModel
|
||||||
import com.kouros.navigation.utils.getSettingsRepository
|
import com.kouros.navigation.utils.getSettingsRepository
|
||||||
|
|
||||||
@@ -66,41 +64,12 @@ class PlaceListScreen(
|
|||||||
val itemListBuilder = ItemList.Builder()
|
val itemListBuilder = ItemList.Builder()
|
||||||
.setNoItemsMessage(carContext.getString(R.string.no_places))
|
.setNoItemsMessage(carContext.getString(R.string.no_places))
|
||||||
recentPlaces.filter { it.category == category }.forEach {
|
recentPlaces.filter { it.category == category }.forEach {
|
||||||
val street = if (it.street != null) {
|
val street = it.street
|
||||||
it.street
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
val row = Row.Builder()
|
val row = Row.Builder()
|
||||||
.setImage(contactIcon(null, it.category))
|
.setImage(contactIcon(null, it.category))
|
||||||
.setTitle("$street ${it.city}")
|
.setTitle("$street ${it.city}")
|
||||||
.setOnClickListener {
|
.setOnClickListener {
|
||||||
place = Place(
|
clickOnPlace(it)
|
||||||
0,
|
|
||||||
it.name,
|
|
||||||
it.category,
|
|
||||||
it.latitude,
|
|
||||||
it.longitude,
|
|
||||||
it.postalCode,
|
|
||||||
it.city,
|
|
||||||
it.street,
|
|
||||||
// avatar = null
|
|
||||||
)
|
|
||||||
screenManager
|
|
||||||
.pushForResult(
|
|
||||||
RoutePreviewScreen(
|
|
||||||
carContext,
|
|
||||||
RoutePreviewType.MULTI_ROUTE,
|
|
||||||
surfaceRenderer,
|
|
||||||
place,
|
|
||||||
navigationViewModel,
|
|
||||||
)
|
|
||||||
) { obj: Any? ->
|
|
||||||
if (obj != null) {
|
|
||||||
setResult(obj)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (category != CONTACTS) {
|
if (category != CONTACTS) {
|
||||||
row.addText(SpannableString(" ").apply {
|
row.addText(SpannableString(" ").apply {
|
||||||
@@ -138,6 +107,69 @@ class PlaceListScreen(
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an Action to navigate to a specific place.
|
||||||
|
*/
|
||||||
|
private fun clickOnPlace(it: Place) {
|
||||||
|
place = Place(
|
||||||
|
0,
|
||||||
|
it.name,
|
||||||
|
it.category,
|
||||||
|
it.latitude,
|
||||||
|
it.longitude,
|
||||||
|
it.postalCode,
|
||||||
|
it.city,
|
||||||
|
it.street,
|
||||||
|
// avatar = null
|
||||||
|
)
|
||||||
|
if (surfaceRenderer.navigation) {
|
||||||
|
startStopOverScreen(place)
|
||||||
|
} else {
|
||||||
|
starPreviewScreen(place)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts preview screen for a specific place.
|
||||||
|
*/
|
||||||
|
private fun starPreviewScreen(place: Place) {
|
||||||
|
screenManager
|
||||||
|
.pushForResult(
|
||||||
|
RoutePreviewScreen(
|
||||||
|
carContext,
|
||||||
|
RoutePreviewType.MULTI_ROUTE,
|
||||||
|
surfaceRenderer,
|
||||||
|
place,
|
||||||
|
navigationViewModel,
|
||||||
|
)
|
||||||
|
) { obj: Any? ->
|
||||||
|
if (obj != null) {
|
||||||
|
setResult(obj)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts preview screen for a specific place.
|
||||||
|
*/
|
||||||
|
private fun startStopOverScreen(place: Place) {
|
||||||
|
screenManager
|
||||||
|
.pushForResult(
|
||||||
|
StopOverScreen(
|
||||||
|
carContext,
|
||||||
|
surfaceRenderer,
|
||||||
|
navigationViewModel,
|
||||||
|
place,
|
||||||
|
)
|
||||||
|
) { obj: Any? ->
|
||||||
|
if (obj != null) {
|
||||||
|
setResult(obj)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an Action to delete a place.
|
* Creates an Action to delete a place.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ class RoutePreviewScreen(
|
|||||||
|
|
||||||
var loading = true
|
var loading = true
|
||||||
|
|
||||||
|
var showAlternativeRoute = true
|
||||||
|
|
||||||
private val backPressedCallback = object : OnBackPressedCallback(false) {
|
private val backPressedCallback = object : OnBackPressedCallback(false) {
|
||||||
override fun handleOnBackPressed() {
|
override fun handleOnBackPressed() {
|
||||||
}
|
}
|
||||||
@@ -82,6 +84,10 @@ class RoutePreviewScreen(
|
|||||||
routeModel.startNavigation(route)
|
routeModel.startNavigation(route)
|
||||||
surfaceRenderer.setPreviewRouteData(routeModel)
|
surfaceRenderer.setPreviewRouteData(routeModel)
|
||||||
loading = false
|
loading = false
|
||||||
|
if (routeModel.route.routes.size == 1) {
|
||||||
|
routeType = RoutePreviewType.SINGLE_ROUTE
|
||||||
|
showAlternativeRoute = false
|
||||||
|
}
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,15 +145,12 @@ class RoutePreviewScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val street = if (destination.street.isEmpty()) {
|
val street = destination.street.ifEmpty {
|
||||||
carContext.getString((R.string.route_preview))
|
carContext.getString((R.string.route_preview))
|
||||||
} else {
|
|
||||||
destination.street
|
|
||||||
}
|
}
|
||||||
val header = Header.Builder()
|
val header = Header.Builder()
|
||||||
.setStartHeaderAction(Action.BACK)
|
.setStartHeaderAction(Action.BACK)
|
||||||
.setTitle(street)
|
.setTitle(street)
|
||||||
|
|
||||||
if (routeType == RoutePreviewType.SINGLE_ROUTE) {
|
if (routeType == RoutePreviewType.SINGLE_ROUTE) {
|
||||||
header.addEndHeaderAction(
|
header.addEndHeaderAction(
|
||||||
favoriteAction()
|
favoriteAction()
|
||||||
@@ -174,16 +177,6 @@ class RoutePreviewScreen(
|
|||||||
.build()
|
.build()
|
||||||
listContent.build()
|
listContent.build()
|
||||||
} else {
|
} else {
|
||||||
val navigateActionIcon: CarIcon = CarIcon.Builder(
|
|
||||||
IconCompat.createWithResource(
|
|
||||||
carContext, R.drawable.navigation_48px
|
|
||||||
)
|
|
||||||
).build()
|
|
||||||
val selectRouteIcon: CarIcon = CarIcon.Builder(
|
|
||||||
IconCompat.createWithResource(
|
|
||||||
carContext, R.drawable.alt_route_48px
|
|
||||||
)
|
|
||||||
).build()
|
|
||||||
val navigateAction =
|
val navigateAction =
|
||||||
createAction(carContext, R.drawable.navigation_48px, FLAG_DEFAULT,{
|
createAction(carContext, R.drawable.navigation_48px, FLAG_DEFAULT,{
|
||||||
onNavigate(routeModel.navState.currentRouteIndex)
|
onNavigate(routeModel.navState.currentRouteIndex)
|
||||||
@@ -195,7 +188,10 @@ class RoutePreviewScreen(
|
|||||||
val listContent = MessageTemplate.Builder(message)
|
val listContent = MessageTemplate.Builder(message)
|
||||||
.setHeader(header.build())
|
.setHeader(header.build())
|
||||||
.addAction(navigateAction)
|
.addAction(navigateAction)
|
||||||
.addAction(selectRouteAction)
|
|
||||||
|
if (showAlternativeRoute) {
|
||||||
|
listContent.addAction(selectRouteAction)
|
||||||
|
}
|
||||||
if (loading) {
|
if (loading) {
|
||||||
listContent.setLoading(true)
|
listContent.setLoading(true)
|
||||||
}
|
}
|
||||||
@@ -211,7 +207,7 @@ class RoutePreviewScreen(
|
|||||||
} )).build()
|
} )).build()
|
||||||
|
|
||||||
)
|
)
|
||||||
if (routeType == RoutePreviewType.MULTI_ROUTE && !routeSelected) {
|
if (routeModel.route.routes.size > 1 && routeType == RoutePreviewType.MULTI_ROUTE && !routeSelected) {
|
||||||
template.setActionStrip(createActionStrip {
|
template.setActionStrip(createActionStrip {
|
||||||
createAction(
|
createAction(
|
||||||
carContext, R.drawable.navigation_48px,
|
carContext, R.drawable.navigation_48px,
|
||||||
@@ -301,7 +297,7 @@ class RoutePreviewScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createRow(route: Routes, index: Int): Row {
|
private fun createRow(route: Routes, index: Int): Row {
|
||||||
val navigateAction = createAction(carContext, R.drawable.navigation_48px ) {
|
val navigateAction = createAction(carContext, R.drawable.navigation_48px, FLAG_DEFAULT ) {
|
||||||
this.onNavigate(index)
|
this.onNavigate(index)
|
||||||
}
|
}
|
||||||
val routeText = createRouteText(route)
|
val routeText = createRouteText(route)
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package com.kouros.navigation.car.screen
|
||||||
|
|
||||||
|
import androidx.car.app.CarContext
|
||||||
|
import androidx.car.app.Screen
|
||||||
|
import androidx.car.app.model.Action
|
||||||
|
import androidx.car.app.model.Action.FLAG_DEFAULT
|
||||||
|
import androidx.car.app.model.Action.FLAG_IS_PERSISTENT
|
||||||
|
import androidx.car.app.model.CarText
|
||||||
|
import androidx.car.app.model.Header
|
||||||
|
import androidx.car.app.model.MessageTemplate
|
||||||
|
import androidx.car.app.model.Template
|
||||||
|
import androidx.car.app.navigation.model.MapController
|
||||||
|
import androidx.car.app.navigation.model.MapWithContentTemplate
|
||||||
|
import com.kouros.data.R
|
||||||
|
import com.kouros.navigation.car.SurfaceRenderer
|
||||||
|
import com.kouros.navigation.data.Place
|
||||||
|
import com.kouros.navigation.data.ViewStyle
|
||||||
|
import com.kouros.navigation.model.NavigationViewModel
|
||||||
|
|
||||||
|
class StopOverScreen(
|
||||||
|
private val carContext: CarContext,
|
||||||
|
private val surfaceRenderer: SurfaceRenderer,
|
||||||
|
private val navigationViewModel: NavigationViewModel,
|
||||||
|
private val place: Place,
|
||||||
|
) : Screen(carContext) {
|
||||||
|
override fun onGetTemplate(): MapWithContentTemplate {
|
||||||
|
val cancelAction =
|
||||||
|
createAction(carContext, R.drawable.ic_close_white_24dp, FLAG_IS_PERSISTENT,{
|
||||||
|
finish()
|
||||||
|
})
|
||||||
|
val header = Header.Builder()
|
||||||
|
.setStartHeaderAction(Action.BACK)
|
||||||
|
.addEndHeaderAction(cancelAction)
|
||||||
|
.setTitle(place.street)
|
||||||
|
|
||||||
|
val message = CarText.Builder("Neue Fahrt oder Zwischenstopp einfügen")
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val navigateAction = Action.Builder()
|
||||||
|
.setIcon(createCarIcon(carContext, R.drawable.navigation_48px))
|
||||||
|
.setFlags(FLAG_DEFAULT)
|
||||||
|
.setOnClickListener {
|
||||||
|
setResult(place)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val selectRouteAction = Action.Builder()
|
||||||
|
.setIcon(createCarIcon(carContext, R.drawable.alt_route_48px))
|
||||||
|
.setFlags(FLAG_IS_PERSISTENT)
|
||||||
|
.setOnClickListener {
|
||||||
|
place.stopOver = true
|
||||||
|
setResult(place)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val listContent = MessageTemplate.Builder(message)
|
||||||
|
.setHeader(header.build())
|
||||||
|
.addAction(navigateAction)
|
||||||
|
.addAction(selectRouteAction)
|
||||||
|
|
||||||
|
val template = MapWithContentTemplate.Builder()
|
||||||
|
.setContentTemplate(listContent.build())
|
||||||
|
|
||||||
|
return template.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -33,6 +33,8 @@ class NavigationSettings(
|
|||||||
|
|
||||||
private var carLocationToggleState = false
|
private var carLocationToggleState = false
|
||||||
|
|
||||||
|
private var alternativeRoutesToggleState = false
|
||||||
|
|
||||||
val settingsViewModel = getSettingsViewModel(carContext)
|
val settingsViewModel = getSettingsViewModel(carContext)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -41,6 +43,7 @@ class NavigationSettings(
|
|||||||
settingsViewModel.avoidMotorway.first()
|
settingsViewModel.avoidMotorway.first()
|
||||||
settingsViewModel.avoidFerry.first()
|
settingsViewModel.avoidFerry.first()
|
||||||
settingsViewModel.carLocation.first()
|
settingsViewModel.carLocation.first()
|
||||||
|
settingsViewModel.alternativeRoutes.first()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +52,7 @@ class NavigationSettings(
|
|||||||
tollWayToggleState = settingsViewModel.avoidTollway.value
|
tollWayToggleState = settingsViewModel.avoidTollway.value
|
||||||
ferryToggleState = settingsViewModel.avoidFerry.value
|
ferryToggleState = settingsViewModel.avoidFerry.value
|
||||||
carLocationToggleState = settingsViewModel.carLocation.value
|
carLocationToggleState = settingsViewModel.carLocation.value
|
||||||
|
alternativeRoutesToggleState = settingsViewModel.alternativeRoutes.value
|
||||||
|
|
||||||
val listBuilder = ItemList.Builder()
|
val listBuilder = ItemList.Builder()
|
||||||
|
|
||||||
@@ -89,6 +93,14 @@ class NavigationSettings(
|
|||||||
carLocationToggleState = !carLocationToggleState
|
carLocationToggleState = !carLocationToggleState
|
||||||
}.setChecked(carLocationToggleState).build()
|
}.setChecked(carLocationToggleState).build()
|
||||||
|
|
||||||
|
// Alternative routes
|
||||||
|
val alternativeRoutesToggle: Toggle =
|
||||||
|
Toggle.Builder { checked: Boolean ->
|
||||||
|
settingsViewModel.onAlternativeRoutes(checked)
|
||||||
|
alternativeRoutesToggleState = !alternativeRoutesToggleState
|
||||||
|
}.setChecked(alternativeRoutesToggleState).build()
|
||||||
|
|
||||||
|
|
||||||
listBuilder.addItem(
|
listBuilder.addItem(
|
||||||
buildRowForTemplate(
|
buildRowForTemplate(
|
||||||
R.string.use_car_location,
|
R.string.use_car_location,
|
||||||
@@ -97,6 +109,14 @@ class NavigationSettings(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
listBuilder.addItem(
|
||||||
|
buildRowForTemplate(
|
||||||
|
R.string.alternative_routes,
|
||||||
|
alternativeRoutesToggle,
|
||||||
|
createCarIcon(carContext,R.drawable.alt_route_48px)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
listBuilder.addItem(
|
listBuilder.addItem(
|
||||||
buildRowForScreenTemplate(
|
buildRowForScreenTemplate(
|
||||||
RoutingSettings(carContext, navigationViewModel),
|
RoutingSettings(carContext, navigationViewModel),
|
||||||
@@ -109,6 +129,7 @@ class NavigationSettings(
|
|||||||
R.string.tomtom_api_key
|
R.string.tomtom_api_key
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return ListTemplate.Builder()
|
return ListTemplate.Builder()
|
||||||
.setSingleList(listBuilder.build())
|
.setSingleList(listBuilder.build())
|
||||||
.setHeader(
|
.setHeader(
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ package com.kouros.navigation.data
|
|||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
val NavigationColorLight = Color(0xFF066462)
|
val NavigationColorLight = Color(0xFF17A119)
|
||||||
|
|
||||||
val NavigationColorDark = Color(0xFF10DED9)
|
val NavigationColorDark = Color(0xFF4EDE10)
|
||||||
|
|
||||||
val RouteColor = Color(0xFF7B06E1)
|
val RouteColor = Color(0xFF05692D)
|
||||||
|
|
||||||
val SpeedColor = Color(0xFF262525)
|
val SpeedColor = Color(0xFF262525)
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ data class Place(
|
|||||||
var lastDate: Long = 0,
|
var lastDate: Long = 0,
|
||||||
var routeIndex: Int = 0,
|
var routeIndex: Int = 0,
|
||||||
var route: String = "",
|
var route: String = "",
|
||||||
|
var stopOver: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class ContactData(
|
data class ContactData(
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ abstract class NavigationRepository {
|
|||||||
abstract fun getRoute(
|
abstract fun getRoute(
|
||||||
context: Context,
|
context: Context,
|
||||||
currentLocation: Location,
|
currentLocation: Location,
|
||||||
destination: Location,
|
location: List<Location>,
|
||||||
carOrientation: Float,
|
carOrientation: Float,
|
||||||
searchFilter: SearchFilter
|
searchFilter: SearchFilter
|
||||||
): String
|
): String
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ class DataStoreManager(private val context: Context) {
|
|||||||
|
|
||||||
val ENGINE_TYPE = intPreferencesKey("EngineType")
|
val ENGINE_TYPE = intPreferencesKey("EngineType")
|
||||||
|
|
||||||
|
val ALTERNATIVE_ROUTES = booleanPreferencesKey("AlternativeRoutes")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read values
|
// Read values
|
||||||
@@ -145,6 +147,11 @@ class DataStoreManager(private val context: Context) {
|
|||||||
?: EngineType.COMBUSTION.ordinal
|
?: EngineType.COMBUSTION.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val alternativeRoutesFlow: Flow<Boolean> =
|
||||||
|
context.dataStore.data.map { preferences ->
|
||||||
|
preferences[PreferencesKeys.ALTERNATIVE_ROUTES] == true
|
||||||
|
}
|
||||||
|
|
||||||
// Save values
|
// Save values
|
||||||
suspend fun setShow3D(enabled: Boolean) {
|
suspend fun setShow3D(enabled: Boolean) {
|
||||||
context.dataStore.edit { preferences ->
|
context.dataStore.edit { preferences ->
|
||||||
@@ -235,4 +242,11 @@ class DataStoreManager(private val context: Context) {
|
|||||||
prefs[PreferencesKeys.ENGINE_TYPE] = mode
|
prefs[PreferencesKeys.ENGINE_TYPE] = mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun setAlternativeRoutes(enabled: Boolean) {
|
||||||
|
context.dataStore.edit { preferences ->
|
||||||
|
preferences[PreferencesKeys.ALTERNATIVE_ROUTES] = enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class OsrmRepository : NavigationRepository() {
|
|||||||
override fun getRoute(
|
override fun getRoute(
|
||||||
context: Context,
|
context: Context,
|
||||||
currentLocation: Location,
|
currentLocation: Location,
|
||||||
location: Location,
|
location: List<Location>,
|
||||||
carOrientation: Float,
|
carOrientation: Float,
|
||||||
searchFilter: SearchFilter
|
searchFilter: SearchFilter
|
||||||
): String {
|
): String {
|
||||||
@@ -28,7 +28,7 @@ class OsrmRepository : NavigationRepository() {
|
|||||||
if (searchFilter.avoidFerry) {
|
if (searchFilter.avoidFerry) {
|
||||||
exclude = "$exclude&exclude=ferry"
|
exclude = "$exclude&exclude=ferry"
|
||||||
}
|
}
|
||||||
val routeLocation = "${currentLocation.longitude},${currentLocation.latitude};${location.longitude},${location.latitude}?steps=true&alternatives=false"
|
val routeLocation = "${currentLocation.longitude},${currentLocation.latitude};${location.first().longitude},${location.first().latitude}?steps=true&alternatives=false"
|
||||||
return fetchUrl(routeUrl + routeLocation + exclude, true)
|
return fetchUrl(routeUrl + routeLocation + exclude, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class OsrmRoute {
|
|||||||
steps.add(step)
|
steps.add(step)
|
||||||
stepIndex += 1
|
stepIndex += 1
|
||||||
}
|
}
|
||||||
legs.add(Leg(steps))
|
legs.add(Leg(steps, summary))
|
||||||
}
|
}
|
||||||
val routeGeoJson = createLineStringCollection(waypoints)
|
val routeGeoJson = createLineStringCollection(waypoints)
|
||||||
val centerLocation = createCenterLocation(createLineStringCollection(waypoints))
|
val centerLocation = createCenterLocation(createLineStringCollection(waypoints))
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
package com.kouros.navigation.data.route
|
package com.kouros.navigation.data.route
|
||||||
|
|
||||||
|
import android.location.Location
|
||||||
|
import com.kouros.navigation.utils.location
|
||||||
|
|
||||||
data class Leg(
|
data class Leg(
|
||||||
var steps : List<Step> = arrayListOf(),
|
var steps : List<Step> = arrayListOf(),
|
||||||
|
val summary: Summary,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,3 +13,57 @@ data class Maneuver(
|
|||||||
val message: String = "",
|
val message: String = "",
|
||||||
val pointIndex : Int = 0,
|
val pointIndex : Int = 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum class ManeuverType {
|
||||||
|
TYPE_UNKNOWN,
|
||||||
|
TYPE_DEPART,
|
||||||
|
TYPE_NAME_CHANGE,
|
||||||
|
TYPE_KEEP_LEFT,
|
||||||
|
TYPE_KEEP_RIGHT,
|
||||||
|
TYPE_TURN_SLIGHT_LEFT,
|
||||||
|
TYPE_TURN_SLIGHT_RIGHT,
|
||||||
|
TYPE_TURN_NORMAL_LEFT,
|
||||||
|
TYPE_TURN_NORMAL_RIGHT,
|
||||||
|
TYPE_TURN_SHARP_LEFT,
|
||||||
|
TYPE_TURN_SHARP_RIGHT,
|
||||||
|
TYPE_U_TURN_LEFT,
|
||||||
|
TYPE_U_TURN_RIGHT,
|
||||||
|
TYPE_ON_RAMP_SLIGHT_LEFT,
|
||||||
|
TYPE_ON_RAMP_SLIGHT_RIGHT,
|
||||||
|
TYPE_ON_RAMP_NORMAL_LEFT,
|
||||||
|
TYPE_ON_RAMP_NORMAL_RIGHT,
|
||||||
|
TYPE_ON_RAMP_SHARP_LEFT,
|
||||||
|
TYPE_ON_RAMP_SHARP_RIGHT,
|
||||||
|
TYPE_ON_RAMP_U_TURN_LEFT,
|
||||||
|
TYPE_ON_RAMP_U_TURN_RIGHT,
|
||||||
|
TYPE_OFF_RAMP_SLIGHT_LEFT,
|
||||||
|
TYPE_OFF_RAMP_SLIGHT_RIGHT,
|
||||||
|
TYPE_OFF_RAMP_NORMAL_LEFT,
|
||||||
|
TYPE_OFF_RAMP_NORMAL_RIGHT,
|
||||||
|
TYPE_FORK_LEFT,
|
||||||
|
TYPE_FORK_RIGHT,
|
||||||
|
TYPE_MERGE_LEFT,
|
||||||
|
TYPE_MERGE_RIGHT,
|
||||||
|
TYPE_MERGE_SIDE_UNSPECIFIED,
|
||||||
|
TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW,
|
||||||
|
TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE,
|
||||||
|
TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW,
|
||||||
|
TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE,
|
||||||
|
TYPE_STRAIGHT,
|
||||||
|
TYPE_FERRY_BOAT,
|
||||||
|
TYPE_FERRY_TRAIN,
|
||||||
|
TYPE_DESTINATION,
|
||||||
|
TYPE_DESTINATION_STRAIGHT,
|
||||||
|
TYPE_DESTINATION_LEFT,
|
||||||
|
TYPE_DESTINATION_RIGHT,
|
||||||
|
TYPE_ROUNDABOUT_ENTER_CW,
|
||||||
|
TYPE_ROUNDABOUT_EXIT_CW,
|
||||||
|
TYPE_ROUNDABOUT_ENTER_CCW,
|
||||||
|
TYPE_ROUNDABOUT_EXIT_CCW,
|
||||||
|
TYPE_FERRY_BOAT_LEFT,
|
||||||
|
TYPE_FERRY_BOAT_RIGHT,
|
||||||
|
TYPE_FERRY_TRAIN_LEFT,
|
||||||
|
TYPE_FERRY_TRAIN_RIGHT,
|
||||||
|
TYPE_WAYPOINT_RIGHT,
|
||||||
|
TYPE_WAYPOINT_LEFT
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,14 +23,14 @@ private const val tomtomFields =
|
|||||||
|
|
||||||
val useLocal = BuildConfig.DEBUG
|
val useLocal = BuildConfig.DEBUG
|
||||||
|
|
||||||
val useLocalTraffic = BuildConfig.DEBUG
|
val useLocalTraffic = BuildConfig.DEBUG
|
||||||
|
|
||||||
|
|
||||||
class TomTomRepository : NavigationRepository() {
|
class TomTomRepository : NavigationRepository() {
|
||||||
override fun getRoute(
|
override fun getRoute(
|
||||||
context: Context,
|
context: Context,
|
||||||
currentLocation: Location,
|
currentLocation: Location,
|
||||||
location: Location,
|
location: List<Location>,
|
||||||
carOrientation: Float,
|
carOrientation: Float,
|
||||||
searchFilter: SearchFilter
|
searchFilter: SearchFilter
|
||||||
): String {
|
): String {
|
||||||
@@ -55,17 +55,34 @@ class TomTomRepository : NavigationRepository() {
|
|||||||
engineType = "electric"
|
engineType = "electric"
|
||||||
}
|
}
|
||||||
val repository = getSettingsRepository(context)
|
val repository = getSettingsRepository(context)
|
||||||
val tomtomApiKey = runBlocking { repository.tomTomApiKeyFlow.first() }
|
val tomtomApiKey = runBlocking {
|
||||||
|
repository.tomTomApiKeyFlow.first()
|
||||||
|
}
|
||||||
|
val alternativeRoutes = runBlocking {
|
||||||
|
repository.alternativeRoutesFlow.first()
|
||||||
|
}
|
||||||
|
val altRoutes = if (alternativeRoutes) {
|
||||||
|
"&maxAlternatives=2"
|
||||||
|
} else {
|
||||||
|
"&maxAlternatives=0"
|
||||||
|
}
|
||||||
val currentLocale = Locale.getDefault()
|
val currentLocale = Locale.getDefault()
|
||||||
val language = currentLocale.language + "-" + currentLocale.country
|
val language = currentLocale.language + "-" + currentLocale.country
|
||||||
|
var loc = ""
|
||||||
|
location.forEach {
|
||||||
|
loc += if (loc.isEmpty()) {
|
||||||
|
"${it.latitude},${it.longitude}"
|
||||||
|
} else {
|
||||||
|
":${it.latitude},${it.longitude}"
|
||||||
|
}
|
||||||
|
}
|
||||||
val url =
|
val url =
|
||||||
routeUrl + "${currentLocation.latitude},${currentLocation.longitude}:${location.latitude},${location.longitude}" +
|
routeUrl + "${currentLocation.latitude},${currentLocation.longitude}:$loc" +
|
||||||
"/json?sectionType=traffic&report=effectiveSettings&routeType=eco" +
|
"/json?sectionType=traffic&report=effectiveSettings&routeType=eco" +
|
||||||
"&traffic=true&avoid=unpavedRoads&travelMode=car" +
|
"&traffic=true&avoid=unpavedRoads&travelMode=car" +
|
||||||
"&vehicleMaxSpeed=120&vehicleCommercial=false" +
|
"&vehicleMaxSpeed=120&vehicleCommercial=false" +
|
||||||
"&instructionsType=text&language=$language§ionType=lanes" +
|
"&instructionsType=text&language=$language§ionType=lanes" +
|
||||||
"&routeRepresentation=encodedPolyline" +
|
"&routeRepresentation=encodedPolyline$altRoutes" +
|
||||||
"&maxAlternatives=2" +
|
|
||||||
"&vehicleEngineType=$engineType$filter&key=$tomtomApiKey"
|
"&vehicleEngineType=$engineType$filter&key=$tomtomApiKey"
|
||||||
return fetchUrl(
|
return fetchUrl(
|
||||||
url,
|
url,
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package com.kouros.navigation.data.tomtom
|
package com.kouros.navigation.data.tomtom
|
||||||
|
|
||||||
|
|
||||||
import com.kouros.navigation.data.Route
|
import com.kouros.navigation.data.Route
|
||||||
import com.kouros.navigation.data.RouteEngine
|
import com.kouros.navigation.data.RouteEngine
|
||||||
import com.kouros.navigation.data.route.Intersection
|
import com.kouros.navigation.data.route.Intersection
|
||||||
import com.kouros.navigation.data.route.Lane
|
import com.kouros.navigation.data.route.Lane
|
||||||
import com.kouros.navigation.data.route.Leg
|
import com.kouros.navigation.data.route.Leg
|
||||||
|
import com.kouros.navigation.data.route.ManeuverType
|
||||||
|
import com.kouros.navigation.data.route.Routes
|
||||||
import com.kouros.navigation.data.route.Step
|
import com.kouros.navigation.data.route.Step
|
||||||
import com.kouros.navigation.data.route.Summary
|
import com.kouros.navigation.data.route.Summary
|
||||||
import com.kouros.navigation.utils.GeoUtils.createCenterLocation
|
import com.kouros.navigation.utils.GeoUtils.createCenterLocation
|
||||||
@@ -17,12 +20,12 @@ import com.kouros.navigation.data.route.Maneuver as RouteManeuver
|
|||||||
class TomTomRoute {
|
class TomTomRoute {
|
||||||
|
|
||||||
fun mapToRoute(routeJson: TomTomResponse, builder: Route.Builder) {
|
fun mapToRoute(routeJson: TomTomResponse, builder: Route.Builder) {
|
||||||
val routes = mutableListOf<com.kouros.navigation.data.route.Routes>()
|
val routes = mutableListOf<Routes>()
|
||||||
routeJson.routes.forEach { route ->
|
routeJson.routes.forEach { route ->
|
||||||
val waypoints = mutableListOf<List<Double>>()
|
val waypoints = mutableListOf<List<Double>>()
|
||||||
|
val points = mutableListOf<List<Double>>()
|
||||||
val legs = mutableListOf<Leg>()
|
val legs = mutableListOf<Leg>()
|
||||||
var stepIndex = 0
|
var stepIndex = 0
|
||||||
var points = listOf<List<Double>>()
|
|
||||||
val summary = Summary(
|
val summary = Summary(
|
||||||
route.summary.travelTimeInSeconds.toDouble(),
|
route.summary.travelTimeInSeconds.toDouble(),
|
||||||
route.summary.lengthInMeters.toDouble(),
|
route.summary.lengthInMeters.toDouble(),
|
||||||
@@ -30,89 +33,98 @@ class TomTomRoute {
|
|||||||
route.summary.trafficLengthInMeters.toDouble()
|
route.summary.trafficLengthInMeters.toDouble()
|
||||||
)
|
)
|
||||||
route.legs.forEach { leg ->
|
route.legs.forEach { leg ->
|
||||||
points = decodePolyline(leg.encodedPolyline, leg.encodedPolylinePrecision)
|
val p = decodePolyline(leg.encodedPolyline, leg.encodedPolylinePrecision)
|
||||||
waypoints.addAll(points)
|
points.addAll(p)
|
||||||
|
waypoints.addAll(p)
|
||||||
}
|
}
|
||||||
var stepDistance = 0.0
|
route.legs.forEach { leg ->
|
||||||
var stepDuration = 0.0
|
var stepDistance = 0.0
|
||||||
val steps = mutableListOf<Step>()
|
var stepDuration = 0.0
|
||||||
var lastPointIndex = 0
|
val steps = mutableListOf<Step>()
|
||||||
for (index in 1..<route.guidance.instructions.size) {
|
val summary = Summary(
|
||||||
val lastInstruction = route.guidance.instructions[index - 1]
|
leg.summary.travelTimeInSeconds.toDouble(),
|
||||||
val instruction = route.guidance.instructions[index]
|
leg.summary.lengthInMeters.toDouble(),
|
||||||
val street = lastInstruction.street ?: ""
|
leg.summary.trafficDelayInSeconds.toDouble(),
|
||||||
val maneuverStreet = instruction.street ?: ""
|
leg.summary.trafficLengthInMeters.toDouble()
|
||||||
val maneuver = RouteManeuver(
|
|
||||||
bearingBefore = 0,
|
|
||||||
bearingAfter = 0,
|
|
||||||
type = convertType(instruction.maneuver),
|
|
||||||
waypoints = points.subList(
|
|
||||||
lastPointIndex,
|
|
||||||
instruction.pointIndex + 1,
|
|
||||||
),
|
|
||||||
exit = exitNumber(instruction),
|
|
||||||
location = location(
|
|
||||||
instruction.point.longitude, instruction.point.latitude
|
|
||||||
),
|
|
||||||
street = maneuverStreet,
|
|
||||||
message = instruction.message,
|
|
||||||
pointIndex = instruction.pointIndex
|
|
||||||
)
|
)
|
||||||
|
var lastPointIndex = 0
|
||||||
|
for (index in 1..<route.guidance.instructions.size) {
|
||||||
|
val lastInstruction = route.guidance.instructions[index - 1]
|
||||||
|
val instruction = route.guidance.instructions[index]
|
||||||
|
val street = lastInstruction.street ?: ""
|
||||||
|
val maneuverStreet = instruction.street ?: ""
|
||||||
|
val maneuver = RouteManeuver(
|
||||||
|
bearingBefore = 0,
|
||||||
|
bearingAfter = 0,
|
||||||
|
type = convertType(instruction.maneuver),
|
||||||
|
waypoints = points.subList(
|
||||||
|
lastPointIndex,
|
||||||
|
instruction.pointIndex + 1,
|
||||||
|
),
|
||||||
|
exit = exitNumber(instruction),
|
||||||
|
location = location(
|
||||||
|
instruction.point.longitude, instruction.point.latitude
|
||||||
|
),
|
||||||
|
street = maneuverStreet,
|
||||||
|
message = instruction.message,
|
||||||
|
pointIndex = instruction.pointIndex
|
||||||
|
)
|
||||||
|
|
||||||
lastPointIndex = instruction.pointIndex
|
lastPointIndex = instruction.pointIndex
|
||||||
val intersections = mutableListOf<Intersection>()
|
val intersections = mutableListOf<Intersection>()
|
||||||
route.sections?.forEach { section ->
|
route.sections?.forEach { section ->
|
||||||
if (section.sectionType == "LANES" && section.startPointIndex <= lastPointIndex
|
if (section.sectionType == "LANES" && section.startPointIndex <= lastPointIndex
|
||||||
&& section.endPointIndex >= lastPointIndex
|
&& section.endPointIndex >= lastPointIndex
|
||||||
) {
|
) {
|
||||||
val lanes = mutableListOf<Lane>()
|
val lanes = mutableListOf<Lane>()
|
||||||
var startIndex = 0
|
var startIndex = 0
|
||||||
var lastLane: Lane? = null
|
var lastLane: Lane? = null
|
||||||
section.lanes?.forEach { itLane ->
|
section.lanes?.forEach { itLane ->
|
||||||
val lane = Lane(
|
val lane = Lane(
|
||||||
location = location(
|
location = location(
|
||||||
waypoints[section.startPointIndex][0],
|
waypoints[section.startPointIndex][0],
|
||||||
waypoints[section.startPointIndex][1]
|
waypoints[section.startPointIndex][1]
|
||||||
),
|
),
|
||||||
valid = itLane.directions.first() == itLane.follow,
|
valid = itLane.directions.first() == itLane.follow,
|
||||||
indications = itLane.directions,
|
indications = itLane.directions,
|
||||||
startIndex = startIndex,
|
startIndex = startIndex,
|
||||||
endIndex = section.endPointIndex
|
endIndex = section.endPointIndex
|
||||||
)
|
)
|
||||||
startIndex = section.startPointIndex
|
startIndex = section.startPointIndex
|
||||||
if (lastLane == null
|
if (lastLane == null
|
||||||
|| (!(lastLane.valid && lane.valid
|
|| (!(lastLane.valid && lane.valid
|
||||||
&& lastLane.indications == lane.indications))
|
&& lastLane.indications == lane.indications))
|
||||||
) {
|
) {
|
||||||
lanes.add(lane)
|
lanes.add(lane)
|
||||||
|
}
|
||||||
|
lastLane = lane
|
||||||
}
|
}
|
||||||
lastLane = lane
|
intersections.add(Intersection(waypoints[startIndex], lanes))
|
||||||
}
|
}
|
||||||
intersections.add(Intersection(waypoints[startIndex], lanes))
|
|
||||||
}
|
}
|
||||||
|
stepDistance =
|
||||||
|
route.guidance.instructions[index].routeOffsetInMeters - stepDistance
|
||||||
|
stepDuration =
|
||||||
|
route.guidance.instructions[index].travelTimeInSeconds - stepDuration
|
||||||
|
val step = Step(
|
||||||
|
index = stepIndex,
|
||||||
|
street = street,
|
||||||
|
distance = stepDistance,
|
||||||
|
duration = stepDuration,
|
||||||
|
maneuver = maneuver,
|
||||||
|
intersection = intersections,
|
||||||
|
countryCode = lastInstruction.countryCode
|
||||||
|
)
|
||||||
|
stepDistance = route.guidance.instructions[index].routeOffsetInMeters.toDouble()
|
||||||
|
stepDuration = route.guidance.instructions[index].travelTimeInSeconds.toDouble()
|
||||||
|
steps.add(step)
|
||||||
|
stepIndex += 1
|
||||||
}
|
}
|
||||||
stepDistance =
|
legs.add(Leg(steps, summary))
|
||||||
route.guidance.instructions[index].routeOffsetInMeters - stepDistance
|
|
||||||
stepDuration =
|
|
||||||
route.guidance.instructions[index].travelTimeInSeconds - stepDuration
|
|
||||||
val step = Step(
|
|
||||||
index = stepIndex,
|
|
||||||
street = street,
|
|
||||||
distance = stepDistance,
|
|
||||||
duration = stepDuration,
|
|
||||||
maneuver = maneuver,
|
|
||||||
intersection = intersections,
|
|
||||||
countryCode = lastInstruction.countryCode
|
|
||||||
)
|
|
||||||
stepDistance = route.guidance.instructions[index].routeOffsetInMeters.toDouble()
|
|
||||||
stepDuration = route.guidance.instructions[index].travelTimeInSeconds.toDouble()
|
|
||||||
steps.add(step)
|
|
||||||
stepIndex += 1
|
|
||||||
}
|
}
|
||||||
legs.add(Leg(steps))
|
|
||||||
val routeGeoJson = createLineStringCollection(waypoints)
|
val routeGeoJson = createLineStringCollection(waypoints)
|
||||||
val centerLocation = createCenterLocation(createLineStringCollection(waypoints))
|
val centerLocation = createCenterLocation(createLineStringCollection(waypoints))
|
||||||
val newRoute = com.kouros.navigation.data.route.Routes(
|
val newRoute = Routes(
|
||||||
legs,
|
legs,
|
||||||
summary,
|
summary,
|
||||||
routeGeoJson,
|
routeGeoJson,
|
||||||
@@ -130,75 +142,79 @@ class TomTomRoute {
|
|||||||
var newType = 0
|
var newType = 0
|
||||||
when (type) {
|
when (type) {
|
||||||
"DEPART" -> {
|
"DEPART" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_DEPART
|
newType = ManeuverType.TYPE_DEPART.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"ARRIVE" -> {
|
"ARRIVE" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_DESTINATION
|
newType = ManeuverType.TYPE_DESTINATION.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
"ARRIVE_LEFT" -> {
|
"ARRIVE_LEFT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_DESTINATION_LEFT
|
newType = ManeuverType.TYPE_DESTINATION_LEFT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"ARRIVE_RIGHT" -> {
|
"ARRIVE_RIGHT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_DESTINATION_RIGHT
|
newType = ManeuverType.TYPE_DESTINATION_RIGHT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"STRAIGHT", "FOLLOW" -> {
|
"STRAIGHT", "FOLLOW" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_STRAIGHT
|
newType = ManeuverType.TYPE_STRAIGHT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"KEEP_RIGHT" -> {
|
"KEEP_RIGHT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_KEEP_RIGHT
|
newType = ManeuverType.TYPE_KEEP_RIGHT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"BEAR_RIGHT" -> {
|
"BEAR_RIGHT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT
|
newType = ManeuverType.TYPE_TURN_SLIGHT_RIGHT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"BEAR_LEFT" -> {
|
"BEAR_LEFT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_LEFT
|
newType = ManeuverType.TYPE_TURN_SLIGHT_LEFT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"KEEP_LEFT" -> {
|
"KEEP_LEFT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_KEEP_LEFT
|
newType = ManeuverType.TYPE_KEEP_LEFT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"TURN_LEFT" -> {
|
"TURN_LEFT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_LEFT
|
newType = ManeuverType.TYPE_TURN_NORMAL_LEFT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"TURN_RIGHT" -> {
|
"TURN_RIGHT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_RIGHT
|
newType = ManeuverType.TYPE_TURN_NORMAL_RIGHT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"SHARP_LEFT" -> {
|
"SHARP_LEFT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SHARP_LEFT
|
newType = ManeuverType.TYPE_TURN_SHARP_LEFT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"SHARP_RIGHT" -> {
|
"SHARP_RIGHT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SHARP_RIGHT
|
newType = ManeuverType.TYPE_TURN_SHARP_RIGHT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"ROUNDABOUT_RIGHT", "ROUNDABOUT_CROSS" -> {
|
"ROUNDABOUT_RIGHT", "ROUNDABOUT_CROSS" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_ROUNDABOUT_ENTER_CCW
|
newType = ManeuverType.TYPE_ROUNDABOUT_ENTER_CCW.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"ROUNDABOUT_LEFT" -> {
|
"ROUNDABOUT_LEFT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_ROUNDABOUT_ENTER_CW
|
newType = ManeuverType.TYPE_ROUNDABOUT_ENTER_CW.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"MAKE_UTURN" -> {
|
"MAKE_UTURN", "TRY_MAKE_UTURN" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_U_TURN_LEFT
|
newType = ManeuverType.TYPE_U_TURN_LEFT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"ENTER_MOTORWAY" -> {
|
"ENTER_MOTORWAY" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_MERGE_LEFT
|
newType = ManeuverType.TYPE_MERGE_LEFT.ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
"TAKE_EXIT" -> {
|
"TAKE_EXIT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT
|
newType = ManeuverType.TYPE_TURN_SLIGHT_RIGHT.ordinal
|
||||||
|
}
|
||||||
|
"WAYPOINT_RIGHT" -> {
|
||||||
|
newType = ManeuverType.TYPE_WAYPOINT_RIGHT.ordinal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newType
|
return newType
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class ValhallaRepository : NavigationRepository() {
|
|||||||
override fun getRoute(
|
override fun getRoute(
|
||||||
context: Context,
|
context: Context,
|
||||||
currentLocation: Location,
|
currentLocation: Location,
|
||||||
location: Location,
|
location: List<Location>,
|
||||||
carOrientation: Float,
|
carOrientation: Float,
|
||||||
searchFilter: SearchFilter
|
searchFilter: SearchFilter
|
||||||
): String {
|
): String {
|
||||||
@@ -35,7 +35,7 @@ class ValhallaRepository : NavigationRepository() {
|
|||||||
lon = currentLocation.longitude,
|
lon = currentLocation.longitude,
|
||||||
searchFilter = exclude
|
searchFilter = exclude
|
||||||
),
|
),
|
||||||
Locations(lat = location.latitude, lon = location.longitude, searchFilter = exclude)
|
Locations(lat = location.first().latitude, lon = location.first().longitude, searchFilter = exclude)
|
||||||
)
|
)
|
||||||
val valhallaLocation = ValhallaLocation(
|
val valhallaLocation = ValhallaLocation(
|
||||||
locations = vLocation,
|
locations = vLocation,
|
||||||
|
|||||||
@@ -6,15 +6,12 @@ import android.graphics.BitmapFactory
|
|||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Matrix
|
import android.graphics.Matrix
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.car.app.model.CarIcon
|
|
||||||
import androidx.car.app.navigation.model.LaneDirection
|
import androidx.car.app.navigation.model.LaneDirection
|
||||||
import androidx.car.app.navigation.model.Maneuver
|
|
||||||
import androidx.core.graphics.createBitmap
|
import androidx.core.graphics.createBitmap
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import com.kouros.data.R
|
import com.kouros.data.R
|
||||||
import com.kouros.navigation.data.StepData
|
import com.kouros.navigation.data.StepData
|
||||||
import java.util.Collections
|
import com.kouros.navigation.data.route.ManeuverType
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class IconMapper {
|
class IconMapper {
|
||||||
@@ -22,62 +19,66 @@ class IconMapper {
|
|||||||
fun maneuverIcon(routeManeuverType: Int): Int {
|
fun maneuverIcon(routeManeuverType: Int): Int {
|
||||||
var currentTurnIcon = R.drawable.ic_turn_name_change
|
var currentTurnIcon = R.drawable.ic_turn_name_change
|
||||||
when (routeManeuverType) {
|
when (routeManeuverType) {
|
||||||
Maneuver.TYPE_STRAIGHT -> {
|
ManeuverType.TYPE_STRAIGHT.ordinal -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_name_change
|
currentTurnIcon = R.drawable.ic_turn_name_change
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_DESTINATION,
|
ManeuverType.TYPE_DESTINATION.ordinal,
|
||||||
Maneuver.TYPE_DESTINATION_RIGHT,
|
ManeuverType.TYPE_DESTINATION_RIGHT.ordinal,
|
||||||
Maneuver.TYPE_DESTINATION_LEFT,
|
ManeuverType.TYPE_DESTINATION_LEFT.ordinal,
|
||||||
Maneuver.TYPE_DESTINATION_STRAIGHT
|
ManeuverType.TYPE_DESTINATION_STRAIGHT.ordinal
|
||||||
-> {
|
-> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_destination
|
currentTurnIcon = R.drawable.ic_turn_destination
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_TURN_NORMAL_RIGHT -> {
|
ManeuverType.TYPE_TURN_NORMAL_RIGHT.ordinal -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_normal_right
|
currentTurnIcon = R.drawable.ic_turn_normal_right
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_TURN_NORMAL_LEFT -> {
|
ManeuverType.TYPE_TURN_NORMAL_LEFT.ordinal -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_normal_left
|
currentTurnIcon = R.drawable.ic_turn_normal_left
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_OFF_RAMP_SLIGHT_RIGHT -> {
|
ManeuverType.TYPE_OFF_RAMP_SLIGHT_RIGHT.ordinal -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_slight_right
|
currentTurnIcon = R.drawable.ic_turn_slight_right
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_TURN_SLIGHT_RIGHT -> {
|
ManeuverType.TYPE_TURN_SLIGHT_RIGHT.ordinal -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_slight_right
|
currentTurnIcon = R.drawable.ic_turn_slight_right
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_KEEP_RIGHT -> {
|
ManeuverType.TYPE_KEEP_RIGHT.ordinal -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_name_change
|
currentTurnIcon = R.drawable.ic_turn_name_change
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_KEEP_LEFT -> {
|
ManeuverType.TYPE_KEEP_LEFT.ordinal -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_name_change
|
currentTurnIcon = R.drawable.ic_turn_name_change
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_ROUNDABOUT_ENTER_CCW -> {
|
ManeuverType.TYPE_ROUNDABOUT_ENTER_CCW.ordinal -> {
|
||||||
currentTurnIcon = R.drawable.ic_roundabout_ccw
|
currentTurnIcon = R.drawable.ic_roundabout_ccw
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_ROUNDABOUT_EXIT_CCW -> {
|
ManeuverType.TYPE_ROUNDABOUT_EXIT_CCW.ordinal -> {
|
||||||
|
|
||||||
currentTurnIcon = R.drawable.ic_roundabout_ccw
|
currentTurnIcon = R.drawable.ic_roundabout_ccw
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_U_TURN_LEFT -> {
|
ManeuverType.TYPE_U_TURN_LEFT.ordinal -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_u_turn_left
|
currentTurnIcon = R.drawable.ic_turn_u_turn_left
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_U_TURN_RIGHT -> {
|
ManeuverType.TYPE_U_TURN_RIGHT.ordinal -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_u_turn_right
|
currentTurnIcon = R.drawable.ic_turn_u_turn_right
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_MERGE_LEFT -> {
|
ManeuverType.TYPE_MERGE_LEFT.ordinal -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_merge_symmetrical
|
currentTurnIcon = R.drawable.ic_turn_merge_symmetrical
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ManeuverType.TYPE_WAYPOINT_RIGHT.ordinal -> {
|
||||||
|
currentTurnIcon = R.drawable.ic_turn_destination
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return currentTurnIcon
|
return currentTurnIcon
|
||||||
}
|
}
|
||||||
@@ -86,8 +87,8 @@ class IconMapper {
|
|||||||
val laneDirection = when (direction.lowercase(Locale.getDefault())) {
|
val laneDirection = when (direction.lowercase(Locale.getDefault())) {
|
||||||
"left_straight" -> {
|
"left_straight" -> {
|
||||||
when (stepData.currentManeuverType) {
|
when (stepData.currentManeuverType) {
|
||||||
Maneuver.TYPE_TURN_NORMAL_LEFT -> LaneDirection.SHAPE_NORMAL_LEFT
|
ManeuverType.TYPE_TURN_NORMAL_LEFT.ordinal -> LaneDirection.SHAPE_NORMAL_LEFT
|
||||||
Maneuver.TYPE_STRAIGHT -> LaneDirection.SHAPE_STRAIGHT
|
ManeuverType.TYPE_STRAIGHT.ordinal -> LaneDirection.SHAPE_STRAIGHT
|
||||||
else
|
else
|
||||||
-> LaneDirection.SHAPE_UNKNOWN
|
-> LaneDirection.SHAPE_UNKNOWN
|
||||||
}
|
}
|
||||||
@@ -95,7 +96,7 @@ class IconMapper {
|
|||||||
|
|
||||||
"left" -> {
|
"left" -> {
|
||||||
when (stepData.currentManeuverType) {
|
when (stepData.currentManeuverType) {
|
||||||
Maneuver.TYPE_TURN_NORMAL_LEFT -> LaneDirection.SHAPE_NORMAL_LEFT
|
ManeuverType.TYPE_TURN_NORMAL_LEFT.ordinal -> LaneDirection.SHAPE_NORMAL_LEFT
|
||||||
else
|
else
|
||||||
-> LaneDirection.SHAPE_UNKNOWN
|
-> LaneDirection.SHAPE_UNKNOWN
|
||||||
}
|
}
|
||||||
@@ -103,9 +104,9 @@ class IconMapper {
|
|||||||
|
|
||||||
"straight" -> {
|
"straight" -> {
|
||||||
when (stepData.currentManeuverType) {
|
when (stepData.currentManeuverType) {
|
||||||
Maneuver.TYPE_STRAIGHT -> LaneDirection.SHAPE_STRAIGHT
|
ManeuverType.TYPE_STRAIGHT.ordinal -> LaneDirection.SHAPE_STRAIGHT
|
||||||
Maneuver.TYPE_KEEP_LEFT -> LaneDirection.SHAPE_STRAIGHT
|
ManeuverType.TYPE_KEEP_LEFT.ordinal -> LaneDirection.SHAPE_STRAIGHT
|
||||||
Maneuver.TYPE_KEEP_RIGHT -> LaneDirection.SHAPE_STRAIGHT
|
ManeuverType.TYPE_KEEP_RIGHT.ordinal -> LaneDirection.SHAPE_STRAIGHT
|
||||||
else
|
else
|
||||||
-> LaneDirection.SHAPE_UNKNOWN
|
-> LaneDirection.SHAPE_UNKNOWN
|
||||||
}
|
}
|
||||||
@@ -113,7 +114,7 @@ class IconMapper {
|
|||||||
|
|
||||||
"right" -> {
|
"right" -> {
|
||||||
when (stepData.currentManeuverType) {
|
when (stepData.currentManeuverType) {
|
||||||
Maneuver.TYPE_TURN_NORMAL_RIGHT -> LaneDirection.SHAPE_NORMAL_RIGHT
|
ManeuverType.TYPE_TURN_NORMAL_RIGHT.ordinal -> LaneDirection.SHAPE_NORMAL_RIGHT
|
||||||
else
|
else
|
||||||
-> LaneDirection.SHAPE_UNKNOWN
|
-> LaneDirection.SHAPE_UNKNOWN
|
||||||
}
|
}
|
||||||
@@ -121,8 +122,8 @@ class IconMapper {
|
|||||||
|
|
||||||
"right_straight" -> {
|
"right_straight" -> {
|
||||||
when (stepData.currentManeuverType) {
|
when (stepData.currentManeuverType) {
|
||||||
Maneuver.TYPE_TURN_NORMAL_RIGHT -> LaneDirection.SHAPE_NORMAL_RIGHT
|
ManeuverType.TYPE_TURN_NORMAL_RIGHT.ordinal -> LaneDirection.SHAPE_NORMAL_RIGHT
|
||||||
Maneuver.TYPE_STRAIGHT -> LaneDirection.SHAPE_STRAIGHT
|
ManeuverType.TYPE_STRAIGHT.ordinal -> LaneDirection.SHAPE_STRAIGHT
|
||||||
else
|
else
|
||||||
-> LaneDirection.SHAPE_UNKNOWN
|
-> LaneDirection.SHAPE_UNKNOWN
|
||||||
}
|
}
|
||||||
@@ -130,8 +131,8 @@ class IconMapper {
|
|||||||
|
|
||||||
"left_slight", "slight_left" -> {
|
"left_slight", "slight_left" -> {
|
||||||
when (stepData.currentManeuverType) {
|
when (stepData.currentManeuverType) {
|
||||||
Maneuver.TYPE_TURN_NORMAL_LEFT -> LaneDirection.SHAPE_SLIGHT_LEFT
|
ManeuverType.TYPE_TURN_NORMAL_LEFT.ordinal -> LaneDirection.SHAPE_SLIGHT_LEFT
|
||||||
Maneuver.TYPE_KEEP_LEFT -> LaneDirection.SHAPE_SLIGHT_LEFT
|
ManeuverType.TYPE_KEEP_LEFT.ordinal -> LaneDirection.SHAPE_SLIGHT_LEFT
|
||||||
else
|
else
|
||||||
-> LaneDirection.SHAPE_UNKNOWN
|
-> LaneDirection.SHAPE_UNKNOWN
|
||||||
}
|
}
|
||||||
@@ -139,8 +140,8 @@ class IconMapper {
|
|||||||
|
|
||||||
"right_slight", "slight_right" -> {
|
"right_slight", "slight_right" -> {
|
||||||
when (stepData.currentManeuverType) {
|
when (stepData.currentManeuverType) {
|
||||||
Maneuver.TYPE_TURN_SLIGHT_RIGHT -> LaneDirection.SHAPE_NORMAL_RIGHT
|
ManeuverType.TYPE_TURN_SLIGHT_RIGHT.ordinal -> LaneDirection.SHAPE_NORMAL_RIGHT
|
||||||
Maneuver.TYPE_KEEP_RIGHT -> LaneDirection.SHAPE_SLIGHT_RIGHT
|
ManeuverType.TYPE_KEEP_RIGHT.ordinal -> LaneDirection.SHAPE_SLIGHT_RIGHT
|
||||||
else
|
else
|
||||||
-> LaneDirection.SHAPE_UNKNOWN
|
-> LaneDirection.SHAPE_UNKNOWN
|
||||||
}
|
}
|
||||||
@@ -212,8 +213,8 @@ class IconMapper {
|
|||||||
return when (direction) {
|
return when (direction) {
|
||||||
"left_straight" -> {
|
"left_straight" -> {
|
||||||
when (stepData.currentManeuverType) {
|
when (stepData.currentManeuverType) {
|
||||||
Maneuver.TYPE_TURN_NORMAL_LEFT -> "left_o_straight_x"
|
ManeuverType.TYPE_TURN_NORMAL_LEFT.ordinal -> "left_o_straight_x"
|
||||||
Maneuver.TYPE_STRAIGHT -> "left_x_straight_o"
|
ManeuverType.TYPE_STRAIGHT.ordinal -> "left_x_straight_o"
|
||||||
else
|
else
|
||||||
-> "left_x_straight_x"
|
-> "left_x_straight_x"
|
||||||
}
|
}
|
||||||
@@ -221,29 +222,29 @@ class IconMapper {
|
|||||||
|
|
||||||
"right_straight" -> {
|
"right_straight" -> {
|
||||||
when (stepData.currentManeuverType) {
|
when (stepData.currentManeuverType) {
|
||||||
Maneuver.TYPE_TURN_NORMAL_RIGHT -> "right_x_straight_x"
|
ManeuverType.TYPE_TURN_NORMAL_RIGHT.ordinal -> "right_x_straight_x"
|
||||||
Maneuver.TYPE_STRAIGHT -> "right_x_straight_o"
|
ManeuverType.TYPE_STRAIGHT.ordinal -> "right_x_straight_o"
|
||||||
Maneuver.TYPE_TURN_SLIGHT_RIGHT -> "right_o_straight_o"
|
ManeuverType.TYPE_TURN_SLIGHT_RIGHT.ordinal -> "right_o_straight_o"
|
||||||
else
|
else
|
||||||
-> "right_x_straight_x"
|
-> "right_x_straight_x"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"right" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT) "${direction}_o" else "${direction}_x"
|
"right" -> if (stepData.currentManeuverType == ManeuverType.TYPE_TURN_NORMAL_RIGHT.ordinal) "${direction}_o" else "${direction}_x"
|
||||||
"left" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_LEFT) "${direction}_o" else "${direction}_x"
|
"left" -> if (stepData.currentManeuverType == ManeuverType.TYPE_TURN_NORMAL_LEFT.ordinal) "${direction}_o" else "${direction}_x"
|
||||||
"straight" -> if (stepData.currentManeuverType == Maneuver.TYPE_STRAIGHT
|
"straight" -> if (stepData.currentManeuverType == ManeuverType.TYPE_STRAIGHT.ordinal
|
||||||
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_LEFT
|
|| stepData.currentManeuverType == ManeuverType.TYPE_KEEP_LEFT.ordinal
|
||||||
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_RIGHT
|
|| stepData.currentManeuverType == ManeuverType.TYPE_KEEP_RIGHT.ordinal
|
||||||
) "${direction}_o" else "${direction}_x"
|
) "${direction}_o" else "${direction}_x"
|
||||||
|
|
||||||
"right_slight", "slight_right" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_SLIGHT_RIGHT
|
"right_slight", "slight_right" -> if (stepData.currentManeuverType == ManeuverType.TYPE_TURN_SLIGHT_RIGHT.ordinal
|
||||||
|| stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT
|
|| stepData.currentManeuverType == ManeuverType.TYPE_TURN_NORMAL_RIGHT.ordinal
|
||||||
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_RIGHT
|
|| stepData.currentManeuverType == ManeuverType.TYPE_KEEP_RIGHT.ordinal
|
||||||
) "slight_right_o" else "slight_right_x"
|
) "slight_right_o" else "slight_right_x"
|
||||||
|
|
||||||
"left_slight", "slight_left" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_SLIGHT_LEFT
|
"left_slight", "slight_left" -> if (stepData.currentManeuverType == ManeuverType.TYPE_TURN_SLIGHT_LEFT.ordinal
|
||||||
|| stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_LEFT
|
|| stepData.currentManeuverType == ManeuverType.TYPE_TURN_NORMAL_LEFT.ordinal
|
||||||
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_LEFT
|
|| stepData.currentManeuverType == ManeuverType.TYPE_KEEP_LEFT.ordinal
|
||||||
) "slight_left_o" else "slight_left_x"
|
) "slight_left_o" else "slight_left_x"
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.kouros.navigation.model
|
|||||||
//import com.kouros.navigation.data.Preferences.boxStore
|
//import com.kouros.navigation.data.Preferences.boxStore
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
|
import android.util.Log
|
||||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||||
import androidx.compose.runtime.toMutableStateList
|
import androidx.compose.runtime.toMutableStateList
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
@@ -147,7 +148,7 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
|||||||
fun loadRoute(
|
fun loadRoute(
|
||||||
context: Context,
|
context: Context,
|
||||||
currentLocation: Location,
|
currentLocation: Location,
|
||||||
destination: Location,
|
destination: List<Location>,
|
||||||
carOrientation: Float
|
carOrientation: Float
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
@@ -181,9 +182,11 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
|||||||
)
|
)
|
||||||
if (data.isNotEmpty()) {
|
if (data.isNotEmpty()) {
|
||||||
val trafficData = rebuildTraffic(data)
|
val trafficData = rebuildTraffic(data)
|
||||||
traffic.postValue(
|
if (trafficData.isNotEmpty()) {
|
||||||
trafficData
|
traffic.postValue(
|
||||||
)
|
trafficData
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
@@ -234,7 +237,7 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
|||||||
repository.getRoute(
|
repository.getRoute(
|
||||||
context,
|
context,
|
||||||
currentLocation,
|
currentLocation,
|
||||||
location,
|
listOf(location),
|
||||||
carOrientation,
|
carOrientation,
|
||||||
getSearchFilter(context)
|
getSearchFilter(context)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -102,6 +102,12 @@ class SettingsViewModel(private val repository: SettingsRepository) : ViewModel(
|
|||||||
0
|
0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val alternativeRoutes = repository.alternativeRoutesFlow.stateIn(
|
||||||
|
viewModelScope,
|
||||||
|
SharingStarted.WhileSubscribed(5_000),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
fun onShow3DChanged(enabled: Boolean) {
|
fun onShow3DChanged(enabled: Boolean) {
|
||||||
viewModelScope.launch { repository.setShow3D(enabled) }
|
viewModelScope.launch { repository.setShow3D(enabled) }
|
||||||
}
|
}
|
||||||
@@ -159,4 +165,7 @@ class SettingsViewModel(private val repository: SettingsRepository) : ViewModel(
|
|||||||
viewModelScope.launch { repository.setEngineType(mode) }
|
viewModelScope.launch { repository.setEngineType(mode) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onAlternativeRoutes(enabled: Boolean) {
|
||||||
|
viewModelScope.launch { repository.setAlternativeRoutes(enabled) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ class SettingsRepository(
|
|||||||
val engineTypeFlow: Flow<Int> =
|
val engineTypeFlow: Flow<Int> =
|
||||||
dataStoreManager.engineTypeFlow
|
dataStoreManager.engineTypeFlow
|
||||||
|
|
||||||
|
val alternativeRoutesFlow: Flow<Boolean> =
|
||||||
|
dataStoreManager.alternativeRoutesFlow
|
||||||
|
|
||||||
suspend fun setShow3D(enabled: Boolean) {
|
suspend fun setShow3D(enabled: Boolean) {
|
||||||
dataStoreManager.setShow3D(enabled)
|
dataStoreManager.setShow3D(enabled)
|
||||||
}
|
}
|
||||||
@@ -109,4 +112,8 @@ class SettingsRepository(
|
|||||||
suspend fun setEngineType(mode: Int) {
|
suspend fun setEngineType(mode: Int) {
|
||||||
dataStoreManager.setEngineType(mode)
|
dataStoreManager.setEngineType(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun setAlternativeRoutes(enabled: Boolean) {
|
||||||
|
dataStoreManager.setAlternativeRoutes(enabled)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,4 +71,5 @@
|
|||||||
<string name="combustion">Combustion</string>
|
<string name="combustion">Combustion</string>
|
||||||
<string name="electric">Electric</string>
|
<string name="electric">Electric</string>
|
||||||
<string name="engine_type">Engine type</string>
|
<string name="engine_type">Engine type</string>
|
||||||
|
<string name="alternative_routes">Alternative routes</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -55,4 +55,5 @@
|
|||||||
<string name="combustion">Combustion</string>
|
<string name="combustion">Combustion</string>
|
||||||
<string name="electric">Electric</string>
|
<string name="electric">Electric</string>
|
||||||
<string name="engine_type">Engine type</string>
|
<string name="engine_type">Engine type</string>
|
||||||
|
<string name="alternative_routes">Alternative routes</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -55,4 +55,5 @@
|
|||||||
<string name="combustion">Combustion</string>
|
<string name="combustion">Combustion</string>
|
||||||
<string name="electric">Electric</string>
|
<string name="electric">Electric</string>
|
||||||
<string name="engine_type">Engine type</string>
|
<string name="engine_type">Engine type</string>
|
||||||
|
<string name="alternative_routes">Alternative routes</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -58,4 +58,5 @@
|
|||||||
<string name="combustion">Combustion</string>
|
<string name="combustion">Combustion</string>
|
||||||
<string name="electric">Electric</string>
|
<string name="electric">Electric</string>
|
||||||
<string name="engine_type">Engine type</string>
|
<string name="engine_type">Engine type</string>
|
||||||
|
<string name="alternative_routes">Alternative routes</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -55,8 +55,8 @@ class RouteCalculatorTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRoute(steps: List<Step>, currentStepIndex: Int = 0): Route {
|
private fun setupRoute(steps: List<Step>, currentStepIndex: Int = 0, summary: Summary): Route {
|
||||||
val leg = Leg(steps = steps)
|
val leg = Leg(steps = steps, summary)
|
||||||
val routes = Routes(
|
val routes = Routes(
|
||||||
legs = listOf(leg),
|
legs = listOf(leg),
|
||||||
summary = Summary(),
|
summary = Summary(),
|
||||||
@@ -74,7 +74,7 @@ class RouteCalculatorTest {
|
|||||||
fun `findStep updates currentStepIndex to step containing the nearest waypoint`() {
|
fun `findStep updates currentStepIndex to step containing the nearest waypoint`() {
|
||||||
val step0 = createStep(index = 0, numWaypoints = 2)
|
val step0 = createStep(index = 0, numWaypoints = 2)
|
||||||
val step1 = createStep(index = 1, numWaypoints = 2)
|
val step1 = createStep(index = 1, numWaypoints = 2)
|
||||||
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0, step1)))
|
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0, step1), summary = Summary()))
|
||||||
|
|
||||||
val mockLocation: Location = mock()
|
val mockLocation: Location = mock()
|
||||||
// step0/wp0: 500F, step0/wp1: 400F, step1/wp0: 300F, step1/wp1: 8F
|
// step0/wp0: 500F, step0/wp1: 400F, step1/wp0: 300F, step1/wp1: 8F
|
||||||
@@ -88,7 +88,7 @@ class RouteCalculatorTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `findStep updates waypointIndex to the nearest waypoint within the step`() {
|
fun `findStep updates waypointIndex to the nearest waypoint within the step`() {
|
||||||
val step0 = createStep(index = 0, numWaypoints = 3)
|
val step0 = createStep(index = 0, numWaypoints = 3)
|
||||||
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0)))
|
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0), summary = Summary()))
|
||||||
|
|
||||||
val mockLocation: Location = mock()
|
val mockLocation: Location = mock()
|
||||||
// wp0: 100F, wp1: 30F (nearest), wp2: 80F
|
// wp0: 100F, wp1: 30F (nearest), wp2: 80F
|
||||||
@@ -104,7 +104,7 @@ class RouteCalculatorTest {
|
|||||||
val step0 = createStep(index = 0, numWaypoints = 2)
|
val step0 = createStep(index = 0, numWaypoints = 2)
|
||||||
val step1 = createStep(index = 1, numWaypoints = 2)
|
val step1 = createStep(index = 1, numWaypoints = 2)
|
||||||
routeModel.navState = routeModel.navState.copy(
|
routeModel.navState = routeModel.navState.copy(
|
||||||
route = setupRoute(listOf(step0, step1), currentStepIndex = 1)
|
route = setupRoute(listOf(step0, step1), currentStepIndex = 1, summary = Summary())
|
||||||
)
|
)
|
||||||
|
|
||||||
val mockLocation: Location = mock()
|
val mockLocation: Location = mock()
|
||||||
@@ -123,7 +123,7 @@ class RouteCalculatorTest {
|
|||||||
val step1 = createStep(index = 1, numWaypoints = 2)
|
val step1 = createStep(index = 1, numWaypoints = 2)
|
||||||
val step2 = createStep(index = 2, numWaypoints = 2)
|
val step2 = createStep(index = 2, numWaypoints = 2)
|
||||||
routeModel.navState = routeModel.navState.copy(
|
routeModel.navState = routeModel.navState.copy(
|
||||||
route = setupRoute(listOf(step0, step1, step2))
|
route = setupRoute(listOf(step0, step1, step2), summary = Summary())
|
||||||
)
|
)
|
||||||
|
|
||||||
val mockLocation: Location = mock()
|
val mockLocation: Location = mock()
|
||||||
@@ -147,7 +147,7 @@ class RouteCalculatorTest {
|
|||||||
val step0 = createStep(index = 0, numWaypoints = 2, duration = 60.0, waypointIndex = 0)
|
val step0 = createStep(index = 0, numWaypoints = 2, duration = 60.0, waypointIndex = 0)
|
||||||
val step1 = createStep(index = 1, numWaypoints = 2, duration = 120.0)
|
val step1 = createStep(index = 1, numWaypoints = 2, duration = 120.0)
|
||||||
val step2 = createStep(index = 2, numWaypoints = 2, duration = 90.0)
|
val step2 = createStep(index = 2, numWaypoints = 2, duration = 90.0)
|
||||||
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0, step1, step2)))
|
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0, step1, step2), summary = Summary()))
|
||||||
|
|
||||||
val result = routeCalculator.travelLeftTime()
|
val result = routeCalculator.travelLeftTime()
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ class RouteCalculatorTest {
|
|||||||
// waypointIndex=2, waypoints=4 → percent = 100*(4-2)/4 = 50 → time = 80*50/100 = 40s
|
// waypointIndex=2, waypoints=4 → percent = 100*(4-2)/4 = 50 → time = 80*50/100 = 40s
|
||||||
val step0 = createStep(index = 0, numWaypoints = 4, duration = 80.0, waypointIndex = 2)
|
val step0 = createStep(index = 0, numWaypoints = 4, duration = 80.0, waypointIndex = 2)
|
||||||
val step1 = createStep(index = 1, numWaypoints = 2, duration = 40.0)
|
val step1 = createStep(index = 1, numWaypoints = 2, duration = 40.0)
|
||||||
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0, step1)))
|
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0, step1), summary = Summary()))
|
||||||
|
|
||||||
val result = routeCalculator.travelLeftTime()
|
val result = routeCalculator.travelLeftTime()
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ class RouteCalculatorTest {
|
|||||||
fun `travelLeftTime returns only future steps when at last step`() {
|
fun `travelLeftTime returns only future steps when at last step`() {
|
||||||
val step0 = createStep(index = 0, numWaypoints = 2, duration = 60.0, waypointIndex = 1)
|
val step0 = createStep(index = 0, numWaypoints = 2, duration = 60.0, waypointIndex = 1)
|
||||||
routeModel.navState = routeModel.navState.copy(
|
routeModel.navState = routeModel.navState.copy(
|
||||||
route = setupRoute(listOf(step0), currentStepIndex = 0)
|
route = setupRoute(listOf(step0), currentStepIndex = 0, summary = Summary())
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = routeCalculator.travelLeftTime()
|
val result = routeCalculator.travelLeftTime()
|
||||||
@@ -189,7 +189,7 @@ class RouteCalculatorTest {
|
|||||||
fun `leftStepDistance returns 0 when waypointIndex is at the last position`() {
|
fun `leftStepDistance returns 0 when waypointIndex is at the last position`() {
|
||||||
// Loop range: waypointIndex..<waypoints.size-1 = 2..<2, which is empty
|
// Loop range: waypointIndex..<waypoints.size-1 = 2..<2, which is empty
|
||||||
val step0 = createStep(index = 0, numWaypoints = 3, waypointIndex = 2)
|
val step0 = createStep(index = 0, numWaypoints = 3, waypointIndex = 2)
|
||||||
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0)))
|
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0), summary = Summary()))
|
||||||
|
|
||||||
val result = routeCalculator.leftStepDistance()
|
val result = routeCalculator.leftStepDistance()
|
||||||
|
|
||||||
@@ -206,7 +206,7 @@ class RouteCalculatorTest {
|
|||||||
val step0 = createStep(index = 0, numWaypoints = 2, distance = 100.0, waypointIndex = 1)
|
val step0 = createStep(index = 0, numWaypoints = 2, distance = 100.0, waypointIndex = 1)
|
||||||
val step1 = createStep(index = 1, numWaypoints = 2, distance = 200.0)
|
val step1 = createStep(index = 1, numWaypoints = 2, distance = 200.0)
|
||||||
val step2 = createStep(index = 2, numWaypoints = 2, distance = 150.0)
|
val step2 = createStep(index = 2, numWaypoints = 2, distance = 150.0)
|
||||||
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0, step1, step2)))
|
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0, step1, step2), summary = Summary()))
|
||||||
|
|
||||||
val result = routeCalculator.travelLeftDistance()
|
val result = routeCalculator.travelLeftDistance()
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ class RouteCalculatorTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `travelLeftDistance returns 0 when on last step at last waypoint`() {
|
fun `travelLeftDistance returns 0 when on last step at last waypoint`() {
|
||||||
val step0 = createStep(index = 0, numWaypoints = 2, distance = 200.0, waypointIndex = 1)
|
val step0 = createStep(index = 0, numWaypoints = 2, distance = 200.0, waypointIndex = 1)
|
||||||
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0)))
|
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0), summary = Summary()))
|
||||||
|
|
||||||
val result = routeCalculator.travelLeftDistance()
|
val result = routeCalculator.travelLeftDistance()
|
||||||
|
|
||||||
@@ -232,7 +232,8 @@ class RouteCalculatorTest {
|
|||||||
fun `arrivalTime returns a timestamp roughly travelLeftTime seconds in the future`() {
|
fun `arrivalTime returns a timestamp roughly travelLeftTime seconds in the future`() {
|
||||||
// step0: 2 waypoints at wp0 → 100% of 3600s duration
|
// step0: 2 waypoints at wp0 → 100% of 3600s duration
|
||||||
val step0 = createStep(index = 0, numWaypoints = 2, duration = 3600.0, waypointIndex = 0)
|
val step0 = createStep(index = 0, numWaypoints = 2, duration = 3600.0, waypointIndex = 0)
|
||||||
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0)))
|
val summary = Summary(duration = 3600.0)
|
||||||
|
routeModel.navState = routeModel.navState.copy(route = setupRoute(listOf(step0), summary = summary))
|
||||||
|
|
||||||
val before = System.currentTimeMillis()
|
val before = System.currentTimeMillis()
|
||||||
val result = routeCalculator.arrivalTime()
|
val result = routeCalculator.arrivalTime()
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class RouteModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRoute(steps: List<Step>, currentStepIndex: Int = 0): Route {
|
private fun setupRoute(steps: List<Step>, currentStepIndex: Int = 0): Route {
|
||||||
val leg = Leg(steps = steps)
|
val leg = Leg(steps = steps, summary = Summary())
|
||||||
val routes = Routes(
|
val routes = Routes(
|
||||||
legs = listOf(leg),
|
legs = listOf(leg),
|
||||||
summary = Summary(),
|
summary = Summary(),
|
||||||
|
|||||||
Reference in New Issue
Block a user