Audio guidance
This commit is contained in:
@@ -13,8 +13,8 @@ android {
|
||||
applicationId = "com.kouros.navigation"
|
||||
minSdk = 33
|
||||
targetSdk = 36
|
||||
versionCode = 59
|
||||
versionName = "0.2.0.59"
|
||||
versionCode = 60
|
||||
versionName = "0.2.0.60"
|
||||
base.archivesName = "navi-$versionName"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import android.app.AppOpsManager
|
||||
import android.location.LocationManager
|
||||
import android.os.Bundle
|
||||
import android.os.Process
|
||||
import android.speech.tts.TextToSpeech
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
@@ -81,13 +83,14 @@ import org.maplibre.compose.location.Location
|
||||
import org.maplibre.compose.location.rememberDefaultLocationProvider
|
||||
import org.maplibre.compose.location.rememberUserLocationState
|
||||
import org.maplibre.spatialk.geojson.Position
|
||||
import java.util.Locale
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
val routeData = MutableLiveData("")
|
||||
val routeModel = RouteModel()
|
||||
var tilt = TILT
|
||||
var tilt = TILT
|
||||
val useMock = false
|
||||
val type = SimulationType.SIMULATE
|
||||
val stepData: MutableLiveData<StepData> by lazy {
|
||||
@@ -97,29 +100,38 @@ class MainActivity : ComponentActivity() {
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
var lastStepIndex = -1
|
||||
var lastLocation = location(0.0, 0.0)
|
||||
val observer = Observer<String> { newRoute ->
|
||||
if (newRoute.isNotEmpty()) {
|
||||
val repository = getSettingsRepository(applicationContext)
|
||||
val routingEngine = runBlocking { repository.routingEngineFlow.first() }
|
||||
val routingEngine = runBlocking { repository.routingEngineFlow.first() }
|
||||
routeModel.navState = routeModel.navState.copy(routingEngine = routingEngine)
|
||||
routeModel.startNavigation(newRoute)
|
||||
if (routeModel.hasLegs()) {
|
||||
getSettingsViewModel(applicationContext).onLastRouteChanged(newRoute)
|
||||
}
|
||||
routeData.value = routeModel.curRoute.routeGeoJson
|
||||
if (useMock) {
|
||||
when (type) {
|
||||
SimulationType.SIMULATE -> simulate(routeModel, mock)
|
||||
SimulationType.TEST -> test(applicationContext, routeModel)
|
||||
SimulationType.GPX -> gpx(
|
||||
context = applicationContext, mock
|
||||
)
|
||||
SimulationType.TEST_SINGLE -> testSingle(applicationContext, routeModel, mock)
|
||||
}
|
||||
checkMock()
|
||||
}
|
||||
}
|
||||
|
||||
lateinit var textToSpeech: TextToSpeech
|
||||
|
||||
private fun checkMock() {
|
||||
if (useMock) {
|
||||
when (type) {
|
||||
SimulationType.SIMULATE -> simulate(routeModel, mock)
|
||||
SimulationType.TEST -> test(applicationContext, routeModel)
|
||||
SimulationType.GPX -> gpx(
|
||||
context = applicationContext, mock
|
||||
)
|
||||
|
||||
SimulationType.TEST_SINGLE -> testSingle(applicationContext, routeModel, mock)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val cameraPosition = MutableLiveData(
|
||||
CameraPosition(
|
||||
zoom = 15.0, target = Position(latitude = 48.1857475, longitude = 11.5793627)
|
||||
@@ -135,6 +147,12 @@ class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
textToSpeech = TextToSpeech(applicationContext) { status ->
|
||||
if (status == TextToSpeech.SUCCESS) {
|
||||
textToSpeech.language = Locale.getDefault()
|
||||
}
|
||||
}
|
||||
|
||||
if (useMock) {
|
||||
checkMockLocationEnabled()
|
||||
}
|
||||
@@ -195,8 +213,10 @@ class MainActivity : ComponentActivity() {
|
||||
updateInterval = 0.5.seconds, desiredAccuracy = DesiredAccuracy.Highest
|
||||
)
|
||||
val userLocationState = rememberUserLocationState(locationProvider)
|
||||
val locationState = locationProvider.location.collectAsState()
|
||||
updateLocation(locationState.value)
|
||||
if (!useMock) {
|
||||
val locationState = locationProvider.location.collectAsState()
|
||||
updateLocation(locationState.value)
|
||||
}
|
||||
val step: StepData? by stepData.observeAsState()
|
||||
val nextStep: StepData? by nextStepData.observeAsState()
|
||||
fun closeSheet() {
|
||||
@@ -210,7 +230,7 @@ class MainActivity : ComponentActivity() {
|
||||
snackbarHost = {
|
||||
SnackbarHost(hostState = snackbarHostState)
|
||||
},
|
||||
scaffoldState = scaffoldState,
|
||||
scaffoldState = scaffoldState,
|
||||
sheetPeekHeight = sheetPeekHeightState.value,
|
||||
sheetContent = {
|
||||
SheetContent(step, nextStep) { closeSheet() }
|
||||
@@ -317,8 +337,9 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
with(routeModel) {
|
||||
if (isNavigating()) {
|
||||
updateLocation( currentLocation, navigationViewModel)
|
||||
updateLocation(currentLocation, navigationViewModel)
|
||||
stepData.value = currentStep()
|
||||
//textToSpeech(stepData.value!!.instruction)
|
||||
if (navState.nextStep) {
|
||||
nextStepData.value = nextStep()
|
||||
}
|
||||
@@ -353,7 +374,24 @@ class MainActivity : ComponentActivity() {
|
||||
mock.setMockLocation(latitude, longitude, 0F)
|
||||
}
|
||||
routeData.value = ""
|
||||
stepData.value = StepData("", "",0.0, 0, 0, 0, 0.0)
|
||||
stepData.value = StepData("", "", 0.0, 0, 0, 0, 0.0)
|
||||
}
|
||||
|
||||
fun textToSpeech(text: String) {
|
||||
val currentStep = routeModel.route.currentStep()
|
||||
val stepData = routeModel.currentStep()
|
||||
if (currentStep.index > lastStepIndex && stepData.leftStepDistance < 50) {
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val cs: CharSequence = stepData.instruction
|
||||
textToSpeech.speak(cs, TextToSpeech.QUEUE_FLUSH, null, "1233455")
|
||||
Log.d("TTS", "speak $cs")
|
||||
} catch (e: Throwable) {
|
||||
Log.d("TTS", "speak error", e)
|
||||
}
|
||||
}
|
||||
lastStepIndex = currentStep.index
|
||||
}
|
||||
}
|
||||
|
||||
fun simulateNavigation() {
|
||||
|
||||
@@ -179,9 +179,12 @@ class RouteModelTest {
|
||||
val curLocation = location(waypoint[0], waypoint[1])
|
||||
if (routeModel.isNavigating()) {
|
||||
if (index in 0..routeModel.curRoute.waypoints.size) {
|
||||
routeModel.updateLocation(curLocation, NavigationViewModel(TomTomRepository()))
|
||||
//runBlocking { delay(1000) }
|
||||
val start = System.currentTimeMillis()
|
||||
routeModel.updateLocation(curLocation, NavigationViewModel(TomTomRepository()))
|
||||
val stepData = routeModel.currentStep()
|
||||
val nextData = routeModel.nextStep()
|
||||
println("${stepData.instruction} ${System.currentTimeMillis() - start}")
|
||||
// val nextData = routeModel.nextStep()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.Manifest.permission
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.location.Location
|
||||
import android.speech.tts.TextToSpeech
|
||||
import android.util.Log
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.Screen
|
||||
@@ -16,9 +17,12 @@ import androidx.car.app.navigation.model.Trip
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelStore
|
||||
import androidx.lifecycle.ViewModelStoreOwner
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.kouros.navigation.car.navigation.NavigationUtils
|
||||
import com.kouros.navigation.car.navigation.RouteCarModel
|
||||
import com.kouros.navigation.car.screen.NavigationScreen
|
||||
import com.kouros.navigation.car.screen.RequestPermissionScreen
|
||||
@@ -35,8 +39,11 @@ import com.kouros.navigation.data.valhalla.ValhallaRepository
|
||||
import com.kouros.navigation.model.NavigationViewModel
|
||||
import com.kouros.navigation.utils.GeoUtils.snapLocation
|
||||
import com.kouros.navigation.utils.NavigationUtils.getViewModel
|
||||
import com.kouros.navigation.utils.getSettingsRepository
|
||||
import kotlinx.coroutines.awaitCancellation
|
||||
import kotlinx.coroutines.launch
|
||||
import org.maplibre.compose.expressions.dsl.step
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
/**
|
||||
@@ -67,6 +74,8 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
|
||||
lateinit var navigationManager: NavigationManager
|
||||
|
||||
lateinit var textToSpeechManager: TextToSpeechManager
|
||||
|
||||
/**
|
||||
* Lifecycle observer for managing session lifecycle events.
|
||||
* Cleans up resources when the session is destroyed.
|
||||
@@ -82,6 +91,9 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
if (::deviceLocationManager.isInitialized) {
|
||||
deviceLocationManager.stopLocationUpdates()
|
||||
}
|
||||
if (::textToSpeechManager.isInitialized) {
|
||||
textToSpeechManager.cleanup()
|
||||
}
|
||||
Log.i(TAG, "NavigationSession destroyed")
|
||||
}
|
||||
}
|
||||
@@ -92,6 +104,10 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
// Store for ViewModels to survive configuration changes
|
||||
lateinit var viewModelStoreOwner: ViewModelStoreOwner
|
||||
|
||||
var lastStepIndex = -1
|
||||
|
||||
var guidanceAudio = 0
|
||||
|
||||
init {
|
||||
lifecycle.addObserver(lifecycleObserver)
|
||||
}
|
||||
@@ -130,6 +146,7 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
CarConnection.CONNECTION_TYPE_NATIVE -> {
|
||||
navigationScreen.checkPermission(AUTOMOTIVE_CAR_SPEED_PERMISSION)
|
||||
}
|
||||
|
||||
CarConnection.CONNECTION_TYPE_PROJECTION -> {
|
||||
navigationScreen.checkPermission(GMS_CAR_SPEED_PERMISSION)
|
||||
}
|
||||
@@ -221,6 +238,12 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
textToSpeechManager = TextToSpeechManager(carContext)
|
||||
val repository = getSettingsRepository(carContext)
|
||||
repository.guidanceAudioFlow.asLiveData().observe(this, Observer {
|
||||
guidanceAudio = it
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,7 +342,6 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
*/
|
||||
fun updateLocation(location: Location) {
|
||||
updateBearing(location)
|
||||
|
||||
if (routeModel.isNavigating()) {
|
||||
handleNavigationLocation(location)
|
||||
} else {
|
||||
@@ -341,6 +363,9 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
* Snaps location to route and checks for deviation requiring reroute.
|
||||
*/
|
||||
private fun handleNavigationLocation(location: Location) {
|
||||
if (guidanceAudio == 1) {
|
||||
handleGuidanceAudio()
|
||||
}
|
||||
navigationScreen.updateTrip(location)
|
||||
if (routeModel.navState.arrived) return
|
||||
val snappedLocation = snapLocation(location, routeModel.route.maneuverLocations())
|
||||
@@ -349,11 +374,9 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
distance > MAXIMAL_ROUTE_DEVIATION -> {
|
||||
navigationScreen.calculateNewRoute(routeModel.navState.destination)
|
||||
}
|
||||
|
||||
distance < MAXIMAL_SNAP_CORRECTION -> {
|
||||
surfaceRenderer.updateLocation(snappedLocation)
|
||||
}
|
||||
|
||||
else -> {
|
||||
surfaceRenderer.updateLocation(location)
|
||||
}
|
||||
@@ -382,6 +405,21 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
navigationManager.updateTrip(trip)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle guidance audio
|
||||
* Called when user wants to hear the step by step instructions
|
||||
*/
|
||||
private fun handleGuidanceAudio() {
|
||||
val currentStep = routeModel.route.currentStep()
|
||||
val stepData = routeModel.currentStep()
|
||||
if (currentStep.index > lastStepIndex && stepData.leftStepDistance < 50) {
|
||||
if (textToSpeechManager.initialized) {
|
||||
textToSpeechManager.speak(stepData.message)
|
||||
}
|
||||
lastStepIndex = currentStep.index
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
// URI host for deep linking
|
||||
var uriHost: String = "navigation"
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.kouros.navigation.car
|
||||
|
||||
import android.media.AudioAttributes
|
||||
import android.media.AudioFocusRequest
|
||||
import android.media.AudioManager
|
||||
import android.speech.tts.TextToSpeech
|
||||
import android.util.Log
|
||||
import androidx.car.app.CarContext
|
||||
import java.util.Locale
|
||||
|
||||
class TextToSpeechManager(private val carContext: CarContext) {
|
||||
|
||||
var textToSpeech: TextToSpeech
|
||||
|
||||
var initialized = false
|
||||
|
||||
init {
|
||||
textToSpeech = TextToSpeech(carContext) { status ->
|
||||
if (status == TextToSpeech.SUCCESS) {
|
||||
Log.d("TTS", "Initialization Success")
|
||||
val audioAttributes =
|
||||
AudioAttributes.Builder()
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
|
||||
.setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
|
||||
.build()
|
||||
val request =
|
||||
AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
|
||||
.setAudioAttributes(audioAttributes)
|
||||
.build()
|
||||
val audioManager: AudioManager =
|
||||
carContext.getSystemService<AudioManager?>(AudioManager::class.java)!!
|
||||
// Requesting the audio focus.
|
||||
if (audioManager.requestAudioFocus(request) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||
textToSpeech.setAudioAttributes(audioAttributes)
|
||||
}
|
||||
initialized = true
|
||||
} else {
|
||||
Log.d("TTS", "Initialization Failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun speak(text: String) {
|
||||
try {
|
||||
val cs: CharSequence = text
|
||||
textToSpeech.speak(cs, TextToSpeech.QUEUE_FLUSH, null, "1233455")
|
||||
} catch (e: Throwable) {
|
||||
Log.d("TTS", "speak error", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up manager.
|
||||
* Should be called when the session is destroyed.
|
||||
*/
|
||||
fun cleanup() {
|
||||
if (initialized) {
|
||||
textToSpeech.shutdown()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,27 @@
|
||||
package com.kouros.navigation.car.navigation
|
||||
|
||||
import android.media.AudioAttributes
|
||||
import android.media.AudioFocusRequest
|
||||
import android.media.AudioManager
|
||||
import android.media.MediaPlayer
|
||||
import android.media.MediaPlayer.OnCompletionListener
|
||||
import android.speech.tts.TextToSpeech
|
||||
import android.util.Log
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.RawRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.CarToast
|
||||
import androidx.car.app.model.Action
|
||||
import androidx.car.app.model.Alert
|
||||
import androidx.car.app.model.AlertCallback
|
||||
import androidx.car.app.model.CarIcon
|
||||
import androidx.car.app.model.CarText
|
||||
import androidx.car.app.model.OnClickListener
|
||||
import androidx.car.app.model.Row
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import com.kouros.android.cars.carappservice.R
|
||||
import com.kouros.navigation.data.Constants.TAG
|
||||
import java.io.IOException
|
||||
import java.util.Locale
|
||||
|
||||
class NavigationMessage (private var carContext: CarContext) {
|
||||
class NavigationUtils(private var carContext: CarContext) {
|
||||
|
||||
private fun createToastAction(
|
||||
@StringRes titleRes: Int, @StringRes toastStringRes: Int,
|
||||
@@ -35,6 +43,7 @@ class NavigationMessage (private var carContext: CarContext) {
|
||||
)
|
||||
.show()
|
||||
}
|
||||
|
||||
fun createCarText(@StringRes stringRes: Int): CarText {
|
||||
return CarText.create(carContext.getString(stringRes))
|
||||
}
|
||||
@@ -42,4 +51,19 @@ class NavigationMessage (private var carContext: CarContext) {
|
||||
fun createCarIcon(@DrawableRes iconRes: Int): CarIcon {
|
||||
return CarIcon.Builder(IconCompat.createWithResource(carContext, iconRes)).build()
|
||||
}
|
||||
|
||||
fun buildRowForTemplate(title: Int, resource: Int): Row {
|
||||
return Row.Builder()
|
||||
.setTitle(carContext.getString(title))
|
||||
.setImage(
|
||||
CarIcon.Builder(
|
||||
IconCompat.createWithResource(
|
||||
carContext,
|
||||
resource
|
||||
)
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.kouros.navigation.car.navigation
|
||||
|
||||
import android.speech.tts.TextToSpeech
|
||||
import android.text.SpannableString
|
||||
import android.util.Log
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.car.app.AppManager
|
||||
@@ -26,15 +28,18 @@ import com.kouros.data.R
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.model.RouteModel
|
||||
import com.kouros.navigation.utils.formattedDistance
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/** A class that provides models for the routing demos. */
|
||||
class RouteCarModel() : RouteModel() {
|
||||
class RouteCarModel : RouteModel() {
|
||||
|
||||
/** Returns the current [Step] with information such as the cue text and images. */
|
||||
fun currentStep(carContext: CarContext): Step {
|
||||
|
||||
val stepData = currentStep()
|
||||
|
||||
val currentStepCueWithImage: SpannableString =
|
||||
createString(stepData.instruction)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import androidx.car.app.navigation.model.MapWithContentTemplate
|
||||
import androidx.lifecycle.Observer
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
import com.kouros.navigation.car.navigation.NavigationMessage
|
||||
import com.kouros.navigation.car.navigation.NavigationUtils
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.overpass.Elements
|
||||
@@ -124,7 +124,7 @@ class CategoryScreen(
|
||||
} else {
|
||||
row.addText(carText("${it.tags.openingHours}"))
|
||||
}
|
||||
val navigationMessage = NavigationMessage(carContext)
|
||||
val navigationUtils = NavigationUtils(carContext)
|
||||
row.addAction(
|
||||
Action.Builder()
|
||||
.setOnClickListener {
|
||||
@@ -144,7 +144,7 @@ class CategoryScreen(
|
||||
)
|
||||
finish()
|
||||
}
|
||||
.setIcon(navigationMessage.createCarIcon(R.drawable.navigation_48px))
|
||||
.setIcon(navigationUtils.createCarIcon(R.drawable.navigation_48px))
|
||||
.build())
|
||||
return row.build()
|
||||
}
|
||||
@@ -180,10 +180,10 @@ class CategoryScreen(
|
||||
@DrawableRes iconRes: Int,
|
||||
scale: Int
|
||||
): Action {
|
||||
val navigationMessage = NavigationMessage(carContext)
|
||||
val navigationUtils = NavigationUtils(carContext)
|
||||
return Action.Builder()
|
||||
.setOnClickListener { surfaceRenderer.handleScale(scale) }
|
||||
.setIcon(navigationMessage.createCarIcon(iconRes))
|
||||
.setIcon(navigationUtils.createCarIcon(iconRes))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.kouros.navigation.car.ViewStyle
|
||||
import com.kouros.navigation.car.navigation.RouteCarModel
|
||||
import com.kouros.navigation.car.screen.observers.NavigationObserverCallback
|
||||
import com.kouros.navigation.car.screen.observers.NavigationObserverManager
|
||||
import com.kouros.navigation.car.screen.settings.SettingsScreen
|
||||
import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.overpass.Elements
|
||||
|
||||
@@ -16,7 +16,6 @@ import androidx.car.app.model.Header
|
||||
import androidx.car.app.model.ItemList
|
||||
import androidx.car.app.model.ListTemplate
|
||||
import androidx.car.app.model.MessageTemplate
|
||||
import androidx.car.app.model.OnClickListener
|
||||
import androidx.car.app.model.Row
|
||||
import androidx.car.app.model.Template
|
||||
import androidx.car.app.navigation.model.MapController
|
||||
@@ -25,12 +24,11 @@ import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
import com.kouros.navigation.car.navigation.NavigationMessage
|
||||
import com.kouros.navigation.car.navigation.NavigationUtils
|
||||
import com.kouros.navigation.car.navigation.RouteCarModel
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.model.NavigationViewModel
|
||||
import com.kouros.navigation.utils.getSettingsRepository
|
||||
import com.kouros.navigation.utils.getSettingsViewModel
|
||||
import com.kouros.navigation.utils.location
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@@ -49,7 +47,7 @@ class RoutePreviewScreen(
|
||||
|
||||
val routeModel = RouteCarModel()
|
||||
|
||||
val navigationMessage = NavigationMessage(carContext)
|
||||
val navigationUtils = NavigationUtils(carContext)
|
||||
val observer = Observer<String> { route ->
|
||||
if (route.isNotEmpty()) {
|
||||
val repository = getSettingsRepository(carContext)
|
||||
@@ -228,8 +226,6 @@ class RoutePreviewScreen(
|
||||
private fun onRouteSelected(index: Int) {
|
||||
routeModel.navState = routeModel.navState.copy(currentRouteIndex = index)
|
||||
surfaceRenderer.setPreviewRouteData(routeModel)
|
||||
//setResult(destination)
|
||||
//finish()
|
||||
}
|
||||
|
||||
fun getMapActionStrip(): ActionStrip {
|
||||
@@ -249,7 +245,7 @@ class RoutePreviewScreen(
|
||||
): Action {
|
||||
return Action.Builder()
|
||||
.setOnClickListener { surfaceRenderer.handleScale(-1) }
|
||||
.setIcon(navigationMessage.createCarIcon(iconRes))
|
||||
.setIcon(navigationUtils.createCarIcon(iconRes))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.kouros.navigation.car.screen.settings
|
||||
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.model.Action
|
||||
import androidx.car.app.model.CarIcon
|
||||
import androidx.car.app.model.Header
|
||||
import androidx.car.app.model.ItemList
|
||||
import androidx.car.app.model.ListTemplate
|
||||
import androidx.car.app.model.Row
|
||||
import androidx.car.app.model.SectionedItemList
|
||||
import androidx.car.app.model.Template
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.car.navigation.NavigationUtils
|
||||
import com.kouros.navigation.utils.getSettingsViewModel
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class AudioSettings(
|
||||
private val carContext: CarContext,
|
||||
) :
|
||||
Screen(carContext) {
|
||||
|
||||
private var guidanceAudioSettings = 0
|
||||
|
||||
val settingsViewModel = getSettingsViewModel(carContext)
|
||||
|
||||
init {
|
||||
lifecycleScope.launch {
|
||||
settingsViewModel.guidanceAudio.first()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGetTemplate(): Template {
|
||||
guidanceAudioSettings = settingsViewModel.guidanceAudio.value
|
||||
val templateBuilder = ListTemplate.Builder()
|
||||
val radioList =
|
||||
ItemList.Builder()
|
||||
.addItem(
|
||||
NavigationUtils(carContext).buildRowForTemplate(
|
||||
R.string.muted,
|
||||
R.drawable.volume_off_24px
|
||||
)
|
||||
)
|
||||
.addItem(
|
||||
NavigationUtils(carContext).buildRowForTemplate(
|
||||
R.string.unmuted,
|
||||
R.drawable.volume_up_24px,
|
||||
)
|
||||
)
|
||||
.addItem(
|
||||
NavigationUtils(carContext).buildRowForTemplate(
|
||||
R.string.alerts_only,
|
||||
R.drawable.warning_24px,
|
||||
)
|
||||
)
|
||||
.setOnSelectedListener { index: Int ->
|
||||
this.onSelected(index)
|
||||
}
|
||||
.setSelectedIndex(guidanceAudioSettings)
|
||||
.build()
|
||||
|
||||
return templateBuilder
|
||||
.addSectionedList(
|
||||
SectionedItemList.create(
|
||||
radioList,
|
||||
carContext.getString(R.string.audio_settings)
|
||||
)
|
||||
)
|
||||
.setHeader(
|
||||
Header.Builder()
|
||||
.setTitle(carContext.getString(R.string.audio_settings))
|
||||
.setStartHeaderAction(Action.BACK)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
||||
private fun onSelected(index: Int) {
|
||||
settingsViewModel.onGuidanceAudioChanged(index)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.kouros.navigation.car.screen
|
||||
package com.kouros.navigation.car.screen.settings
|
||||
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.CarToast
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.model.Action
|
||||
import androidx.car.app.model.Header
|
||||
@@ -12,6 +11,7 @@ import androidx.car.app.model.SectionedItemList
|
||||
import androidx.car.app.model.Template
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.car.navigation.NavigationUtils
|
||||
import com.kouros.navigation.utils.getSettingsViewModel
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -34,18 +34,21 @@ class DarkModeSettings(private val carContext: CarContext) : Screen(carContext)
|
||||
val radioList =
|
||||
ItemList.Builder()
|
||||
.addItem(
|
||||
buildRowForTemplate(
|
||||
NavigationUtils(carContext).buildRowForTemplate(
|
||||
R.string.off_action_title,
|
||||
R.drawable.light_mode_24px
|
||||
)
|
||||
)
|
||||
.addItem(
|
||||
buildRowForTemplate(
|
||||
NavigationUtils(carContext).buildRowForTemplate(
|
||||
R.string.on_action_title,
|
||||
R.drawable.dark_mode_24px
|
||||
)
|
||||
)
|
||||
.addItem(
|
||||
buildRowForTemplate(
|
||||
NavigationUtils(carContext).buildRowForTemplate(
|
||||
R.string.use_car_settings,
|
||||
R.drawable.directions_car_24px
|
||||
)
|
||||
)
|
||||
.setOnSelectedListener { index: Int ->
|
||||
@@ -74,11 +77,4 @@ class DarkModeSettings(private val carContext: CarContext) : Screen(carContext)
|
||||
private fun onSelected(index: Int) {
|
||||
settingsViewModel.onDarkModeChanged(index)
|
||||
}
|
||||
|
||||
private fun buildRowForTemplate(title: Int): Row {
|
||||
return Row.Builder()
|
||||
.setTitle(carContext.getString(title))
|
||||
.build()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.kouros.navigation.car.screen
|
||||
package com.kouros.navigation.car.screen.settings
|
||||
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.Screen
|
||||
@@ -11,6 +11,7 @@ import androidx.car.app.model.Template
|
||||
import androidx.car.app.model.Toggle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.car.screen.settings.DistanceSettings
|
||||
import com.kouros.navigation.utils.getSettingsViewModel
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.kouros.navigation.car.screen
|
||||
package com.kouros.navigation.car.screen.settings
|
||||
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.CarToast
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.model.Action
|
||||
import androidx.car.app.model.Header
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.kouros.navigation.car.screen
|
||||
package com.kouros.navigation.car.screen.settings
|
||||
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.Screen
|
||||
@@ -11,12 +11,13 @@ import androidx.car.app.model.Template
|
||||
import androidx.car.app.model.Toggle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.car.screen.settings.PasswordSettings
|
||||
import com.kouros.navigation.car.screen.settings.RoutingSettings
|
||||
import com.kouros.navigation.model.NavigationViewModel
|
||||
import com.kouros.navigation.utils.getSettingsViewModel
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class NavigationSettings(
|
||||
private val carContext: CarContext,
|
||||
private var navigationViewModel: NavigationViewModel
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.kouros.navigation.car.screen
|
||||
package com.kouros.navigation.car.screen.settings
|
||||
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.Screen
|
||||
@@ -10,7 +10,6 @@ import androidx.car.app.model.signin.InputSignInMethod
|
||||
import androidx.car.app.model.signin.SignInTemplate
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.model.NavigationViewModel
|
||||
import com.kouros.navigation.utils.getSettingsViewModel
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.kouros.navigation.car.screen
|
||||
package com.kouros.navigation.car.screen.settings
|
||||
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.CarToast
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.model.Action
|
||||
import androidx.car.app.model.Header
|
||||
@@ -56,7 +55,8 @@ class RoutingSettings(private val carContext: CarContext, private var navigation
|
||||
.build()
|
||||
|
||||
return templateBuilder
|
||||
.addSectionedList(SectionedItemList.create(
|
||||
.addSectionedList(
|
||||
SectionedItemList.create(
|
||||
radioList,
|
||||
carContext.getString(R.string.routing_engine)
|
||||
))
|
||||
@@ -1,19 +1,4 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.kouros.navigation.car.screen
|
||||
package com.kouros.navigation.car.screen.settings
|
||||
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.Screen
|
||||
@@ -34,6 +19,12 @@ class SettingsScreen(
|
||||
|
||||
override fun onGetTemplate(): Template {
|
||||
val listBuilder = ItemList.Builder()
|
||||
listBuilder.addItem(
|
||||
buildRowForTemplate(
|
||||
AudioSettings(carContext),
|
||||
R.string.audio_settings
|
||||
)
|
||||
)
|
||||
listBuilder.addItem(
|
||||
buildRowForTemplate(
|
||||
DisplaySettings(carContext),
|
||||
@@ -67,4 +58,4 @@ class SettingsScreen(
|
||||
.setBrowsable(true)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,7 @@ data class StepData (
|
||||
var leftDistance: Double,
|
||||
var lane: List<Lane> = listOf(Lane(location(0.0, 0.0), valid = false, indications = emptyList())),
|
||||
var exitNumber: Int = 0,
|
||||
var message: String = "",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ class DataStoreManager(private val context: Context) {
|
||||
|
||||
val DISTANCE_MODE = intPreferencesKey("DistanceMode")
|
||||
|
||||
val GUIDANCE_AUDIO = intPreferencesKey("GuidanceAudio")
|
||||
|
||||
}
|
||||
|
||||
// Read values
|
||||
@@ -107,6 +109,12 @@ class DataStoreManager(private val context: Context) {
|
||||
?: 0
|
||||
}
|
||||
|
||||
val guidanceAudioFlow: Flow<Int> =
|
||||
context.dataStore.data.map { preferences ->
|
||||
preferences[PreferencesKeys.GUIDANCE_AUDIO]
|
||||
?: 0
|
||||
}
|
||||
|
||||
// Save values
|
||||
suspend fun setShow3D(enabled: Boolean) {
|
||||
context.dataStore.edit { preferences ->
|
||||
@@ -168,4 +176,10 @@ class DataStoreManager(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun setGuidanceAudio(mode: Int) {
|
||||
context.dataStore.edit { prefs ->
|
||||
prefs[PreferencesKeys.GUIDANCE_AUDIO] = mode
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,4 +10,5 @@ data class Maneuver(
|
||||
val location: Location,
|
||||
val exit: Int = 0,
|
||||
val street: String = "",
|
||||
val message: String = ""
|
||||
)
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.kouros.navigation.utils.GeoUtils.calculateSquareRadius
|
||||
import com.kouros.navigation.utils.getSettingsRepository
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
private const val routeUrl = "https://api.tomtom.com/routing/1/calculateRoute/"
|
||||
@@ -42,12 +43,14 @@ class TomTomRepository : NavigationRepository() {
|
||||
}
|
||||
val repository = getSettingsRepository(context)
|
||||
val tomtomApiKey = runBlocking { repository.tomTomApiKeyFlow.first() }
|
||||
val currentLocale = Locale.getDefault()
|
||||
val language = currentLocale.language + "-" + currentLocale.country
|
||||
val url =
|
||||
routeUrl + "${currentLocation.latitude},${currentLocation.longitude}:${location.latitude},${location.longitude}" +
|
||||
"/json?sectionType=traffic&report=effectiveSettings&routeType=eco" +
|
||||
"&traffic=true&avoid=unpavedRoads&travelMode=car" +
|
||||
"&vehicleMaxSpeed=120&vehicleCommercial=false" +
|
||||
"&instructionsType=text&language=en-GB§ionType=lanes" +
|
||||
"&instructionsType=text&language=$language§ionType=lanes" +
|
||||
"&routeRepresentation=encodedPolyline" +
|
||||
"&vehicleEngineType=combustion$filter&key=$tomtomApiKey"
|
||||
return fetchUrl(
|
||||
|
||||
@@ -55,7 +55,8 @@ class TomTomRoute {
|
||||
location = location(
|
||||
instruction.point.longitude, instruction.point.latitude
|
||||
),
|
||||
street = maneuverStreet
|
||||
street = maneuverStreet,
|
||||
message = instruction.message
|
||||
)
|
||||
|
||||
lastPointIndex = instruction.pointIndex
|
||||
|
||||
@@ -93,7 +93,8 @@ open class RouteModel {
|
||||
arrivalTime = routeCalculator.arrivalTime(),
|
||||
leftDistance = routeCalculator.travelLeftDistance(),
|
||||
lane = currentLanes(),
|
||||
exitNumber = exitNumber
|
||||
exitNumber = exitNumber,
|
||||
message = currentStep.maneuver.message
|
||||
)
|
||||
}
|
||||
|
||||
@@ -118,7 +119,8 @@ open class RouteModel {
|
||||
icon = maneuverIcon,
|
||||
arrivalTime = routeCalculator.arrivalTime(),
|
||||
leftDistance = routeCalculator.travelLeftDistance(),
|
||||
exitNumber = nextStep.maneuver.exit
|
||||
exitNumber = nextStep.maneuver.exit,
|
||||
message = nextStep.maneuver.message
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,12 @@ class SettingsViewModel(private val repository: SettingsRepository) : ViewModel(
|
||||
0
|
||||
)
|
||||
|
||||
val guidanceAudio = repository.guidanceAudioFlow.stateIn(
|
||||
viewModelScope,
|
||||
SharingStarted.WhileSubscribed(5_000),
|
||||
0
|
||||
)
|
||||
|
||||
fun onShow3DChanged(enabled: Boolean) {
|
||||
viewModelScope.launch { repository.setShow3D(enabled) }
|
||||
}
|
||||
@@ -108,4 +114,8 @@ class SettingsViewModel(private val repository: SettingsRepository) : ViewModel(
|
||||
viewModelScope.launch { repository.setDistanceMode(mode) }
|
||||
}
|
||||
|
||||
fun onGuidanceAudioChanged(mode: Int) {
|
||||
viewModelScope.launch { repository.setGuidanceAudio(mode) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ class SettingsRepository(
|
||||
val distanceModeFlow: Flow<Int> =
|
||||
dataStoreManager.distanceModeFlow
|
||||
|
||||
val guidanceAudioFlow: Flow<Int> =
|
||||
dataStoreManager.guidanceAudioFlow
|
||||
|
||||
|
||||
suspend fun setShow3D(enabled: Boolean) {
|
||||
dataStoreManager.setShow3D(enabled)
|
||||
@@ -77,5 +80,8 @@ class SettingsRepository(
|
||||
dataStoreManager.setDistanceMode(mode)
|
||||
}
|
||||
|
||||
suspend fun setGuidanceAudio(mode: Int) {
|
||||
dataStoreManager.setGuidanceAudio(mode)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
10
common/data/src/main/res/drawable/dark_mode_24px.xml
Normal file
10
common/data/src/main/res/drawable/dark_mode_24px.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M480,840Q330,840 225,735Q120,630 120,480Q120,330 225,225Q330,120 480,120Q494,120 507.5,121Q521,122 534,124Q493,153 468.5,199.5Q444,246 444,300Q444,390 507,453Q570,516 660,516Q715,516 761,491.5Q807,467 836,426Q838,439 839,452.5Q840,466 840,480Q840,630 735,735Q630,840 480,840ZM480,760Q568,760 638,711.5Q708,663 740,585Q720,590 700,593Q680,596 660,596Q537,596 450.5,509.5Q364,423 364,300Q364,280 367,260Q370,240 375,220Q297,252 248.5,322Q200,392 200,480Q200,596 282,678Q364,760 480,760ZM470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Q470,490 470,490Z"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/directions_car_24px.xml
Normal file
10
common/data/src/main/res/drawable/directions_car_24px.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M240,760L240,800Q240,817 228.5,828.5Q217,840 200,840L160,840Q143,840 131.5,828.5Q120,817 120,800L120,480L204,240Q210,222 225.5,211Q241,200 260,200L700,200Q719,200 734.5,211Q750,222 756,240L840,480L840,800Q840,817 828.5,828.5Q817,840 800,840L760,840Q743,840 731.5,828.5Q720,817 720,800L720,760L240,760ZM232,400L728,400L686,280L274,280L232,400ZM200,480L200,480L200,680L200,680L200,480ZM300,640Q325,640 342.5,622.5Q360,605 360,580Q360,555 342.5,537.5Q325,520 300,520Q275,520 257.5,537.5Q240,555 240,580Q240,605 257.5,622.5Q275,640 300,640ZM660,640Q685,640 702.5,622.5Q720,605 720,580Q720,555 702.5,537.5Q685,520 660,520Q635,520 617.5,537.5Q600,555 600,580Q600,605 617.5,622.5Q635,640 660,640ZM200,680L760,680L760,480L200,480L200,680Z"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/light_mode_24px.xml
Normal file
10
common/data/src/main/res/drawable/light_mode_24px.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M565,565Q600,530 600,480Q600,430 565,395Q530,360 480,360Q430,360 395,395Q360,430 360,480Q360,530 395,565Q430,600 480,600Q530,600 565,565ZM338.5,621.5Q280,563 280,480Q280,397 338.5,338.5Q397,280 480,280Q563,280 621.5,338.5Q680,397 680,480Q680,563 621.5,621.5Q563,680 480,680Q397,680 338.5,621.5ZM200,520L40,520L40,440L200,440L200,520ZM920,520L760,520L760,440L920,440L920,520ZM440,200L440,40L520,40L520,200L440,200ZM440,920L440,760L520,760L520,920L440,920ZM256,310L155,213L212,154L308,254L256,310ZM748,806L651,705L704,650L805,747L748,806ZM650,256L747,155L806,212L706,308L650,256ZM154,748L255,651L310,704L213,805L154,748ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
|
||||
</vector>
|
||||
10
common/data/src/main/res/drawable/volume_off_24px.xml
Normal file
10
common/data/src/main/res/drawable/volume_off_24px.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M792,904L671,783Q646,799 618,810.5Q590,822 560,829L560,747Q574,742 587.5,737Q601,732 613,725L480,592L480,800L280,600L120,600L120,360L248,360L56,168L112,112L848,848L792,904ZM784,672L726,614Q743,583 751.5,549Q760,515 760,479Q760,385 705,311Q650,237 560,211L560,129Q684,157 762,254.5Q840,352 840,479Q840,532 825.5,581Q811,630 784,672ZM650,538L560,448L560,318Q607,340 633.5,384Q660,428 660,480Q660,495 657.5,509.5Q655,524 650,538ZM480,368L376,264L480,160L480,368ZM400,606L400,512L328,440L328,440L200,440L200,520L314,520L400,606ZM364,476L364,476L364,476L364,476L364,476L364,476L364,476Z"/>
|
||||
</vector>
|
||||
11
common/data/src/main/res/drawable/volume_up_24px.xml
Normal file
11
common/data/src/main/res/drawable/volume_up_24px.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:autoMirrored="true">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M560,829L560,747Q650,721 705,647Q760,573 760,479Q760,385 705,311Q650,237 560,211L560,129Q684,157 762,254.5Q840,352 840,479Q840,606 762,703.5Q684,801 560,829ZM120,600L120,360L280,360L480,160L480,800L280,600L120,600ZM560,640L560,318Q607,340 633.5,384Q660,428 660,480Q660,531 633.5,574.5Q607,618 560,640ZM400,354L314,440L200,440L200,520L314,520L400,606L400,354ZM300,480L300,480L300,480L300,480L300,480L300,480Z"/>
|
||||
</vector>
|
||||
@@ -24,7 +24,7 @@
|
||||
},
|
||||
{
|
||||
"key": "departAt",
|
||||
"value": "2026-02-06T09:09:59.054Z"
|
||||
"value": "2026-03-04T14:38:14.253Z"
|
||||
},
|
||||
{
|
||||
"key": "guidanceVersion",
|
||||
@@ -40,16 +40,20 @@
|
||||
},
|
||||
{
|
||||
"key": "language",
|
||||
"value": "en-GB"
|
||||
"value": "de-DE"
|
||||
},
|
||||
{
|
||||
"key": "locations",
|
||||
"value": "48.18575,11.57939:48.11654,11.59449"
|
||||
"value": "48.18575,11.57937:48.11648,11.59432"
|
||||
},
|
||||
{
|
||||
"key": "maxAlternatives",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"key": "maxPathAlternatives",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"key": "routeRepresentation",
|
||||
"value": "encodedPolyline"
|
||||
@@ -60,11 +64,11 @@
|
||||
},
|
||||
{
|
||||
"key": "sectionType",
|
||||
"value": "traffic"
|
||||
"value": "lanes"
|
||||
},
|
||||
{
|
||||
"key": "sectionType",
|
||||
"value": "lanes"
|
||||
"value": "traffic"
|
||||
},
|
||||
{
|
||||
"key": "traffic",
|
||||
@@ -86,10 +90,6 @@
|
||||
"key": "vehicleEngineType",
|
||||
"value": "combustion"
|
||||
},
|
||||
{
|
||||
"key": "vehicleHeading",
|
||||
"value": "90"
|
||||
},
|
||||
{
|
||||
"key": "vehicleHeight",
|
||||
"value": "0.00"
|
||||
@@ -119,28 +119,46 @@
|
||||
"routes": [
|
||||
{
|
||||
"summary": {
|
||||
"lengthInMeters": 11116,
|
||||
"travelTimeInSeconds": 1148,
|
||||
"trafficDelayInSeconds": 0,
|
||||
"trafficLengthInMeters": 0,
|
||||
"departureTime": "2026-02-06T10:09:59+01:00",
|
||||
"arrivalTime": "2026-02-06T10:29:07+01:00"
|
||||
"lengthInMeters": 11122,
|
||||
"travelTimeInSeconds": 1483,
|
||||
"trafficDelayInSeconds": 175,
|
||||
"trafficLengthInMeters": 2191,
|
||||
"departureTime": "2026-03-04T15:38:14+01:00",
|
||||
"arrivalTime": "2026-03-04T16:02:57+01:00"
|
||||
},
|
||||
"legs": [
|
||||
{
|
||||
"summary": {
|
||||
"lengthInMeters": 11116,
|
||||
"travelTimeInSeconds": 1148,
|
||||
"trafficDelayInSeconds": 0,
|
||||
"trafficLengthInMeters": 0,
|
||||
"departureTime": "2026-02-06T10:09:59+01:00",
|
||||
"arrivalTime": "2026-02-06T10:29:07+01:00"
|
||||
"lengthInMeters": 11122,
|
||||
"travelTimeInSeconds": 1483,
|
||||
"trafficDelayInSeconds": 175,
|
||||
"trafficLengthInMeters": 2191,
|
||||
"departureTime": "2026-03-04T15:38:14+01:00",
|
||||
"arrivalTime": "2026-03-04T16:02:57+01:00"
|
||||
},
|
||||
"encodedPolyline": "sfbeHarteAE~DQEy@GQ?wDQFkEH{G?M?sA@kB?_FAeC?o@?[@_@\\Ab@CVAz@CJA@?dBGhAGjAExAGlBEvBKdCKTAfCKLAv@ELA|AGnAGt@ClCKjDQpBIf@BXDPDPBF@ZB?S@SAYAUKi@Go@Cc@BgBBs@Bg@JyAJiAXqBDWNs@TaA\\mAFa@Po@`BwF?YL]FSFSl@iB^kALc@L]Ro@f@yAf@{AFQNe@dAoCdBgEx@qBTi@BITe@L[L_@^}@HSXu@pB}El@eAb@e@f@[h@QZCRAL?j@HRFh@Vf@XLJhAn@lAv@TLtAz@r@`@bAn@pAv@f@X~@j@z@h@vBpA`@VHDFFJFf@X`CzApAh@f@L`@Fz@@f@AXEVEVEhA[h@Yn@e@PQFEJKRWV[PW`@w@t@}AHQN]~BiFP]`AoBh@aADGTa@t@aAt@{@PQJKJGFG@Cd@]XSxDmCf@a@n@o@TY\\g@LQHMJSLUP[f@iAPg@b@yAFODMNi@FS|@qCVaAHUHUn@wBHYh@eBpAkEjBiGfAeDj@yADMFQd@sAf@kAJUh@qAf@eAt@sAn@iALSN[p@kAVc@JOLSj@w@z@}@x@q@pAu@p@_@j@Sl@MLCRCb@E`@?^?L@`ABz@?N@~AFdADJ@rAH`DVpCVrAJd@BfHp@zGl@pAJ|ALnGp@jEh@fBJpAFF?P@N@ZCtC]r@GJCFCLCD?TEVEXGhAYzAg@NGv@]`@QJEvB_AXMVK\\Qb@Qn@QJCNAZC^ENA`@FnBb@xEtA^H^JnCl@z@r@`@Pr@TtBlA~C`Bn@\\xAl@PF`@LrAVlCh@bBLl@BlBJdG\\RDjCHn@?pB?xB?R@`@@GxAC^?ZInBIfCAvC?r@@dD@n@@b@@^D`C?TDxAFbBHdB@VHp@RjAJb@NNH`@VlBFf@PzARhBFd@@LRbBFh@\\nC@FNhAb@lEj@tDPpABTBRZlBTdBXjBn@xEBLDTRpAR~@l@jDj@Qv@IrEP",
|
||||
"encodedPolyline": "sfbeH_rteAE|DQEy@GQ?wDQFkEH{G?M?sA@kB?_FAeC?o@?[@_@\\Ab@CVAz@CJA@?dBGhAGjAExAGlBEvBKdCKTAfCKLAv@ELA|AGnAGt@ClCKjDQpBIf@BXDPDPBF@ZB?S@SAYAUKi@Go@Cc@BgBBs@Bg@JyAJiAXqBDWNs@TaA\\mAFa@Po@`BwF?YL]FSFSl@iB^kALc@L]Ro@f@yAf@{AFQNe@dAoCdBgEx@qBTi@BITe@L[L_@^}@HSXu@pB}El@eAb@e@f@[h@QZCRAL?j@HRFh@Vf@XLJhAn@lAv@TLtAz@r@`@bAn@pAv@f@X~@j@z@h@vBpA`@VHDFFJFf@X`CzApAh@f@L`@Fz@@f@AXEVEVEhA[h@Yn@e@PQFEJKRWV[PW`@w@t@}AHQN]~BiFP]`AoBh@aADGTa@t@aAt@{@PQJKJGFG@Cd@]XSxDmCf@a@n@o@TY\\g@LQHMJSLUP[f@iAPg@b@yAFODMNi@FS|@qCVaAHUHUn@wBHYh@eBpAkEjBiGfAeDj@yADMFQd@sAf@kAJUh@qAf@eAt@sAn@iALSN[p@kAVc@JOLSj@w@z@}@x@q@pAu@p@_@j@Sl@MLCRCb@E`@?^?L@`ABz@?N@~AFdADJ@rAH`DVpCVrAJd@BfHp@zGl@pAJ|ALnGp@jEh@fBJpAFF?P@N@ZCtC]r@GJCFCLCD?TEVEXGhAYzAg@NGv@]`@QJEvB_AXMVK\\Qb@Qn@QJCNAZC^ENA`@FnBb@xEtA^H^JnCl@z@r@`@Pr@TtBlA~C`Bn@\\xAl@PF`@LrAVlCh@bBLl@BlBJdG\\RDjCHn@?pB?xB?R@`@@GxAC^?ZInBIfCAvC?r@@dD@n@@b@@^D`C?TDxAFbBHdB@VHp@RjAJb@NNH`@VlBFf@PzARhBFd@@LRbBFh@\\nC@FNhAb@lEj@tDPpABTBRZlBTdBXjBn@xEBLDTRpAR~@l@jDj@Qv@I~ER",
|
||||
"encodedPolylinePrecision": 5
|
||||
}
|
||||
],
|
||||
"sections": [
|
||||
{
|
||||
"startPointIndex": 66,
|
||||
"endPointIndex": 143,
|
||||
"sectionType": "TRAFFIC",
|
||||
"simpleCategory": "JAM",
|
||||
"effectiveSpeedInKmh": 26,
|
||||
"delayInSeconds": 175,
|
||||
"magnitudeOfDelay": 1,
|
||||
"tec": {
|
||||
"causes": [
|
||||
{
|
||||
"mainCauseCode": 1
|
||||
}
|
||||
],
|
||||
"effectCode": 4
|
||||
},
|
||||
"eventId": "TTL41056710392017000"
|
||||
},
|
||||
{
|
||||
"lanes": [
|
||||
{
|
||||
@@ -331,7 +349,7 @@
|
||||
"travelTimeInSeconds": 0,
|
||||
"point": {
|
||||
"latitude": 48.18554,
|
||||
"longitude": 11.57937
|
||||
"longitude": 11.57936
|
||||
},
|
||||
"pointIndex": 0,
|
||||
"instructionType": "LOCATION_DEPARTURE",
|
||||
@@ -340,10 +358,10 @@
|
||||
"possibleCombineWithNext": false,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "DEPART",
|
||||
"message": "Leave from Vogelhartstraße"
|
||||
"message": "Abfahrt von Vogelhartstraße"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 72,
|
||||
"routeOffsetInMeters": 71,
|
||||
"travelTimeInSeconds": 16,
|
||||
"point": {
|
||||
"latitude": 48.18557,
|
||||
@@ -358,11 +376,11 @@
|
||||
"possibleCombineWithNext": false,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "TURN_RIGHT",
|
||||
"message": "Turn right onto Silcherstraße"
|
||||
"message": "Biegen Sie rechts ab auf Silcherstraße"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 226,
|
||||
"travelTimeInSeconds": 60,
|
||||
"routeOffsetInMeters": 225,
|
||||
"travelTimeInSeconds": 61,
|
||||
"point": {
|
||||
"latitude": 48.18696,
|
||||
"longitude": 11.57857
|
||||
@@ -376,11 +394,11 @@
|
||||
"possibleCombineWithNext": false,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "TURN_RIGHT",
|
||||
"message": "Turn right onto Schmalkaldener Straße"
|
||||
"message": "Biegen Sie rechts ab auf Schmalkaldener Straße"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 658,
|
||||
"travelTimeInSeconds": 134,
|
||||
"routeOffsetInMeters": 657,
|
||||
"travelTimeInSeconds": 135,
|
||||
"point": {
|
||||
"latitude": 48.18686,
|
||||
"longitude": 11.58437
|
||||
@@ -397,11 +415,11 @@
|
||||
"possibleCombineWithNext": false,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "TURN_RIGHT",
|
||||
"message": "Turn right onto Ingolstädter Straße/B13"
|
||||
"message": "Biegen Sie rechts ab auf Ingolstädter Straße/B13"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 1720,
|
||||
"travelTimeInSeconds": 267,
|
||||
"routeOffsetInMeters": 1719,
|
||||
"travelTimeInSeconds": 291,
|
||||
"point": {
|
||||
"latitude": 48.17733,
|
||||
"longitude": 11.58503
|
||||
@@ -418,12 +436,12 @@
|
||||
"possibleCombineWithNext": true,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "TURN_LEFT",
|
||||
"message": "Turn left onto Schenkendorfstraße/B2R",
|
||||
"combinedMessage": "Turn left onto Schenkendorfstraße/B2R then keep left at Schenkendorfstraße/B2R toward Messe / ICM"
|
||||
"message": "Biegen Sie links ab auf Schenkendorfstraße/B2R",
|
||||
"combinedMessage": "Biegen Sie links ab auf Schenkendorfstraße/B2R dann bleiben Sie bei Schenkendorfstraße/B2R Richtung Messe / ICM links"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 2075,
|
||||
"travelTimeInSeconds": 307,
|
||||
"routeOffsetInMeters": 2074,
|
||||
"travelTimeInSeconds": 333,
|
||||
"point": {
|
||||
"latitude": 48.17678,
|
||||
"longitude": 11.58957
|
||||
@@ -441,12 +459,12 @@
|
||||
"possibleCombineWithNext": true,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "KEEP_LEFT",
|
||||
"message": "Keep left at Schenkendorfstraße/B2R toward Messe / ICM",
|
||||
"combinedMessage": "Keep left at Schenkendorfstraße/B2R toward Messe / ICM then keep left at Schenkendorfstraße/B2R toward Passau"
|
||||
"message": "Bleiben Sie bei Schenkendorfstraße/B2R Richtung Messe / ICM links",
|
||||
"combinedMessage": "Bleiben Sie bei Schenkendorfstraße/B2R Richtung Messe / ICM links dann bleiben Sie bei Schenkendorfstraße/B2R Richtung Passau links"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 2426,
|
||||
"travelTimeInSeconds": 329,
|
||||
"routeOffsetInMeters": 2425,
|
||||
"travelTimeInSeconds": 371,
|
||||
"point": {
|
||||
"latitude": 48.17518,
|
||||
"longitude": 11.59363
|
||||
@@ -464,11 +482,11 @@
|
||||
"possibleCombineWithNext": false,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "KEEP_LEFT",
|
||||
"message": "Keep left at Schenkendorfstraße/B2R toward Passau"
|
||||
"message": "Bleiben Sie bei Schenkendorfstraße/B2R Richtung Passau links"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 2781,
|
||||
"travelTimeInSeconds": 353,
|
||||
"routeOffsetInMeters": 2780,
|
||||
"travelTimeInSeconds": 436,
|
||||
"point": {
|
||||
"latitude": 48.17329,
|
||||
"longitude": 11.59747
|
||||
@@ -484,14 +502,14 @@
|
||||
"possibleCombineWithNext": false,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "FOLLOW",
|
||||
"message": "Follow Isarring/B2R toward München-Ost"
|
||||
"message": "Folgen Sie Isarring/B2R Richtung München-Ost"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 8433,
|
||||
"travelTimeInSeconds": 734,
|
||||
"routeOffsetInMeters": 8431,
|
||||
"travelTimeInSeconds": 1014,
|
||||
"point": {
|
||||
"latitude": 48.13017,
|
||||
"longitude": 11.61541
|
||||
"longitude": 11.6154
|
||||
},
|
||||
"pointIndex": 266,
|
||||
"instructionType": "TURN",
|
||||
@@ -502,11 +520,11 @@
|
||||
"possibleCombineWithNext": false,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "BEAR_RIGHT",
|
||||
"message": "Bear right at Ampfingstraße"
|
||||
"message": "Halten Sie sich rechts bei Ampfingstraße"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 9495,
|
||||
"travelTimeInSeconds": 884,
|
||||
"routeOffsetInMeters": 9494,
|
||||
"travelTimeInSeconds": 1197,
|
||||
"point": {
|
||||
"latitude": 48.12089,
|
||||
"longitude": 11.61285
|
||||
@@ -520,12 +538,12 @@
|
||||
"possibleCombineWithNext": true,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "TURN_RIGHT",
|
||||
"message": "Turn right onto Anzinger Straße",
|
||||
"combinedMessage": "Turn right onto Anzinger Straße then keep straight on at Sankt-Martin-Straße"
|
||||
"message": "Biegen Sie rechts ab auf Anzinger Straße",
|
||||
"combinedMessage": "Biegen Sie rechts ab auf Anzinger Straße dann fahren Sie geradeaus weiter auf Sankt-Martin-Straße"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 9991,
|
||||
"travelTimeInSeconds": 974,
|
||||
"routeOffsetInMeters": 9990,
|
||||
"travelTimeInSeconds": 1286,
|
||||
"point": {
|
||||
"latitude": 48.12087,
|
||||
"longitude": 11.60621
|
||||
@@ -539,11 +557,11 @@
|
||||
"possibleCombineWithNext": false,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "STRAIGHT",
|
||||
"message": "Keep straight on at Sankt-Martin-Straße"
|
||||
"message": "Fahren Sie geradeaus weiter auf Sankt-Martin-Straße"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 10941,
|
||||
"travelTimeInSeconds": 1103,
|
||||
"routeOffsetInMeters": 10940,
|
||||
"travelTimeInSeconds": 1440,
|
||||
"point": {
|
||||
"latitude": 48.11811,
|
||||
"longitude": 11.59417
|
||||
@@ -557,15 +575,15 @@
|
||||
"possibleCombineWithNext": true,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "TURN_LEFT",
|
||||
"message": "Turn left onto Hohenwaldeckstraße",
|
||||
"combinedMessage": "Turn left onto Hohenwaldeckstraße then you have arrived at Hohenwaldeckstraße. Your destination is on the left"
|
||||
"message": "Biegen Sie links ab auf Hohenwaldeckstraße",
|
||||
"combinedMessage": "Biegen Sie links ab auf Hohenwaldeckstraße dann sie haben Hohenwaldeckstraße erreicht. Ihr Ziel liegt auf der linken Seite"
|
||||
},
|
||||
{
|
||||
"routeOffsetInMeters": 11116,
|
||||
"travelTimeInSeconds": 1148,
|
||||
"routeOffsetInMeters": 11122,
|
||||
"travelTimeInSeconds": 1483,
|
||||
"point": {
|
||||
"latitude": 48.11655,
|
||||
"longitude": 11.59422
|
||||
"latitude": 48.11649,
|
||||
"longitude": 11.59421
|
||||
},
|
||||
"pointIndex": 338,
|
||||
"instructionType": "LOCATION_ARRIVAL",
|
||||
@@ -574,33 +592,33 @@
|
||||
"possibleCombineWithNext": false,
|
||||
"drivingSide": "RIGHT",
|
||||
"maneuver": "ARRIVE_LEFT",
|
||||
"message": "You have arrived at Hohenwaldeckstraße. Your destination is on the left"
|
||||
"message": "Sie haben Hohenwaldeckstraße erreicht. Ihr Ziel liegt auf der linken Seite"
|
||||
}
|
||||
],
|
||||
"instructionGroups": [
|
||||
{
|
||||
"firstInstructionIndex": 0,
|
||||
"lastInstructionIndex": 3,
|
||||
"groupMessage": "Leave from Vogelhartstraße. Take the Ingolstädter Straße/B13",
|
||||
"groupLengthInMeters": 1720
|
||||
"groupMessage": "Abfahrt von Vogelhartstraße. Fahren Sie auf die Ingolstädter Straße/B13",
|
||||
"groupLengthInMeters": 1719
|
||||
},
|
||||
{
|
||||
"firstInstructionIndex": 4,
|
||||
"lastInstructionIndex": 7,
|
||||
"groupMessage": "Take the Schenkendorfstraße, Isarring/B2R toward Messe / ICM, Passau, München-Ost",
|
||||
"groupLengthInMeters": 6713
|
||||
"groupMessage": "Fahren Sie auf die Schenkendorfstraße, Isarring/B2R in Richtung Messe / ICM, Passau, München-Ost",
|
||||
"groupLengthInMeters": 6712
|
||||
},
|
||||
{
|
||||
"firstInstructionIndex": 8,
|
||||
"lastInstructionIndex": 10,
|
||||
"groupMessage": "Take the Ampfingstraße, Anzinger Straße, Sankt-Martin-Straße",
|
||||
"groupLengthInMeters": 2508
|
||||
"groupMessage": "Fahren Sie auf die Ampfingstraße, Anzinger Straße, Sankt-Martin-Straße",
|
||||
"groupLengthInMeters": 2509
|
||||
},
|
||||
{
|
||||
"firstInstructionIndex": 11,
|
||||
"lastInstructionIndex": 12,
|
||||
"groupMessage": "Get to your destination at Hohenwaldeckstraße",
|
||||
"groupLengthInMeters": 175
|
||||
"groupMessage": "Fahren Sie zu Ihrem Ziel in der Hohenwaldeckstraße",
|
||||
"groupLengthInMeters": 182
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -58,4 +58,8 @@
|
||||
<string name="automaticaly">Automatisch</string>
|
||||
<string name="kilometer">Kilometer</string>
|
||||
<string name="miles">Meilen</string>
|
||||
<string name="audio_settings">Töne</string>
|
||||
<string name="muted">Stummgeschaltet</string>
|
||||
<string name="unmuted">Ton an</string>
|
||||
<string name="alerts_only">Nur Alarme</string>
|
||||
</resources>
|
||||
|
||||
48
common/data/src/main/res/values-el/strings.xml
Normal file
48
common/data/src/main/res/values-el/strings.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="speed_camera">Κάμερα ταχύτητας</string>
|
||||
<string name="exit_action_title">Κλείσιμο</string>
|
||||
<string name="fuel_station">Πρατήριο καυσίμων</string>
|
||||
<string name="pharmacy">Φαρμακείο</string>
|
||||
<string name="charging_station">Σταθμός φόρτισης</string>
|
||||
<string name="category_title">Κατηγορία</string>
|
||||
<string name="on_action_title">Ενεργό</string>
|
||||
<string name="off_action_title">Ανενεργό</string>
|
||||
<string name="use_telephon_settings">Χρήση ρυθμίσεων τηλεφώνου</string>
|
||||
<string name="dark_mode">Σκούρα εμφάνιση</string>
|
||||
<string name="display_settings">Οθόνη</string>
|
||||
<string name="threed_building">3D κτίρια</string>
|
||||
<string name="arrived_exclamation_msg">Φτάσατε!</string>
|
||||
<string name="drive_now">Οδήγηση τώρα</string>
|
||||
<string name="stop_action_title">Διακοπή</string>
|
||||
<string name="avoid_highways_row_title">Αποφυγή αυτοκινητοδρόμων</string>
|
||||
<string name="avoid_tolls_row_title">Αποφυγή διοδίων</string>
|
||||
<string name="no_places">Δεν βρέθηκαν τοποθεσίες</string>
|
||||
<string name="recent_destinations">Πρόσφατοι προορισμοί</string>
|
||||
<string name="contacts">Επαφές</string>
|
||||
<string name="favorites">Αγαπημένα</string>
|
||||
<string name="recent_Item_deleted">Το πρόσφατο στοιχείο διαγράφηκε</string>
|
||||
<string name="route_preview">Προεπισκόπηση διαδρομής</string>
|
||||
<string name="display">Εμφάνιση</string>
|
||||
<string name="navigation_settings">Πλοήγηση</string>
|
||||
<string name="settings_action_title">Ρυθμίσεις</string>
|
||||
<string name="accept_action_title">Αποδοχή</string>
|
||||
<string name="reject_action_title">Απόρριψη</string>
|
||||
<string name="ok_action_title">OK</string>
|
||||
<string name="search_action_title">Αναζήτηση</string>
|
||||
<string name="use_car_location">Χρήση τοποθεσίας αυτοκινήτου</string>
|
||||
<string name="tomtom">TomTom</string>
|
||||
<string name="options">Επιλογές</string>
|
||||
<string name="tomtom_api_key">Κλειδί API TomTom</string>
|
||||
<string name="use_car_settings">Χρήση ρυθμίσεων αυτοκινήτου</string>
|
||||
<string name="exit_number">Αριθμός εξόδου</string>
|
||||
<string name="navigation_icon_description">Εικονίδιο πλοήγησης</string>
|
||||
<string name="distance_units">Μονάδες απόστασης</string>
|
||||
<string name="automaticaly">Αυτόματα</string>
|
||||
<string name="kilometer">Χιλιόμετρα</string>
|
||||
<string name="miles">Μίλια</string>
|
||||
<string name="audio_settings">Φωνητική καθοδήγηση</string>
|
||||
<string name="muted">Σίγαση</string>
|
||||
<string name="unmuted">Ήχος ενεργός</string>
|
||||
<string name="alerts_only">Μόνο ειδοποιήσεις</string>
|
||||
</resources>
|
||||
48
common/data/src/main/res/values-pl/strings.xml
Normal file
48
common/data/src/main/res/values-pl/strings.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="speed_camera">Fotoradar</string>
|
||||
<string name="exit_action_title">Odrzuć</string>
|
||||
<string name="fuel_station">Stacja paliw</string>
|
||||
<string name="pharmacy">Apteka</string>
|
||||
<string name="charging_station">Stacja ładowania</string>
|
||||
<string name="category_title">Kategoria</string>
|
||||
<string name="on_action_title">Włączone</string>
|
||||
<string name="off_action_title">Wyłączone</string>
|
||||
<string name="use_telephon_settings">Użyj ustawień telefonu</string>
|
||||
<string name="dark_mode">Tryb ciemny</string>
|
||||
<string name="display_settings">Wyświetlacz</string>
|
||||
<string name="threed_building">Budynki 3D</string>
|
||||
<string name="arrived_exclamation_msg">Dotarto do celu!</string>
|
||||
<string name="drive_now">Jedź teraz</string>
|
||||
<string name="stop_action_title">Zatrzymaj</string>
|
||||
<string name="avoid_highways_row_title">Unikaj autostrad</string>
|
||||
<string name="avoid_tolls_row_title">Unikaj opłat drogowych</string>
|
||||
<string name="no_places">Brak miejsc</string>
|
||||
<string name="recent_destinations">Ostatnie cele</string>
|
||||
<string name="contacts">Kontakty</string>
|
||||
<string name="favorites">Ulubione</string>
|
||||
<string name="recent_Item_deleted">Usunięto ostatni element</string>
|
||||
<string name="route_preview">Podgląd trasy</string>
|
||||
<string name="display">Wyświetlanie</string>
|
||||
<string name="navigation_settings">Nawigacja</string>
|
||||
<string name="settings_action_title">Ustawienia</string>
|
||||
<string name="accept_action_title">Akceptuj</string>
|
||||
<string name="reject_action_title">Odrzuć</string>
|
||||
<string name="ok_action_title">OK</string>
|
||||
<string name="search_action_title">Szukaj</string>
|
||||
<string name="use_car_location">Użyj lokalizacji samochodu</string>
|
||||
<string name="tomtom">TomTom</string>
|
||||
<string name="options">Opcje</string>
|
||||
<string name="tomtom_api_key">Klucz API TomTom</string>
|
||||
<string name="use_car_settings">Użyj ustawień samochodu</string>
|
||||
<string name="exit_number">Numer zjazdu</string>
|
||||
<string name="navigation_icon_description">Ikona nawigacji</string>
|
||||
<string name="distance_units">Jednostki odległości</string>
|
||||
<string name="automaticaly">Automatycznie</string>
|
||||
<string name="kilometer">Kilometry</string>
|
||||
<string name="miles">Mile</string>
|
||||
<string name="audio_settings">Wskazówki głosowe</string>
|
||||
<string name="muted">Wyciszony</string>
|
||||
<string name="unmuted">Dźwięk włączony</string>
|
||||
<string name="alerts_only">Tylko ostrzeżenia</string>
|
||||
</resources>
|
||||
@@ -34,7 +34,7 @@
|
||||
<string name="osrm" translatable="false">Osrm</string>
|
||||
<string name="routing_engine" translatable="false">Routing engine</string>
|
||||
<string name="use_car_location">Use car location</string>
|
||||
<string name="tomtom">TomTom\t</string>
|
||||
<string name="tomtom" translatable="false">TomTom\t</string>
|
||||
<string name="options">Options</string>
|
||||
<string name="tomtom_api_key">TomTom ApiKey</string>
|
||||
<string name="use_car_settings">Use car settings</string>
|
||||
@@ -44,4 +44,8 @@
|
||||
<string name="automaticaly">Automaticaly</string>
|
||||
<string name="kilometer">Kilometer</string>
|
||||
<string name="miles">Miles</string>
|
||||
<string name="audio_settings">Guidance audio</string>
|
||||
<string name="muted">Muted</string>
|
||||
<string name="unmuted">Unmuted</string>
|
||||
<string name="alerts_only">Alerts only</string>
|
||||
</resources>
|
||||
@@ -36,10 +36,11 @@ rootProject.name = "Navigation"
|
||||
include(
|
||||
":",
|
||||
":app",
|
||||
":automotive",
|
||||
":common",
|
||||
":common:data",
|
||||
":common:car",
|
||||
":common:data",
|
||||
)
|
||||
|
||||
|
||||
include(":automotive")
|
||||
//include(":automotive")
|
||||
|
||||
Reference in New Issue
Block a user