Refactoring

This commit is contained in:
Dimitris
2025-12-10 17:08:25 +01:00
parent aeca6ff237
commit a02673af36
92 changed files with 557 additions and 1643 deletions

View File

@@ -14,8 +14,8 @@ android {
applicationId = "com.kouros.navigation" applicationId = "com.kouros.navigation"
minSdk = 33 minSdk = 33
targetSdk = 36 targetSdk = 36
versionCode = 6 versionCode = 7
versionName = "0.1.3.6" versionName = "0.1.3.7"
base.archivesName = "navi-$versionName" base.archivesName = "navi-$versionName"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -93,6 +93,7 @@ dependencies {
implementation(libs.androidx.compose.material3.window.size.class1) implementation(libs.androidx.compose.material3.window.size.class1)
implementation(libs.androidx.compose.ui.graphics) implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.window) implementation(libs.androidx.window)
implementation(libs.androidx.compose.foundation.layout)
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)

View File

@@ -13,14 +13,10 @@ import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.annotation.RequiresPermission import androidx.annotation.RequiresPermission
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.BottomSheetScaffold import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.Card
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -31,31 +27,23 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableDoubleStateOf import androidx.compose.runtime.mutableDoubleStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.window.layout.WindowMetricsCalculator
import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices import com.google.android.gms.location.LocationServices
import com.kouros.android.cars.carappservice.R import com.kouros.navigation.data.Constants.homeLocation
import com.kouros.navigation.car.map.BuildingLayer
import com.kouros.navigation.car.map.NavigationImage
import com.kouros.navigation.car.map.RouteLayer
import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.data.StepData import com.kouros.navigation.data.StepData
import com.kouros.navigation.data.nominatim.SearchResult
import com.kouros.navigation.model.MockLocation import com.kouros.navigation.model.MockLocation
import com.kouros.navigation.model.RouteModel import com.kouros.navigation.model.RouteModel
import com.kouros.navigation.model.ViewModel import com.kouros.navigation.model.ViewModel
import com.kouros.navigation.ui.theme.NavigationTheme import com.kouros.navigation.ui.theme.NavigationTheme
import com.kouros.navigation.utils.NavigationUtils
import com.kouros.navigation.utils.bearing import com.kouros.navigation.utils.bearing
import com.kouros.navigation.utils.calculateZoom import com.kouros.navigation.utils.calculateZoom
import com.kouros.navigation.utils.location import com.kouros.navigation.utils.location
@@ -63,18 +51,12 @@ import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.CameraPosition
import org.maplibre.compose.camera.rememberCameraState
import org.maplibre.compose.location.DesiredAccuracy import org.maplibre.compose.location.DesiredAccuracy
import org.maplibre.compose.location.LocationTrackingEffect import org.maplibre.compose.location.Location
import org.maplibre.compose.location.UserLocationState
import org.maplibre.compose.location.rememberDefaultLocationProvider import org.maplibre.compose.location.rememberDefaultLocationProvider
import org.maplibre.compose.location.rememberUserLocationState import org.maplibre.compose.location.rememberUserLocationState
import org.maplibre.compose.map.MapOptions
import org.maplibre.compose.map.MaplibreMap
import org.maplibre.compose.map.OrnamentOptions
import org.maplibre.compose.sources.getBaseSource
import org.maplibre.compose.style.BaseStyle
import org.maplibre.spatialk.geojson.Position import org.maplibre.spatialk.geojson.Position
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
@@ -88,15 +70,19 @@ class MainActivity : ComponentActivity() {
var tilt = 50.0 var tilt = 50.0
val useMock = true val useMock = true
val instruction: MutableLiveData<StepData> by lazy { val stepData: MutableLiveData<StepData> by lazy {
MutableLiveData<StepData>() MutableLiveData<StepData>()
} }
var lastLocation = location(0.0, 0.0) var lastLocation = location(0.0, 0.0)
val observer = Observer<String> { newRoute -> val observer = Observer<String> { newRoute ->
routeModel.startNavigation(newRoute) if (newRoute.isNotEmpty()) {
routeData.value = routeModel.route.routeGeoJson routeModel.startNavigation(newRoute)
routeData.value = routeModel.route.routeGeoJson
//mock.setMockLocation(homeLocation.latitude, homeLocation.longitude)
simulate()
}
} }
val cameraPosition = MutableLiveData( val cameraPosition = MutableLiveData(
CameraPosition( CameraPosition(
@@ -129,8 +115,8 @@ class MainActivity : ComponentActivity() {
if (useMock) { if (useMock) {
mock = MockLocation(locationManager) mock = MockLocation(locationManager)
mock.setMockLocation( mock.setMockLocation(
Constants.homeLocation.latitude, homeLocation.latitude,
Constants.homeLocation.longitude homeLocation.longitude
) )
} }
enableEdgeToEdge() enableEdgeToEdge()
@@ -139,6 +125,21 @@ class MainActivity : ComponentActivity() {
} }
} }
@SuppressLint("MissingPermission")
@Composable
fun CheckPermissionScreen() {
val permissions = listOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
)
PermissionScreen(
permissions = permissions,
requiredPermissions = listOf(permissions.first()),
onGranted = {
Content()
},
)
}
@SuppressLint("AutoboxingStateCreation") @SuppressLint("AutoboxingStateCreation")
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -146,6 +147,8 @@ class MainActivity : ComponentActivity() {
fun Content() { fun Content() {
val scaffoldState = rememberBottomSheetScaffoldState() val scaffoldState = rememberBottomSheetScaffoldState()
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
val locationProvider = rememberDefaultLocationProvider( val locationProvider = rememberDefaultLocationProvider(
updateInterval = 0.5.seconds, updateInterval = 0.5.seconds,
desiredAccuracy = DesiredAccuracy.Highest desiredAccuracy = DesiredAccuracy.Highest
@@ -157,7 +160,15 @@ class MainActivity : ComponentActivity() {
if (locationState.value != null) { if (locationState.value != null) {
latitude = locationState.value!!.position.latitude latitude = locationState.value!!.position.latitude
} }
val step: StepData? by instruction.observeAsState() val step: StepData? by stepData.observeAsState()
fun openSheet() {
scope.launch { scaffoldState.bottomSheetState.expand() }
}
fun closeSheet() {
scope.launch { scaffoldState.bottomSheetState.partialExpand() }
}
NavigationTheme { NavigationTheme {
BottomSheetScaffold( BottomSheetScaffold(
@@ -167,7 +178,7 @@ class MainActivity : ComponentActivity() {
scaffoldState = scaffoldState, scaffoldState = scaffoldState,
sheetPeekHeight = 128.dp, sheetPeekHeight = 128.dp,
sheetContent = { sheetContent = {
SheetContent(latitude, step) SheetContent(latitude, step) { closeSheet() }
}, },
) { innerPadding -> ) { innerPadding ->
Box( Box(
@@ -176,117 +187,35 @@ class MainActivity : ComponentActivity() {
.padding(innerPadding), .padding(innerPadding),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
Map(userLocationState, step) MapView(applicationContext,userLocationState, step, cameraPosition, routeData, tilt)
} }
} }
} }
} }
@Composable @Composable
fun SheetContent(locationState: Double, step: StepData?) { fun SheetContent(locationState: Double, step: StepData?, closeSheet: () -> Unit) {
if (!routeModel.isNavigating()) { if (!routeModel.isNavigating()) {
SearchSheet(applicationContext, viewModel, lastLocation) SearchSheet(applicationContext, viewModel, lastLocation) { closeSheet() }
} else { } else {
NavigationSheet( routeModel, step, { simulate() }) NavigationSheet(
} routeModel, step!!,
// to recomposite SheetContent ! { stopNavigation { closeSheet() } },
Text("State $locationState") { simulateNavigation() }
}
@Composable
fun NavigationInfo(step: StepData?) {
Card {
Column {
Icon(
painter = painterResource(R.drawable.ic_turn_normal_right),
contentDescription = stringResource(id = R.string.accept_action_title)
)
if (step != null) {
Text(text = step.instruction, fontSize = 25.sp)
}
}
}
}
@Composable
fun Map(userLocationState: UserLocationState, step: StepData?) {
Column {
if (step != null) {
NavigationInfo(step)
}
MapView(userLocationState)
}
}
@Composable
fun MapView(userLocationState: UserLocationState) {
val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this)
val width = metrics.bounds.width()
val height = metrics.bounds.height()
val paddingValues = PaddingValues(start = 0.dp, top = 350.dp)
val position: CameraPosition? by cameraPosition.observeAsState()
val route: String? by routeData.observeAsState()
val cameraState =
rememberCameraState(
firstPosition =
CameraPosition(
target = Position(
position!!.target.latitude,
position!!.target.longitude
),
zoom = 15.0,
)
) )
Box (contentAlignment = Alignment.Center) {
MaplibreMap(
options = MapOptions(
ornamentOptions =
OrnamentOptions(isScaleBarEnabled = false)
),
cameraState = cameraState,
baseStyle = BaseStyle.Uri(Constants.STYLE),
) {
getBaseSource(id = "openmaptiles")?.let { tiles ->
if (!NavigationUtils.getBooleanKeyValue(
context = applicationContext,
Constants.SHOW_THREED_BUILDING
)
) {
BuildingLayer(tiles)
}
RouteLayer(route, "", position!!.zoom)
}
if (userLocationState.location != null) {
///PuckState(cameraState, userLocationState)
}
}
LocationTrackingEffect(
locationState = userLocationState,
) {
cameraState.animateTo(
finalPosition = CameraPosition(
bearing = position!!.bearing,
zoom = position!!.zoom,
target = position!!.target,
tilt = tilt,
padding = paddingValues
),
duration = 1.seconds
)
}
NavigationImage(paddingValues, width, height /6, "")
} }
// For recomposition!
Text("$locationState", fontSize = 12.sp)
} }
fun updateLocation(location: org.maplibre.compose.location.Location?) { fun updateLocation(location: Location?) {
if (location != null if (location != null
&& lastLocation.latitude != location.position.latitude && lastLocation.latitude != location.position.latitude
&& lastLocation.longitude != location.position.longitude) { && lastLocation.longitude != location.position.longitude
) {
if (routeModel.isNavigating()) { if (routeModel.isNavigating()) {
routeModel.updateLocation(lastLocation) routeModel.updateLocation(lastLocation)
instruction.value = routeModel.currentStep() stepData.value = routeModel.currentStep()
} }
val currentLocation = location(location.position.longitude, location.position.latitude) val currentLocation = location(location.position.longitude, location.position.latitude)
val bearing = bearing(lastLocation, currentLocation, cameraPosition.value!!.bearing) val bearing = bearing(lastLocation, currentLocation, cameraPosition.value!!.bearing)
@@ -306,6 +235,17 @@ class MainActivity : ComponentActivity() {
} }
} }
fun stopNavigation(closeSheet: () -> Unit) {
closeSheet()
routeModel.stopNavigation()
routeData.value = ""
stepData.value = StepData("", 0.0, 0, 0, 0, 0.0)
}
fun simulateNavigation() {
simulate()
}
private fun checkMockLocationEnabled() { private fun checkMockLocationEnabled() {
try { try {
// Check if mock location is enabled for this app // Check if mock location is enabled for this app
@@ -330,24 +270,9 @@ class MainActivity : ComponentActivity() {
} }
} }
@SuppressLint("MissingPermission")
@Composable
fun CheckPermissionScreen() {
val permissions = listOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
)
PermissionScreen(
permissions = permissions,
requiredPermissions = listOf(permissions.first()),
onGranted = {
Content()
},
)
}
@OptIn(DelicateCoroutinesApi::class) @OptIn(DelicateCoroutinesApi::class)
fun simulate() = GlobalScope.async { fun simulate() = GlobalScope.async {
for ((i, loc) in routeModel.route.waypoints.withIndex()) { for ((_, loc) in routeModel.route.waypoints.withIndex()) {
if (routeModel.isNavigating()) { if (routeModel.isNavigating()) {
mock.setMockLocation(loc[1], loc[0]) mock.setMockLocation(loc[1], loc[0])
delay(1000L) // delay(1000L) //

View File

@@ -0,0 +1,103 @@
package com.kouros.navigation.ui
import android.content.Context
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.unit.dp
import androidx.lifecycle.MutableLiveData
import androidx.window.layout.WindowMetricsCalculator
import com.kouros.navigation.car.map.BuildingLayer
import com.kouros.navigation.car.map.NavigationImage
import com.kouros.navigation.car.map.RouteLayer
import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.StepData
import com.kouros.navigation.utils.NavigationUtils
import org.maplibre.compose.camera.CameraPosition
import org.maplibre.compose.camera.rememberCameraState
import org.maplibre.compose.location.LocationTrackingEffect
import org.maplibre.compose.location.UserLocationState
import org.maplibre.compose.map.MapOptions
import org.maplibre.compose.map.MaplibreMap
import org.maplibre.compose.map.OrnamentOptions
import org.maplibre.compose.sources.getBaseSource
import org.maplibre.compose.style.BaseStyle
import org.maplibre.spatialk.geojson.Position
import kotlin.time.Duration.Companion.seconds
@Composable
fun MapView(
applicationContext: Context,
userLocationState: UserLocationState,
step: StepData?,
cameraPosition: MutableLiveData<CameraPosition>,
routeData: MutableLiveData<String>,
tilt: Double
) {
val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(applicationContext)
val width = metrics.bounds.width()
val height = metrics.bounds.height()
val paddingValues = PaddingValues(start = 0.dp, top = 350.dp)
val position: CameraPosition? by cameraPosition.observeAsState()
val route: String? by routeData.observeAsState()
val cameraState =
rememberCameraState(
firstPosition =
CameraPosition(
target = Position(
position!!.target.latitude,
position!!.target.longitude
),
zoom = 15.0,
)
)
Column {
NavigationInfo(step)
Box(contentAlignment = Alignment.Center) {
MaplibreMap(
options = MapOptions(
ornamentOptions =
OrnamentOptions(isScaleBarEnabled = false)
),
cameraState = cameraState,
baseStyle = BaseStyle.Uri(Constants.STYLE),
) {
getBaseSource(id = "openmaptiles")?.let { tiles ->
if (!NavigationUtils.getBooleanKeyValue(
context = applicationContext,
Constants.SHOW_THREED_BUILDING
)
) {
BuildingLayer(tiles)
}
RouteLayer(route, "", position!!.zoom)
}
if (userLocationState.location != null) {
///PuckState(cameraState, userLocationState)
}
}
LocationTrackingEffect(
locationState = userLocationState,
) {
cameraState.animateTo(
finalPosition = CameraPosition(
bearing = position!!.bearing,
zoom = position!!.zoom,
target = position!!.target,
tilt = tilt,
padding = paddingValues
),
duration = 1.seconds
)
}
NavigationImage(paddingValues, width, height / 6, "")
}
}
}

View File

@@ -0,0 +1,51 @@
package com.kouros.navigation.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Card
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.kouros.data.R
import com.kouros.navigation.data.StepData
import com.kouros.navigation.utils.round
@Composable
fun NavigationInfo(step: StepData?) {
if (step != null && step.instruction.isNotEmpty()) {
Card(modifier = Modifier.padding(top = 60.dp)) {
Column() {
Row {
Icon(
painter = painterResource(step.icon),
contentDescription = stringResource(id = R.string.accept_action_title),
modifier = Modifier.size(48.dp, 48.dp),
)
Column {
if (step.leftStepDistance < 1000) {
Text(text = "${step.leftStepDistance.toInt()} m", fontSize = 25.sp)
} else {
Text(
text = "${(step.leftStepDistance / 1000).round(1)} km",
fontSize = 25.sp
)
}
Text(text = step.instruction, fontSize = 20.sp)
}
Icon(
painter = painterResource(step.icon),
contentDescription = stringResource(id = R.string.accept_action_title),
modifier = Modifier.size(48.dp, 48.dp),
)
}
}
}
}
}

View File

@@ -1,34 +1,45 @@
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.kouros.android.cars.carappservice.R import androidx.compose.ui.unit.sp
import com.kouros.data.R
import com.kouros.navigation.data.StepData import com.kouros.navigation.data.StepData
import com.kouros.navigation.model.RouteModel import com.kouros.navigation.model.RouteModel
import kotlinx.coroutines.Deferred import com.kouros.navigation.utils.formatDateTime
import com.kouros.navigation.utils.round
@Composable @Composable
fun NavigationSheet( fun NavigationSheet(
routeModel: RouteModel, routeModel: RouteModel,
step: StepData?, step: StepData,
simulate: () -> Unit stopNavigation: () -> Unit,
simulateNavigation: () -> Unit,
) { ) {
val distance = step.leftDistance.round(1)
Column { Column {
//Text("${routeModel.travelLeftTime()}") FlowRow(horizontalArrangement= Arrangement.SpaceEvenly) {
if (step != null) Text(formatDateTime(step.arrivalTime), fontSize = 22.sp)
Text("${step.leftDistance / 1000} km") Spacer(Modifier.size(30.dp))
Text("$distance km", fontSize = 22.sp)
}
HorizontalDivider() HorizontalDivider()
Row() { FlowRow(horizontalArrangement = Arrangement.SpaceEvenly) {
if (routeModel.isNavigating()) { if (routeModel.isNavigating()) {
Button(onClick = { Button(onClick = {
routeModel.stopNavigation() stopNavigation()
}) { }) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_close_white_24dp), painter = painterResource(id = R.drawable.ic_close_white_24dp),
@@ -36,8 +47,9 @@ fun NavigationSheet(
modifier = Modifier.size(24.dp, 24.dp), modifier = Modifier.size(24.dp, 24.dp),
) )
} }
Spacer(Modifier.size(30.dp))
Button(onClick = { Button(onClick = {
simulate() simulateNavigation()
}) { }) {
Icon( Icon(
painter = painterResource(id = R.drawable.assistant_navigation_48px), painter = painterResource(id = R.drawable.assistant_navigation_48px),

View File

@@ -22,8 +22,6 @@ import androidx.compose.material3.SearchBar
import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.SearchBarDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
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.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -38,7 +36,7 @@ import androidx.compose.ui.semantics.isTraversalGroup
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.traversalIndex import androidx.compose.ui.semantics.traversalIndex
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.kouros.android.cars.carappservice.R import com.kouros.data.R
import com.kouros.navigation.data.Place import com.kouros.navigation.data.Place
import com.kouros.navigation.data.PlaceColor import com.kouros.navigation.data.PlaceColor
import com.kouros.navigation.data.nominatim.SearchResult import com.kouros.navigation.data.nominatim.SearchResult
@@ -46,7 +44,12 @@ import com.kouros.navigation.model.ViewModel
import com.kouros.navigation.utils.location import com.kouros.navigation.utils.location
@Composable @Composable
fun SearchSheet(applicationContext: Context, viewModel: ViewModel, location: Location) { fun SearchSheet(
applicationContext: Context,
viewModel: ViewModel,
location: Location,
closeSheet: () -> Unit
) {
val searchResults = mutableListOf<SearchResult>() val searchResults = mutableListOf<SearchResult>()
val recentPlaces = viewModel.places.observeAsState() val recentPlaces = viewModel.places.observeAsState()
val search = viewModel.searchPlaces.observeAsState() val search = viewModel.searchPlaces.observeAsState()
@@ -63,7 +66,9 @@ fun SearchSheet(applicationContext: Context, viewModel: ViewModel, location: Loc
searchResults = searchResults, searchResults = searchResults,
viewModel = viewModel, viewModel = viewModel,
context = applicationContext, context = applicationContext,
location = location location = location,
closeSheet = {closeSheet()}
) )
} }
} }
@@ -77,7 +82,8 @@ fun SearchSheet(applicationContext: Context, viewModel: ViewModel, location: Loc
searchResults = searchResults, searchResults = searchResults,
viewModel = viewModel, viewModel = viewModel,
context = applicationContext, context = applicationContext,
location = location location = location,
closeSheet = {closeSheet()}
) )
} }
} }
@@ -93,6 +99,7 @@ fun SearchBar(
viewModel: ViewModel, viewModel: ViewModel,
context: Context, context: Context,
location: Location, location: Location,
closeSheet: () -> Unit
) { ) {
var expanded by rememberSaveable { mutableStateOf(true) } var expanded by rememberSaveable { mutableStateOf(true) }
Box( Box(
@@ -121,19 +128,19 @@ fun SearchBar(
}, },
expanded = expanded, expanded = expanded,
onExpandedChange = { expanded = it }, onExpandedChange = { expanded = it },
placeholder = { Text("Suchen") } placeholder = { Text(context.getString(R.string.search_action_title)) }
) )
}, },
expanded = expanded, expanded = expanded,
onExpandedChange = { expanded = it }, onExpandedChange = { expanded = it },
) { ) {
if (searchPlaces.isNotEmpty()) { if (searchPlaces.isNotEmpty()) {
Text("Recent places") Text(context.getString(R.string.recent_destinations))
RecentPlaces(searchPlaces, viewModel, context, location) RecentPlaces(searchPlaces, viewModel, context, location, closeSheet)
} }
if (searchResults.isNotEmpty()) { if (searchResults.isNotEmpty()) {
Text("Search places") Text("Search places")
SearchPlaces(searchResults, viewModel, context, location) SearchPlaces(searchResults, viewModel, context, location, closeSheet)
} }
} }
} }
@@ -149,6 +156,7 @@ private fun SearchPlaces(
viewModel: ViewModel, viewModel: ViewModel,
context: Context, context: Context,
location: Location, location: Location,
closeSheet: () -> Unit
) { ) {
val color = remember { PlaceColor } val color = remember { PlaceColor }
LazyColumn( LazyColumn(
@@ -171,6 +179,7 @@ private fun SearchPlaces(
val toLocation = val toLocation =
location(place.lon.toDouble(), place.lat.toDouble()) location(place.lon.toDouble(), place.lat.toDouble())
viewModel.loadRoute(context, location, toLocation) viewModel.loadRoute(context, location, toLocation)
closeSheet()
} }
.fillMaxWidth() .fillMaxWidth()
) )
@@ -186,7 +195,8 @@ private fun RecentPlaces(
recentPlaces: List<Place>, recentPlaces: List<Place>,
viewModel: ViewModel, viewModel: ViewModel,
context: Context, context: Context,
location: Location location: Location,
closeSheet: () -> Unit
) { ) {
val color = remember { PlaceColor } val color = remember { PlaceColor }
LazyColumn( LazyColumn(
@@ -207,6 +217,7 @@ private fun RecentPlaces(
.clickable { .clickable {
val toLocation = location(place.longitude, place.latitude) val toLocation = location(place.longitude, place.latitude)
viewModel.loadRoute(context, location, toLocation) viewModel.loadRoute(context, location, toLocation)
closeSheet()
} }
.fillMaxWidth() .fillMaxWidth()
) )

View File

@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins { plugins {
alias(libs.plugins.android.library) alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.android)
@@ -27,8 +29,10 @@ android {
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11
} }
kotlinOptions { kotlin {
jvmTarget = "11" compilerOptions {
jvmTarget = JvmTarget.JVM_11
}
} }
buildFeatures { buildFeatures {
compose = true compose = true
@@ -38,8 +42,7 @@ android {
dependencies { dependencies {
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.car.app) implementation(libs.androidx.car.app)
implementation(libs.androidx.compose.ui)
implementation(libs.ui)
implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.ui) implementation(libs.androidx.ui)
implementation(libs.maplibre.compose) implementation(libs.maplibre.compose)

View File

@@ -110,7 +110,6 @@ class NavigationSession : Session(), NavigationScreen.Listener {
if ((CarContext.ACTION_NAVIGATE == intent.action)) { if ((CarContext.ACTION_NAVIGATE == intent.action)) {
val uri = ("http://" + intent.dataString).toUri() val uri = ("http://" + intent.dataString).toUri()
val location = Location(LocationManager.GPS_PROVIDER) val location = Location(LocationManager.GPS_PROVIDER)
screenManager.popToRoot() screenManager.popToRoot()
screenManager.pushForResult( screenManager.pushForResult(
SearchScreen( SearchScreen(

View File

@@ -24,7 +24,7 @@ import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.kouros.android.cars.carappservice.R import com.kouros.data.R
import com.kouros.navigation.data.NavigationColor import com.kouros.navigation.data.NavigationColor
import com.kouros.navigation.data.RouteColor import com.kouros.navigation.data.RouteColor
import com.kouros.navigation.data.SpeedColor import com.kouros.navigation.data.SpeedColor

View File

@@ -28,7 +28,6 @@ import androidx.car.app.navigation.model.Maneuver
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.android.cars.carappservice.R
import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD
import com.kouros.navigation.data.ManeuverType import com.kouros.navigation.data.ManeuverType
import com.kouros.navigation.model.RouteModel import com.kouros.navigation.model.RouteModel
@@ -40,34 +39,14 @@ class RouteCarModel() : RouteModel() {
/** Returns the current [Step] with information such as the cue text and images. */ /** Returns the current [Step] with information such as the cue text and images. */
fun currentStep(carContext: CarContext): Step { fun currentStep(carContext: CarContext): Step {
val maneuver = route.currentManeuver()
val maneuverType = maneuver.type
val stepData = currentStep() val stepData = currentStep()
var routing: (Pair<Int, CarIcon>)
routing = if (hasArrived(maneuverType)) {
routingData(maneuverType, carContext)
} else {
routingData(ManeuverType.None.value, carContext)
}
when (stepData.leftDistance) {
in 0.0..NEXT_STEP_THRESHOLD -> {
if (route.currentManeuverIndex < route.maneuvers.size) {
val maneuver = route.nextManeuver()
val maneuverType = maneuver.type
routing = routingData(maneuverType, carContext)
}
}
}
val currentStepCueWithImage: SpannableString = val currentStepCueWithImage: SpannableString =
createString(stepData.instruction) createString(stepData.instruction)
val step = val step =
Step.Builder(currentStepCueWithImage) Step.Builder(currentStepCueWithImage)
.setManeuver( .setManeuver(
Maneuver.Builder(routing.first) Maneuver.Builder(stepData.maneuverType)
.setIcon(routing.second) .setIcon(createCarIcon(carContext, stepData.icon))
.build() .build()
) )
.setRoad(destination.street!!) .setRoad(destination.street!!)
@@ -77,130 +56,40 @@ class RouteCarModel() : RouteModel() {
/** Returns the next [Step] with information such as the cue text and images. */ /** Returns the next [Step] with information such as the cue text and images. */
fun nextStep(carContext: CarContext): Step? { fun nextStep(carContext: CarContext): Step? {
val maneuver = route.nextManeuver() val stepData = nextStep()
val maneuverType = maneuver.type
val routing = routingData(maneuverType, carContext)
var text = ""
val distanceLeft = leftStepDistance()
when (distanceLeft) {
in 0.0..NEXT_STEP_THRESHOLD -> {
return null
}
else -> {
if (maneuver.streetNames != null && maneuver.streetNames!!.isNotEmpty()) {
text = maneuver.streetNames!![0]
}
}
}
val currentStepCueWithImage: SpannableString = val currentStepCueWithImage: SpannableString =
createString(text) createString(stepData.instruction)
val step = val step =
Step.Builder(currentStepCueWithImage) Step.Builder(currentStepCueWithImage)
.setManeuver( .setManeuver(
Maneuver.Builder(routing.first) Maneuver.Builder(stepData.maneuverType)
.setIcon(routing.second) .setIcon(createCarIcon(carContext, stepData.icon))
.build() .build()
) )
.build() .build()
return step return step
} }
fun routingData(routeManeuverType: Int, carContext: CarContext): (Pair<Int, CarIcon>) {
var type = Maneuver.TYPE_DEPART
var currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change)
when (routeManeuverType) {
ManeuverType.None.value -> {
type = Maneuver.TYPE_STRAIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change)
}
ManeuverType.Destination.value,
ManeuverType.DestinationRight.value,
ManeuverType.DestinationLeft.value,
-> {
type = Maneuver.TYPE_DESTINATION
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_destination)
}
ManeuverType.Right.value -> {
type = Maneuver.TYPE_TURN_NORMAL_RIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_normal_right)
}
ManeuverType.Left.value -> {
type = Maneuver.TYPE_TURN_NORMAL_LEFT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_normal_left)
}
ManeuverType.RampRight.value -> {
type = Maneuver.TYPE_OFF_RAMP_SLIGHT_RIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_slight_right)
}
ManeuverType.RampLeft.value -> {
type = Maneuver.TYPE_TURN_NORMAL_LEFT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_normal_left)
}
ManeuverType.ExitRight.value -> {
type = Maneuver.TYPE_TURN_SLIGHT_RIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_slight_right)
}
ManeuverType.StayRight.value -> {
type = Maneuver.TYPE_KEEP_RIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change)
}
ManeuverType.StayLeft.value -> {
type = Maneuver.TYPE_KEEP_LEFT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change)
}
ManeuverType.RoundaboutEnter.value -> {
type = Maneuver.TYPE_ROUNDABOUT_ENTER_CCW
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_roundabout_ccw)
}
ManeuverType.RoundaboutExit.value -> {
type = Maneuver.TYPE_ROUNDABOUT_EXIT_CCW
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_roundabout_ccw)
}
}
maneuverType = type
return Pair(type, currentTurnIcon)
}
fun hasArrived(type: Int): Boolean {
return type == ManeuverType.DestinationRight.value
|| maneuverType == ManeuverType.Destination.value
|| maneuverType == ManeuverType.DestinationLeft.value
}
fun travelEstimate(): TravelEstimate { fun travelEstimate(): TravelEstimate {
val timeLeft = travelLeftTime() val timeLeft = travelLeftTime()
// Calculate the time to destination from the current time.
val nowUtcMillis = System.currentTimeMillis()
val timeToDestinationMillis = val timeToDestinationMillis =
TimeUnit.SECONDS.toMillis(timeLeft.toLong()) TimeUnit.SECONDS.toMillis(timeLeft.toLong())
val leftDistance = travelLeftDistance() val leftDistance = travelLeftDistance()
val displayUnit = if (leftDistance > 1.0) { val displayUnit = if (leftDistance > 1.0) {
Distance.UNIT_KILOMETERS Distance.UNIT_KILOMETERS
} else { } else {
Distance.UNIT_METERS Distance.UNIT_METERS
} }
val arivalTime = DateTimeWithZone.create(
arrivalTime(),
TimeZone.getTimeZone("Europe/Berlin")
)
return TravelEstimate.Builder( // The estimated distance to the destination. return TravelEstimate.Builder( // The estimated distance to the destination.
Distance.create( Distance.create(
leftDistance, leftDistance,
displayUnit displayUnit
), // Arrival time at the destination with the destination time zone. ), // Arrival time at the destination with the destination time zone.
arivalTime
DateTimeWithZone.create(
nowUtcMillis + timeToDestinationMillis,
TimeZone.getTimeZone("Europe/Berlin")
)
) )
.setRemainingTimeSeconds( .setRemainingTimeSeconds(
TimeUnit.MILLISECONDS.toSeconds( TimeUnit.MILLISECONDS.toSeconds(

View File

@@ -10,7 +10,7 @@ import androidx.car.app.model.ListTemplate
import androidx.car.app.model.Row import androidx.car.app.model.Row
import androidx.car.app.model.Template import androidx.car.app.model.Template
import androidx.car.app.model.Toggle import androidx.car.app.model.Toggle
import com.kouros.android.cars.carappservice.R import com.kouros.data.R
import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING
import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue
import com.kouros.navigation.utils.NavigationUtils.setBooleanKeyValue import com.kouros.navigation.utils.NavigationUtils.setBooleanKeyValue

View File

@@ -25,7 +25,7 @@ import androidx.car.app.notification.CarPendingIntent
import androidx.car.app.suggestion.model.Suggestion import androidx.car.app.suggestion.model.Suggestion
import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.IconCompat
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.kouros.android.cars.carappservice.R import com.kouros.data.R
import com.kouros.navigation.car.NavigationCarAppService import com.kouros.navigation.car.NavigationCarAppService
import com.kouros.navigation.car.SurfaceRenderer import com.kouros.navigation.car.SurfaceRenderer
import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.car.navigation.RouteCarModel

View File

@@ -9,7 +9,7 @@ import androidx.car.app.model.ListTemplate
import androidx.car.app.model.Row import androidx.car.app.model.Row
import androidx.car.app.model.Template import androidx.car.app.model.Template
import androidx.car.app.model.Toggle import androidx.car.app.model.Toggle
import com.kouros.android.cars.carappservice.R import com.kouros.data.R
import com.kouros.navigation.data.Constants.AVOID_MOTORWAY import com.kouros.navigation.data.Constants.AVOID_MOTORWAY
import com.kouros.navigation.data.Constants.AVOID_TOLLWAY import com.kouros.navigation.data.Constants.AVOID_TOLLWAY
import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue

View File

@@ -18,7 +18,7 @@ import androidx.car.app.model.Row
import androidx.car.app.model.Template import androidx.car.app.model.Template
import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.IconCompat
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.kouros.android.cars.carappservice.R import com.kouros.data.R
import com.kouros.navigation.car.SurfaceRenderer import com.kouros.navigation.car.SurfaceRenderer
import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants

View File

@@ -39,7 +39,7 @@ import androidx.car.app.navigation.model.MapController
import androidx.car.app.navigation.model.MapWithContentTemplate import androidx.car.app.navigation.model.MapWithContentTemplate
import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.IconCompat
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.kouros.android.cars.carappservice.R import com.kouros.data.R
import com.kouros.navigation.car.SurfaceRenderer import com.kouros.navigation.car.SurfaceRenderer
import com.kouros.navigation.car.navigation.NavigationMessage import com.kouros.navigation.car.navigation.NavigationMessage
import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.car.navigation.RouteCarModel

View File

@@ -14,7 +14,7 @@ import androidx.car.app.model.SearchTemplate.SearchCallback
import androidx.car.app.model.Template import androidx.car.app.model.Template
import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.IconCompat
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.kouros.android.cars.carappservice.R import com.kouros.data.R
import com.kouros.navigation.car.SurfaceRenderer import com.kouros.navigation.car.SurfaceRenderer
import com.kouros.navigation.data.Category import com.kouros.navigation.data.Category
import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants

View File

@@ -15,9 +15,7 @@
*/ */
package com.kouros.navigation.car.screen package com.kouros.navigation.car.screen
import android.content.Context
import androidx.car.app.CarContext import androidx.car.app.CarContext
import androidx.car.app.CarToast
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.Header import androidx.car.app.model.Header
@@ -25,10 +23,7 @@ import androidx.car.app.model.ItemList
import androidx.car.app.model.ListTemplate import androidx.car.app.model.ListTemplate
import androidx.car.app.model.Row import androidx.car.app.model.Row
import androidx.car.app.model.Template import androidx.car.app.model.Template
import androidx.car.app.model.Toggle import com.kouros.data.R
import androidx.core.content.edit
import com.kouros.android.cars.carappservice.R
import com.kouros.navigation.car.NavigationSession
/** A screen demonstrating selectable lists. */ /** A screen demonstrating selectable lists. */
class SettingsScreen( class SettingsScreen(

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M321,668L480,596L639,668L644,663L480,266L316,663L321,668ZM480,880Q398,880 325,848.5Q252,817 197.5,762.5Q143,708 111.5,635Q80,562 80,480Q80,397 111.5,324Q143,251 197.5,197Q252,143 325,111.5Q398,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,562 848.5,635Q817,708 763,762.5Q709,817 636,848.5Q563,880 480,880ZM480,820Q622,820 721,720.5Q820,621 820,480Q820,338 721,239Q622,140 480,140Q339,140 239.5,239Q140,338 140,480Q140,621 239.5,720.5Q339,820 480,820ZM480,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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 B

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M321,668L480,596L639,668L644,663L480,266L316,663L321,668ZM480,880Q398,880 325,848.5Q252,817 197.5,762.5Q143,708 111.5,635Q80,562 80,480Q80,397 111.5,324Q143,251 197.5,197Q252,143 325,111.5Q398,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,562 848.5,635Q817,708 763,762.5Q709,817 636,848.5Q563,880 480,880ZM480,820Q622,820 721,720.5Q820,621 820,480Q820,338 721,239Q622,140 480,140Q339,140 239.5,239Q140,338 140,480Q140,621 239.5,720.5Q339,820 480,820ZM480,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>

View File

@@ -1,21 +0,0 @@
<!--
Copyright 2024 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M12,1C5.93,1 1,5.93 1,12s4.93,11 11,11 11,-4.93 11,-11S18.07,1 12,1zM15.57,17L12,15.42 8.43,17l-0.37,-0.37L12,7l3.95,9.63 -0.38,0.37z"/>
</vector>

View File

@@ -1,21 +0,0 @@
<!--
Copyright 2023 Google LLC
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.
-->
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2L4.5,20.29l0.71,0.71L12,18l6.79,3 0.71,-0.71z"/>
</vector>

View File

@@ -1,26 +0,0 @@
<!--
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.
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M6.4,19 L5,17.6 10.6,12 5,6.4 6.4,5 12,10.6 17.6,5 19,6.4 13.4,12 19,17.6 17.6,19 12,13.4Z"/>
</vector>

View File

@@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>

View File

@@ -1,15 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="#000000">
<group android:scaleX="0.7888"
android:scaleY="0.7888"
android:translateX="101.376"
android:translateY="101.376">
<path
android:fillColor="@android:color/white"
android:pathData="M280,240L280,240L280,400Q280,400 280,481.5Q280,563 280,680Q280,701 280,721Q280,741 280,760L280,760Q280,760 280,760Q280,760 280,760L280,240ZM450,840L280,840Q247,840 223.5,816.5Q200,793 200,760L200,240L160,240L160,160L360,160L360,120L600,120L600,160L800,160L800,240L760,240L760,412Q743,407 720.5,403.5Q698,400 680,400L680,240L280,240L280,760Q280,760 280,760Q280,760 280,760L412,760Q418,781 428,801.5Q438,822 450,840ZM360,680L400,680Q400,617 420,576.5Q440,536 440,536L440,320L360,320L360,680ZM520,450Q537,439 558.5,428Q580,417 600,412L600,320L520,320L520,450ZM680,880Q597,880 538.5,821.5Q480,763 480,680Q480,597 538.5,538.5Q597,480 680,480Q763,480 821.5,538.5Q880,597 880,680Q880,763 821.5,821.5Q763,880 680,880ZM746,774L774,746L700,672L700,560L660,560L660,688L746,774Z"/>
</group>
</vector>

View File

@@ -1,26 +0,0 @@
<!--
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.
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,21 L10.55,19.7Q6.625,16.2 4.312,13.612Q2,11.025 2,8.15Q2,5.8 3.575,4.225Q5.15,2.65 7.5,2.65Q8.825,2.65 10,3.212Q11.175,3.775 12,4.75Q12.825,3.775 14,3.212Q15.175,2.65 16.5,2.65Q18.85,2.65 20.425,4.225Q22,5.8 22,8.15Q22,11.025 19.688,13.612Q17.375,16.2 13.45,19.7ZM12,18.3Q8.425,15.05 6.213,12.7Q4,10.35 4,8.15Q4,6.65 5,5.65Q6,4.65 7.5,4.65Q8.675,4.65 9.675,5.312Q10.675,5.975 11.05,7H12.95Q13.325,5.975 14.325,5.312Q15.325,4.65 16.5,4.65Q18,4.65 19,5.65Q20,6.65 20,8.15Q20,10.35 17.788,12.7Q15.575,15.05 12,18.3ZM12,18.3Q15.575,15.05 17.788,12.7Q20,10.35 20,8.15Q20,6.65 19,5.65Q18,4.65 16.5,4.65Q15.325,4.65 14.325,5.312Q13.325,5.975 12.95,7H11.05Q10.675,5.975 9.675,5.312Q8.675,4.65 7.5,4.65Q6,4.65 5,5.65Q4,6.65 4,8.15Q4,10.35 6.213,12.7Q8.425,15.05 12,18.3Z"/>
</vector>

View File

@@ -1,26 +0,0 @@
<!--
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.
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,21 L10.55,19.7Q6.625,16.2 4.312,13.612Q2,11.025 2,8.15Q2,5.8 3.575,4.225Q5.15,2.65 7.5,2.65Q8.825,2.65 10,3.212Q11.175,3.775 12,4.75Q12.825,3.775 14,3.212Q15.175,2.65 16.5,2.65Q18.85,2.65 20.425,4.225Q22,5.8 22,8.15Q22,11.025 19.688,13.612Q17.375,16.2 13.45,19.7ZM12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475ZM12,18.3Q15.575,15.05 17.788,12.7Q20,10.35 20,8.15Q20,6.65 19,5.65Q18,4.65 16.5,4.65Q15.325,4.65 14.325,5.312Q13.325,5.975 12.95,7H11.05Q10.675,5.975 9.675,5.312Q8.675,4.65 7.5,4.65Q6,4.65 5,5.65Q4,6.65 4,8.15Q4,10.35 6.213,12.7Q8.425,15.05 12,18.3Z"/>
</vector>

View File

@@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>

View File

@@ -1,28 +0,0 @@
<!--
Copyright 2021 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M15.54,5.54L13.77,7.3 12,5.54 10.23,7.3 8.46,5.54 12,2zM18.46,15.54l-1.76,-1.77L18.46,12l-1.76,-1.77 1.76,-1.77L22,12zM8.46,18.46l1.77,-1.76L12,18.46l1.77,-1.76 1.77,1.76L12,22zM5.54,8.46l1.76,1.77L5.54,12l1.76,1.77 -1.76,1.77L2,12z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
</vector>

View File

@@ -1,25 +0,0 @@
<!--
Copyright 2021 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,12c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM18,10.2C18,6.57 15.35,4 12,4s-6,2.57 -6,6.2c0,2.34 1.95,5.44 6,9.14 4.05,-3.7 6,-6.8 6,-9.14zM12,2c4.2,0 8,3.22 8,8.2 0,3.32 -2.67,7.25 -8,11.8 -5.33,-4.55 -8,-8.48 -8,-11.8C4,5.22 7.8,2 12,2z"
android:fillColor="#FFFFFF"/>
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 835 B

View File

@@ -1,25 +0,0 @@
<!--
Copyright 2021 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View File

@@ -1,25 +0,0 @@
<!--
Copyright 2021 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19,13H5v-2h14v2z"/>
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M190,840L160,810L480,80L800,810L770,840L480,708L190,840ZM258,742L480,644L702,742L480,228L258,742ZM480,644L480,644L480,644L480,644Z"/>
</vector>

View File

@@ -1,5 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M200,840L200,200Q200,167 223.5,143.5Q247,120 280,120L520,120Q520,143 520,160Q520,177 520,200L280,200Q280,200 280,200Q280,200 280,200L280,718L480,632L680,718L680,440Q703,440 720,440Q737,440 760,440L760,840L480,720L200,840ZM280,200L280,200Q280,200 280,200Q280,200 280,200L520,200Q520,200 520,200Q520,200 520,200Q520,200 520,200Q520,200 520,200L520,200L480,200L280,200ZM680,360L680,280L600,280L600,200L680,200L680,120L760,120L760,200L840,200L840,280L760,280L760,360L680,360Z"/>
</vector>

View File

@@ -1,5 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M713,360L600,247L656,190L713,247L854,105L911,162L713,360ZM200,840L200,200Q200,167 223.5,143.5Q247,120 280,120L520,120Q520,143 520,160Q520,177 520,200L280,200Q280,200 280,200Q280,200 280,200L280,718L480,632L680,718L680,440Q703,440 720,440Q737,440 760,440L760,840L480,720L200,840ZM280,200L280,200Q280,200 280,200Q280,200 280,200L520,200Q520,200 520,200Q520,200 520,200Q520,200 520,200Q520,200 520,200L520,200L480,200L280,200Z"/>
</vector>

View File

@@ -1,10 +0,0 @@
<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="M370,880L354,752Q341,747 329.5,740Q318,733 307,725L188,775L78,585L181,507Q180,500 180,493.5Q180,487 180,480Q180,473 180,466.5Q180,460 181,453L78,375L188,185L307,235Q318,227 330,220Q342,213 354,208L370,80L590,80L606,208Q619,213 630.5,220Q642,227 653,235L772,185L882,375L779,453Q780,460 780,466.5Q780,473 780,480Q780,487 780,493.5Q780,500 778,507L881,585L771,775L653,725Q642,733 630,740Q618,747 606,752L590,880L370,880ZM440,800L519,800L533,694Q564,686 590.5,670.5Q617,655 639,633L738,674L777,606L691,541Q696,527 698,511.5Q700,496 700,480Q700,464 698,448.5Q696,433 691,419L777,354L738,286L639,328Q617,305 590.5,289.5Q564,274 533,266L520,160L441,160L427,266Q396,274 369.5,289.5Q343,305 321,327L222,286L183,354L269,418Q264,433 262,448Q260,463 260,480Q260,496 262,511Q264,526 269,541L183,606L222,674L321,632Q343,655 369.5,670.5Q396,686 427,694L440,800ZM482,620Q540,620 581,579Q622,538 622,480Q622,422 581,381Q540,340 482,340Q423,340 382.5,381Q342,422 342,480Q342,538 382.5,579Q423,620 482,620ZM480,480L480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Z"/>
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M280,800L280,432Q280,407.25 297.63,389.62Q315.25,372 340,372L726,372L636,282L678,240L840,402L678,564L636,522L726,432L340,432Q340,432 340,432Q340,432 340,432L340,800L280,800Z"/>
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M280,800L280,432Q280,407.25 297.63,389.62Q315.25,372 340,372L726,372L636,282L678,240L840,402L678,564L636,522L726,432L340,432Q340,432 340,432Q340,432 340,432L340,800L280,800Z"/>
</vector>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_delete_background"/>
<foreground android:drawable="@drawable/ic_delete_foreground"/>
</adaptive-icon>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_delete_background"/>
<foreground android:drawable="@drawable/ic_delete_foreground"/>
</adaptive-icon>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,308 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="exit_action_title" msgid="9086586388884500731">"Beenden"</string>
<string name="refresh_action_title" msgid="3674260822403151377">"Aktualisieren"</string>
<string name="close_action_title" msgid="2661907510124308560">"Schließen"</string>
<string name="grant_access_action_title" msgid="4033140828804350723">"Zugriff gewähren"</string>
<string name="enable_location_action_title" msgid="8181862247222797044">"Standortermittlung aktivieren"</string>
<string name="cancel_action_title" msgid="1149738685397349236">"Ignorieren"</string>
<string name="stop_action_title" msgid="1187619482795416314">"Stopp"</string>
<string name="more_action_title" msgid="1039516575011403837">"Mehr"</string>
<string name="call_action_title" msgid="6218977436905001611">"Anrufen"</string>
<string name="options_action_title" msgid="1168121856107932984">"Optionen"</string>
<string name="search_action_title" msgid="3483459674263446335">"Suchen"</string>
<string name="checked_action_title" msgid="906023941445896399">"Aktiviert"</string>
<string name="unchecked_action_title" msgid="802503415474307811">"Deaktiviert"</string>
<string name="on_action_title" msgid="4129601573763429611">"An"</string>
<string name="off_action_title" msgid="8669201170189204848">"Aus"</string>
<string name="settings_action_title" msgid="8616900063253887861">"Einstellungen"</string>
<string name="accept_action_title" msgid="4899660585470647578">"Annehmen"</string>
<string name="reject_action_title" msgid="6730366705938402668">"Ablehnen"</string>
<string name="ok_action_title" msgid="7128494973966098611">"OK"</string>
<string name="throw_action_title" msgid="7163710562670220163">"Auslösen"</string>
<string name="commute_action_title" msgid="2585755255290185096">"Arbeitsweg"</string>
<string name="sign_out_action_title" msgid="1653943000866713010">"Abmelden"</string>
<string name="yes_action_title" msgid="5507096013762092189">"Ja"</string>
<string name="no_action_title" msgid="1452124604210014010">"Nein"</string>
<string name="zoomed_in_toast_msg" msgid="8915301497303842649">"Herangezoomt"</string>
<string name="zoomed_out_toast_msg" msgid="6260981223227212493">"Herausgezoomt"</string>
<string name="favorites" msgid="522064494016370117">"Favoriten"</string>
<string name="not_favorite_toast_msg" msgid="6831181108681007428">"Kein Favorit!"</string>
<string name="nav_requested_toast_msg" msgid="6696525973145493908">"Navigation angefragt"</string>
<string name="selected_route_toast_msg" msgid="3149189677200086656">"Ausgewählte Route"</string>
<string name="visible_routes_toast_msg" msgid="7065558153736024203">"Sichtbare Routen"</string>
<string name="settings_toast_msg" msgid="7697794473002342727">"Einstellungen angeklickt"</string>
<string name="parked_toast_msg" msgid="2532422265890824446">"Aktion „Geparkt“"</string>
<string name="more_toast_msg" msgid="5938288138225509885">"„Mehr“ angeklickt"</string>
<string name="grant_location_permission_toast_msg" msgid="268046297444808010">"Standortermittlung erlauben, um aktuellen Standort anzuzeigen"</string>
<string name="navigate" msgid="2713090390373996139">"Navigieren"</string>
<string name="dial" msgid="3145707439707628311">"Wählen"</string>
<string name="address" msgid="9010635942573581302">"Adresse"</string>
<string name="phone" msgid="2504766809811627577">"Smartphone"</string>
<string name="fail_start_nav" msgid="6921321606009212189">"Fehler beim Starten der Navigation"</string>
<string name="fail_start_dialer" msgid="1471602619507306261">"Fehler beim Starten des Telefons"</string>
<string name="display_settings" msgid="5726880972110281095">"Einstellungen für die Anzeige"</string>
<string name="package_not_found_error_msg" msgid="7525619456883627939">"Paket wurde nicht gefunden."</string>
<string name="permissions_granted_msg" msgid="2348556088141992714">"Alle Berechtigungen wurden erteilt. Du kannst sie in den Einstellungen deaktivieren."</string>
<string name="needs_access_msg_prefix" msgid="2204136858798832382">"Die App benötigt Zugriff auf die folgenden Berechtigungen:\n"</string>
<string name="phone_screen_permission_msg" msgid="3599815596923367256">"Berechtigungen über das Smartphone-Display erteilen"</string>
<string name="enable_location_permission_on_device_msg" msgid="472752487966156897">"Berechtigungen zur Standortermittlung auf Gerät aktivieren"</string>
<string name="enable_location_permission_on_phone_msg" msgid="5082615523959139121">"Standortermittlung auf dem Smartphone-Bildschirm aktivieren"</string>
<string name="required_permissions_title" msgid="5351791879153568211">"Erforderliche Berechtigungen"</string>
<string name="request_permissions_title" msgid="7456426341142412300">"Demo der Berechtigungsanfrage"</string>
<string name="cancel_reservation_title" msgid="1374986823057959608">"Bildschirm zum Stornieren der Reservierung"</string>
<string name="reservation_cancelled_msg" msgid="6334213670275547875">"Reservierung wurde storniert"</string>
<string name="result_demo_title" msgid="3900525190662148290">"Ergebnisdemo"</string>
<string name="not_started_for_result_msg" msgid="7498800528148447270">"Diese App wurde nicht für ein Ergebnis gestartet"</string>
<string name="started_for_result_msg" msgid="4225260243713833974">"Diese App wurde aufgerufen, um Ergebnisse aus %s zu erhalten. Wähle das Ergebnis aus, das an den Anrufer zurückgesendet werden soll."</string>
<string name="arrived_exclamation_msg" msgid="9132265698563096988">"Angekommen!"</string>
<string name="send_notification_title" msgid="4731688444696028193">"Benachrichtigung senden"</string>
<string name="start_notifications_title" msgid="8699668027543530460">"Benachrichtigungen starten"</string>
<string name="stop_notifications_title" msgid="3703892710275206239">"Benachrichtigungen deaktivieren"</string>
<string name="notification_title" msgid="5507590705935298176">"Benachrichtigung"</string>
<string name="importance_title" msgid="9034862997821839831">"Wichtigkeit"</string>
<string name="category_title" msgid="4783851267093259949">"Kategorie"</string>
<string name="ongoing_title" msgid="4957996003270280496">"Aktiv"</string>
<string name="default_importance" msgid="6347996298832939989">"Standard"</string>
<string name="high_importance" msgid="5009120714837304882">"Hoch"</string>
<string name="low_importance" msgid="4721161314404294033">"Gering"</string>
<string name="unknown_importance" msgid="909001735933359216">"Unbekannt"</string>
<string name="notification_demo" msgid="1819496937832036387">"Benachrichtigungsdemo"</string>
<string name="misc_demo_title" msgid="7399959062407349380">"Verschiedene Demos"</string>
<string name="navigating_demo_title" msgid="7454579665387386476">"Navigationsdemo"</string>
<string name="arrived_demo_title" msgid="6708013121387053838">"Demo für „Angekommen“"</string>
<string name="junction_image_demo_title" msgid="3302979708776502314">"Demo des Kreuzungsbildes"</string>
<string name="nav_template_demos_title" msgid="8215835368932160866">"Demos der Navigationsvorlage"</string>
<string name="map_template_pane_demo_title" msgid="4849450903277412004">"Demo der Kartenvorlage mit Bereich"</string>
<string name="map_template_list_demo_title" msgid="1473810899303903185">"Demo der Kartenvorlage mit Liste"</string>
<string name="start_notification_title" msgid="2208831088632818681">"Benachrichtigung beginnen"</string>
<string name="stop_notification_title" msgid="3709643750540881176">"Benachrichtigung deaktivieren"</string>
<string name="nav_notification_demo_title" msgid="4448683262984308442">"Demo der Navigationsbenachrichtigung"</string>
<string name="go_straight" msgid="2301747728609198718">"Geradeaus fahren"</string>
<string name="turn_right" msgid="4710562732720109969">"Rechts abbiegen"</string>
<string name="take_520" msgid="3804796387195842741">"Die 520 nehmen"</string>
<string name="gas_station" msgid="1203313937444666161">"Tankstelle"</string>
<string name="short_route" msgid="4831864276538141265">"Kurze Route"</string>
<string name="less_busy" msgid="310625272281710983">"Weniger Verkehr"</string>
<string name="hov_friendly" msgid="6956152104754594971">"Carpool-Spur-fähig"</string>
<string name="long_route" msgid="4737969235741057506">"Lange Route"</string>
<string name="continue_start_nav" msgid="6231797535084469163">"Weiter, um die Navigation zu starten"</string>
<string name="continue_route" msgid="5172258139245088080">"Weiter zur Route"</string>
<string name="routes_title" msgid="7799772149932075357">"Route"</string>
<string name="new_route">Neue Route Berechnung</string>
<string name="place_list_nav_template_demo_title" msgid="8019588508812955290">"Demo der Navigationsvorlage für Ortslisten"</string>
<string name="route_preview_template_demo_title" msgid="7878704357953167555">"Demo der Routenvorschauvorlage"</string>
<string name="notification_template_demo_title" msgid="5076051497316030274">"Demo der Benachrichtigungsvorlage"</string>
<string name="nav_map_template_demo_title" msgid="344985380763975398">"Demo der Navigationsvorlage nur mit Karte"</string>
<string name="nav_demos_title" msgid="72781206086461004">"Navigationsdemos"</string>
<string name="navigation_alert_title" msgid="8306554249264200848">"Blitzer noch da?"</string>
<string name="navigation_alert_subtitle" msgid="3331130131492672264">"Vor 10 Minuten gemeldet"</string>
<string name="no_toll_card_permission" msgid="6789073114449712090">"Keine Berechtigung für Mautkarte."</string>
<string name="no_energy_level_permission" msgid="1684773185095107825">"Keine Berechtigung für Akkustand."</string>
<string name="no_speed_permission" msgid="5812532480922675390">"Keine Berechtigung für Geschwindigkeit."</string>
<string name="no_mileage_permission" msgid="4074779840599589847">"Keine Berechtigung für Kilometerstand."</string>
<string name="no_ev_status_permission" msgid="933075402821938973">"Keine Berechtigung für Status des Elektrofahrzeugs."</string>
<string name="no_accelerometer_permission" msgid="896914448469117234">"Keine Berechtigung für Beschleunigungsmesser."</string>
<string name="no_gyroscope_permission" msgid="665293140266771569">"Keine Berechtigung für Gyroskop."</string>
<string name="no_compass_permission" msgid="5162304489577567125">"Keine Berechtigung für Kompass."</string>
<string name="no_car_hardware_location" msgid="3505517472938045093">"Keine Berechtigung für Auto-Hardware-Standort."</string>
<string name="fetch_toll_info" msgid="6864627977128179834">"Mautinformationen werden abgerufen."</string>
<string name="fetch_energy_level" msgid="1773415471137542832">"Akkustand wird abgerufen."</string>
<string name="fetch_speed" msgid="7333830984597189627">"Geschwindigkeit wird abgerufen."</string>
<string name="fetch_mileage" msgid="7490131687788025123">"Kilometerstand wird abgerufen."</string>
<string name="fetch_ev_status" msgid="2798910410830567052">"Status des Elektrofahrzeugs wird abgerufen."</string>
<string name="fetch_accelerometer" msgid="697750041126810911">"Beschleunigungsmesser wird abgerufen."</string>
<string name="fetch_gyroscope" msgid="7153155318827188539">"Gyroskop wird abgerufen."</string>
<string name="fetch_compass" msgid="7316188117590056717">"Kompass wird abgerufen."</string>
<string name="fetch_location" msgid="5015066922035852615">"Standort wird abgerufen."</string>
<string name="toll_card_state" msgid="4430544885695162226">"Status der Mautkarte"</string>
<string name="low_energy" msgid="3462774027012877028">"Niedriger Akkustand"</string>
<string name="range" msgid="8744960568263400641">"Bereich"</string>
<string name="fuel" msgid="4253578650127250651">"Kraftstoff"</string>
<string name="battery" msgid="2183623637331546820">"Akku"</string>
<string name="display_speed" msgid="9161318805331348165">"Geschwindigkeit anzeigen"</string>
<string name="raw_speed" msgid="7295910214088983967">"Rohgeschwindigkeit"</string>
<string name="unit" msgid="7697521583928135171">"Einheit"</string>
<string name="odometer" msgid="3925174645651546591">"Kilometerzähler"</string>
<string name="ev_connected" msgid="2277845607662494696">"Ladeanschluss des Elektrofahrzeugs verbunden"</string>
<string name="ev_open" msgid="4916704450914519643">"Ladeanschluss des Elektrofahrzeugs ist offen"</string>
<string name="accelerometer" msgid="2084026313768299185">"Beschleunigungsmesser"</string>
<string name="gyroscope" msgid="3428075828014504651">"Gyroskop"</string>
<string name="compass" msgid="7037367764762441245">"Kompass"</string>
<string name="car_hardware_location" msgid="5826128477363068617">"Standort der Auto-Hardware"</string>
<string name="non_actionable" msgid="8999757911111188784">"Keine Aktion möglich"</string>
<string name="second_item" msgid="5245792503030812493">"Zweiter Eintrag"</string>
<string name="third_item" msgid="334088179008716411">"Dritter Eintrag"</string>
<string name="fourth_item" msgid="1153409687260543158">"Vierter Eintrag"</string>
<string name="fifth_item" msgid="295284272719956932">"Der fünfte Eintrag hat einen langen Titel"</string>
<string name="sixth_item" msgid="3880321601391343607">"Der sechste Eintrag hat einen langen Titel"</string>
<string name="grid_template_demo_title" msgid="6159115661928982245">"Demo der Rastervorlage"</string>
<string name="parked_only_title" msgid="3190603222397552672">"Titel für „Nur geparkt“"</string>
<string name="parked_only_text" msgid="8720610556452272916">"Mehr Text für „Nur geparkt“."</string>
<string name="clicked_row_prefix" msgid="9068303427922069941">"Angeklickte Zeile"</string>
<string name="first_line_text" msgid="6648055806656590336">"Erste Textzeile"</string>
<string name="second_line_text" msgid="38664490158836864">"Zweite Textzeile"</string>
<string name="long_line_text" msgid="8082962600953333087">"Dieser Subtext kann im uneingeschränkten Modus (z. B. Parkmodus, eingeschränkter Modus für niedrige Geschwindigkeit) vollständig angezeigt werden. Im eingeschränkten Modus (z. B. Fahrmodus) wird er jedoch nach zwei Zeilen abgeschnitten. Zu Testzwecken ist dieser Subtext extrem lang."</string>
<string name="title_prefix" msgid="3991742709199357049">"Titel"</string>
<string name="list_template_demo_title" msgid="1740208242737246151">"Demo für Listenvorlage"</string>
<string name="long_msg_template_demo_title" msgid="1793748562161438131">"Demo der langen Nachrichtenvorlage"</string>
<string name="long_msg_template_not_supported_text" msgid="3641559637317672505">"Dein Host unterstützt keine lange Nachrichtenvorlage"</string>
<string name="long_msg_template_not_supported_title" msgid="8600719470226274925">"Inkompatibler Host"</string>
<string name="no_places" msgid="7246005909846715898">"Keine Orte"</string>
<string name="additional_text" msgid="5755100726890686184">"Bitte lies unsere "<annotation link="terms_of_service">"Nutzungsbedingungen"</annotation></string>
<string name="google_sign_in" msgid="6556259799319701727">"Google Log-in"</string>
<string name="use_pin" msgid="7850893299484337431">"PIN nutzen"</string>
<string name="qr_code" msgid="5487041647280777397">"QR-Code"</string>
<string name="sign_in_template_not_supported_text" msgid="7184733753948837646">"Dein Host unterstützt keine Anmeldevorlage"</string>
<string name="sign_in_template_not_supported_title" msgid="4892883228898541764">"Inkompatibler Host"</string>
<string name="email_hint" msgid="7205549445477319606">"E-Mail"</string>
<string name="sign_in_title" msgid="4551967308262681703">"Anmelden"</string>
<string name="sign_in_instructions" msgid="9044850228284294762">"Anmeldedaten eingeben"</string>
<string name="invalid_email_error_msg" msgid="5261362663718987167">"Der Nutzername muss eine gültige E-Mail-Adresse sein"</string>
<string name="invalid_length_error_msg" msgid="8238905276326976425">"Der Nutzername muss mindestens %s Zeichen enthalten"</string>
<string name="invalid_password_error_msg" msgid="1090359893902674610">"Ungültiges Passwort"</string>
<string name="password_hint" msgid="2869107073860012864">"Passwort"</string>
<string name="password_sign_in_instruction_prefix" msgid="9105788349198243508">"Nutzername"</string>
<string name="pin_sign_in_instruction" msgid="2288691296234360441">"Gib diese PIN auf deinem Telefon ein"</string>
<string name="qr_code_sign_in_title" msgid="8137070561006464518">"Zum Anmelden QR-Code scannen"</string>
<string name="sign_in_with_google_title" msgid="8043752000786977249">"Über Google anmelden"</string>
<string name="provider_sign_in_instruction" msgid="7586815688292506743">"Schließe mit dieser Schaltfläche dein Google Log-in ab"</string>
<string name="sign_in_complete_text" msgid="8423984266325680606">"Du bist angemeldet!"</string>
<string name="sign_in_complete_title" msgid="8919868148773983428">"Anmeldung abgeschlossen"</string>
<string name="sign_in_template_demo_title" msgid="6052035424941410249">"Anmeldungsvorlagendemo"</string>
<string name="tab_template_layouts_demo_title" msgid="6529681462424538165">"Tab-Vorlage  Demos"</string>
<string name="tab_template_demo_title" msgid="7587839101813629975">"Tab-Vorlage  Demo"</string>
<string name="tab_title_message" msgid="5266710951630087246">"Tab „Nachrichten“"</string>
<string name="tab_title_pane" msgid="2520606145526537263">"Tab „Bereich“"</string>
<string name="tab_title_list" msgid="5104962518489668123">"Tab „Liste“"</string>
<string name="tab_title_grid" msgid="5268168907976325154">"Tab „Raster“ mit langem Tab-Titel"</string>
<string name="tab_title_search" msgid="1892925693146631173">"Tab „Suche“"</string>
<string name="tab_title_loading" msgid="5385807479734490989">"Tab wird geladen"</string>
<string name="tab_template_loading_demo_title" msgid="4638051615030345574">"Tab-Vorlage  Demo wird geladen"</string>
<string name="tab_template_no_tabs_demo_title" msgid="6907466201298082309">"Tab-Vorlage  Demo „Keine Tabs“"</string>
<string name="images_unknown_host_error" msgid="3180661817432720076">"Für einen unbekannten Host können keine Bilder angezeigt werden"</string>
<string name="icon_title_prefix" msgid="8487026131229541244">"Symbol"</string>
<string name="content_provider_icons_demo_title" msgid="5708602618664311097">"Demo der Contentanbietersymbole"</string>
<string name="icons_demo_title" msgid="4082976685262307357">"Symboldemo"</string>
<string name="app_icon_title" msgid="7534936683349723423">"Das App-Symbol"</string>
<string name="vector_no_tint_title" msgid="874591632279039146">"Ein Vektor-Drawable ohne Färbung"</string>
<string name="vector_with_tint_title" msgid="1022346419829696827">"Ein Vektor-Drawable mit einer Färbung"</string>
<string name="vector_with_app_theme_attr_title" msgid="4890094482708376219">"Ein Vektor-Drawable mit einem App-Designattribut für die Farbe"</string>
<string name="png_res_title" msgid="7437083018336747544">"Eine PNG wurde als Ressource gesendet"</string>
<string name="png_bitmap_title" msgid="3385912074130977032">"Eine PNG-Datei, als Bitmap gesendet"</string>
<string name="just_row_title" msgid="965700021568970725">"Nur ein Titel"</string>
<string name="title_with_app_icon_row_title" msgid="6294250714820740520">"Titel mit App-Symbol"</string>
<string name="title_with_res_id_image_row_title" msgid="3813134904602875778">"Titel mit Bild für Ressourcen-ID"</string>
<string name="title_with_svg_image_row_title" msgid="6109092343637263755">"Titel mit SVG-Bild"</string>
<string name="colored_secondary_row_title" msgid="5173288934252528929">"Farbiger Sekundärtext"</string>
<string name="title_with_secondary_lines_row_title" msgid="7769408881272549837">"Titel mit mehreren Zeilen Sekundärtext"</string>
<string name="title_with_secondary_lines_row_text_1" msgid="8945114692653524102">"Du darfst irren, und irren, und irren aber immer weniger, und weniger, und weniger."</string>
<string name="title_with_secondary_lines_row_text_2" msgid="1017734603405251531">" Piet Hein"</string>
<string name="rows_demo_title" msgid="3198566660454251007">"Demo der Zeilen"</string>
<string name="text_icons_demo_title" msgid="8732943920672143201">"Demos für Text und Symbole"</string>
<string name="row_text_icons_demo_title" msgid="135167694047524905">"Demo der Zeilen mit Text und Symbolen"</string>
<string name="radio_button_list_demo_title" msgid="9082264324855338774">"Demo der Optionsfeldlisten"</string>
<string name="selectable_lists_demo_title" msgid="5492658731113129386">"Demo der auswählbaren Listen"</string>
<string name="option_1_title" msgid="7221252541651471199">"Option 1"</string>
<string name="option_2_title" msgid="1905146448697963818">"Option 2"</string>
<string name="option_3_title" msgid="6319268250436119258">"Option 3"</string>
<string name="option_row_radio_title" msgid="5978617101267398181">"Zeile mit Optionsfeld"</string>
<string name="option_row_radio_icon_title" msgid="3304229002524317977">"Zeile mit Optionsfeld und Symbol"</string>
<string name="option_row_radio_icon_colored_text_title" msgid="947641896184637026">"Zeile mit Optionsfeld, Symbol und farbigem Text"</string>
<string name="some_additional_text" msgid="4009872495806318260">"Zusätzlicher Text"</string>
<string name="sample_additional_list" msgid="5085372891301576306">"Beispiel für auswählbare Liste"</string>
<string name="task_restriction_demo_title" msgid="2212084350718766941">"Demo der Aufgabenbeschränkung"</string>
<string name="task_limit_reached_msg" msgid="7162842196382260992">"Hierdurch wird die maximale Anzahl an Schritten überschritten und du gelangst zu einem neuen Bildschirm."</string>
<string name="task_step_of_title" msgid="2791717962535723839">"Aufgabe: Schritt %1$d von %2$d"</string>
<string name="task_step_of_text" msgid="4646729781462227219">"Klicken, um fortzufahren"</string>
<string name="task_content_allowed" msgid="545061986612431190">"Bitte rufe die verschiedenen Vorlagen auf und achte darauf, dass sich das Auto im Fahrmodus befindet"</string>
<string name="toggle_button_demo_title" msgid="3179103600967398928">"Demo der Ein-/Aus-Schaltfläche"</string>
<string name="toggle_test_title" msgid="924485265152862631">"Test der Ein-/Aus-Schaltfläche"</string>
<string name="toggle_test_text" msgid="8107217216013312857">"Zustandsorientierte Änderungen sind erlaubt"</string>
<string name="toggle_test_first_toggle_title" msgid="3635022201072117680">"Test der Ein-/Aus-Schaltfläche aktivieren"</string>
<string name="toggle_test_first_toggle_text" msgid="5914741538328669668">"Klicke diese Option an, um den Test der Ein-/Aus-Schaltfläche zu aktivieren"</string>
<string name="toggle_test_second_toggle_title" msgid="1083594617400613969">"Test der Ein-/Aus-Schaltfläche"</string>
<string name="toggle_test_second_toggle_text" msgid="1813071017415876745">"Zustandsorientierte Änderungen sind erlaubt"</string>
<string name="image_test_title" msgid="8273863429801477547">"Bildtest"</string>
<string name="image_test_text" msgid="6264812093895530445">"Bildänderungen sind erlaubt"</string>
<string name="additional_data_title" msgid="3546689652240300617">"Zusätzliche Daten"</string>
<string name="additional_data_text" msgid="2846223398214158872">"Updates beim Zurückgehen erlaubt."</string>
<string name="toggle_test_enabled" msgid="982370904182034076">"Test der Ein-/Aus-Schaltfläche aktiviert"</string>
<string name="toggle_test_disabled" msgid="8366040658408451664">"Test der Ein-/Aus-Schaltfläche deaktiviert"</string>
<string name="secondary_actions_decoration_button_demo_title" msgid="3710817648501132309">"Demo der sekundären Aktion und der Dekoration"</string>
<string name="secondary_actions_test_title" msgid="3664453747553733613">"Test für sekundäre Aktion"</string>
<string name="secondary_actions_test_subtitle" msgid="6985282813402073703">"Nur die sekundäre Aktion kann ausgewählt werden"</string>
<string name="decoration_test_title" msgid="8450127046762442244">"Dekorationstest"</string>
<string name="secondary_actions_decoration_test_title" msgid="6282873404859209490">"Sekundäre Aktionen und Dekoration"</string>
<string name="secondary_actions_decoration_test_title_long" msgid="3700606949229899169">"Zeile mit sekundären Aktionen und Dekoration mit einem sehr langen Titel"</string>
<string name="secondary_actions_decoration_test_subtitle" msgid="155884606592724532">"Auch diese Zeile kann ausgewählt werden"</string>
<string name="recent_Item_deleted" msgid="5076434693504006565">Eintrag gelöscht</string>
<string name="row_primary_action_toast" msgid="756516694751965204">"Zeile mit der primären Aktion ist ausgewählt"</string>
<string name="sectioned_item_list_demo_title" msgid="1236735461225007729">"Demo für Elementliste mit Abschnitten"</string>
<string name="sectioned_item_list_one_title" msgid="6594204350307263338">"Liste 1"</string>
<string name="sectioned_item_list_two_title" msgid="4941545381743022833">"Liste 2"</string>
<string name="sectioned_item_list_subtext" msgid="2963927693547537519">"Subtext unter jeder Liste"</string>
<string name="empty_list_demo_title" msgid="5989013634820902455">"Leere Liste  Demo"</string>
<string name="empty_list_message" msgid="5331395517560728138">"Die Liste ist leer"</string>
<string name="misc_templates_demos_title" msgid="6077169010255928114">"Demos der verschiedenen Vorlagen"</string>
<string name="showcase_demos_title" msgid="1542092687878113304">"Demos anzeigen"</string>
<string name="template_layouts_demo_title" msgid="788249269446087847">"Demo der Layoutvorlagen"</string>
<string name="grid_template_menu_demo_title" msgid="7096285873490705119">"Demo der Rastervorlagen"</string>
<string name="voice_access_demo_title" msgid="3825223890895361496">"Bildschirm für Voice Access-Demo"</string>
<string name="user_interactions_demo_title" msgid="1356952319161314986">"Nutzerinteraktionen"</string>
<string name="request_permission_menu_demo_title" msgid="4796486779527427017">"Demos zur Berechtigungsanfrage"</string>
<string name="application_overflow_title" msgid="396427940886169325">"Anwendungs-Overflow-Validator"</string>
<string name="application_overflow_subtitle1" msgid="7429415605726615529">"Bitte teste die folgenden Vorlagen, wenn du"</string>
<string name="application_overflow_subtitle2" msgid="4385123036846369714">"das Fahrzeug vom Park- in den Fahrmodus umschaltest"</string>
<string name="perm_group" msgid="3834918337351876270">"Berechtigungsgruppe"</string>
<string name="perm_group_description" msgid="7348847631139139024">"Berechtigungsgruppe für die Showcase App"</string>
<string name="perm_fine_location" msgid="5438874642600304118">"Zugriff auf genauen Standort"</string>
<string name="perm_fine_location_desc" msgid="3549183883787912516">"Berechtigung für Zugriff auf den genauen Standort"</string>
<string name="perm_coarse_location" msgid="6140337431619481015">"Zugriff auf ungefähren Standort"</string>
<string name="perm_coarse_location_desc" msgid="6074759942301565943">"Berechtigung für Zugriff auf den ungefähren Standort"</string>
<string name="perm_record_audio" msgid="2758340693260523493">"Zugriff für Audioaufnahmen"</string>
<string name="perm_record_audio_desc" msgid="8038648467605928912">"Berechtigung für Zugriff für Audioaufnahmen"</string>
<string name="location_1_description" msgid="4801052291684791371">"Gefärbter Ressourcenvektor"</string>
<string name="location_2_description" msgid="3331356135359047166">"Bitmap-Infobild"</string>
<string name="location_3_description" msgid="3982142774088944850">"Farbige Textmarkierung"</string>
<string name="location_4_description" msgid="6560365445044381911">"Bitmap-Bild"</string>
<string name="location_description_text_label" msgid="2779911545316756419">"Textlabel"</string>
<string name="parking_vs_driving_demo_title" msgid="3367862800135053111">"Demo: Parken im Vergleich zu Fahren"</string>
<string name="latest_feature_details" msgid="6843008350392721502">"Displays in Autos."</string>
<string name="navigation_settings" msgid="7929405790070777460">"Navigation"</string>
<string name="display">Anzeige</string>
<string name="threed_building" msgid="8828072732804454994">"3D Gebäude"</string>
<string name="loading_toggle_disabled" msgid="7689738885077382673">"Laden deaktiviert"</string>
<string name="loading_screen" msgid="4771507490730308794">"Ladebildschirm"</string>
<string name="vector_toggle_details" msgid="1301305340033556819">"Schieberegler zum Hinzufügen/Entfernen von Farben"</string>
<string name="map_template_toggle_demo_title" msgid="6510798293640092611">"Kartenvorlage mit Ein-/Aus-Schaltflächen"</string>
<string name="avoid_tolls_row_title" msgid="5194057244144831024">"Mautstraßen meiden"</string>
<string name="route_options_demo_title" msgid="4599699012716426514">"Routenoptionen"</string>
<string name="avoid_highways_row_title" msgid="4711913426200490304">"Autobahnen meiden"</string>
<string name="avoid_ferries_row_title" msgid="8232883866013711974">"Fähren meiden"</string>
<string name="map_demos_title" msgid="2169766615521476592">"Kartenbezogene Demos"</string>
<string name="map_with_content_demo_title" msgid="1032610482145018739">"Demos von Karten mit Inhalten"</string>
<string name="map_with_message_demo_title" msgid="7007078234918054436">"Karte mit Demo der Nachrichtenvorlage"</string>
<string name="map_with_grid_demo_title" msgid="688667167861193192">"Demo einer Karte mit Rastervorlage"</string>
<string name="route_preview">Routen</string>
<string name="recent_destinations">Letzte Ziele</string>
<string name="contacts">Kontakte</string>
<string name="drive_now">Jetzt losfahren</string>
</resources>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<declare-styleable name="ShowcaseTheme">
<attr name="themedIconColor" format="color"/>
<attr name="markerIconTintColor" format="color"/>
<attr name="markerIconTintColorDark" format="color"/>
</declare-styleable>
</resources>

View File

@@ -1,415 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2021 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.
-->
<resources>
<string name="app_name" translatable="false">Navigation</string>
<!-- Action Titles -->
<string name="exit_action_title">Exit</string>
<string name="refresh_action_title">Refresh</string>
<string name="close_action_title">Close</string>
<string name="grant_access_action_title">Grant Access</string>
<string name="enable_location_action_title">Enable Location</string>
<string name="cancel_action_title">Cancel</string>
<string name="stop_action_title">Stop</string>
<string name="more_action_title">More</string>
<string name="call_action_title">Call</string>
<string name="options_action_title">Options</string>
<string name="search_action_title">Search</string>
<string name="checked_action_title">Checked</string>
<string name="unchecked_action_title">Unchecked</string>
<string name="on_action_title">On</string>
<string name="off_action_title">Off</string>
<string name="settings_action_title">Settings</string>
<string name="accept_action_title">Accept</string>
<string name="reject_action_title">Reject</string>
<string name="ok_action_title">OK</string>
<string name="throw_action_title">Throw</string>
<string name="commute_action_title">Commute</string>
<string name="sign_out_action_title">Sign out</string>
<string name="yes_action_title">Yes</string>
<string name="no_action_title">No</string>
<!-- Toast Messages -->
<string name="zoomed_in_toast_msg">Zoomed in</string>
<string name="zoomed_out_toast_msg">Zoomed out</string>
<string name="favorites">Favorites</string>
<string name="not_favorite_toast_msg">Not a favorite!</string>
<string name="nav_requested_toast_msg">Navigation Requested</string>
<string name="selected_route_toast_msg">Selected route</string>
<string name="visible_routes_toast_msg">Visible routes</string>
<string name="settings_toast_msg">Clicked Settings</string>
<string name="parked_toast_msg">Parked action</string>
<string name="more_toast_msg">Clicked More</string>
<string name="grant_location_permission_toast_msg">Grant location Permission to see current location</string>
<!-- Place Details Screen -->
<string name="navigate">Navigate</string>
<string name="dial">Dial</string>
<string name="address">Address</string>
<string name="phone">Phone</string>
<!-- CarHardwareDemoScreen -->
<string name="fail_start_nav">Failure starting navigation</string>
<string name="fail_start_dialer">Failure starting dialer</string>
<string name="display_settings">Display settings</string>
<!-- RequestPermissionScreen -->
<string name="package_not_found_error_msg">Package Not found.</string>
<string name="permissions_granted_msg">All permissions have been granted. Please revoke permissions from Settings.</string>
<string name="needs_access_msg_prefix">The app needs access to the following permissions:\n</string>
<string name="phone_screen_permission_msg">Grant Permission on the phone screen</string>
<string name="enable_location_permission_on_device_msg">Enable Location Permissions on device</string>
<string name="enable_location_permission_on_phone_msg">Enable location on the phone screen</string>
<string name="required_permissions_title">Required Permissions</string>
<string name="request_permissions_title">Request Permission Demo</string>
<!-- ReservationCancelledScreen -->
<string name="cancel_reservation_title">Cancel Reservation Screen</string>
<string name="reservation_cancelled_msg">Reservation canceled</string>
<!-- ResultDemoScreen -->
<string name="result_demo_title">Result demo</string>
<string name="not_started_for_result_msg">This app was not started for result</string>
<string name="started_for_result_msg">This app was called for result from %s. Please select the result to send back to the caller</string>
<!-- ArrivedDemoScreen -->
<string name="arrived_exclamation_msg">Arrived!</string>
<!-- RoutingDemoModels -->
<string name="current_step_cue" translatable="false">Roy st 520</string>
<string name="next_step_cue" translatable="false">I5 Aurora Ave N</string>
<!-- NotificationDemoScreen -->
<string name="send_notification_title">Send a notification</string>
<string name="start_notifications_title">Start notifications</string>
<string name="stop_notifications_title">Stop notifications</string>
<string name="notification_title">Notification</string>
<string name="importance_title">Importance</string>
<string name="category_title">Category</string>
<string name="ongoing_title">Ongoing</string>
<string name="default_importance">Default</string>
<string name="high_importance">High</string>
<string name="low_importance">Low</string>
<string name="unknown_importance">Unknown</string>
<string name="notification_demo">Notification Demo</string>
<!-- MiscDemoScreen -->
<string name="misc_demo_title">Misc Demos</string>
<!-- NavigationTemplateDemoScreen -->
<string name="navigating_demo_title">Navigating Demo</string>
<string name="arrived_demo_title">Arrived Demo</string>
<string name="junction_image_demo_title">Junction Image Demo</string>
<string name="nav_template_demos_title">Navigation Template Demos</string>
<!-- MapTemplateDemoScreen -->
<string name="map_template_pane_demo_title">Map Template with Pane Demo</string>
<string name="map_template_list_demo_title">Map Template with List Demo</string>
<!-- NavigationNotificationsDemoScreen -->
<string name="start_notification_title">Start Notification</string>
<string name="stop_notification_title">Stop Notification</string>
<string name="nav_notification_demo_title">Navigation Notification Demo</string>
<!-- NavigationNotificationService -->
<string name="go_straight">Go Straight</string>
<string name="turn_right">Turn Right</string>
<string name="take_520">Take 520</string>
<string name="gas_station">Gas Station</string>
<string name="short_route">Short route</string>
<string name="less_busy">Less busy</string>
<string name="hov_friendly">HOV friendly</string>
<string name="long_route">Long route</string>
<string name="continue_start_nav">Continue to start navigation</string>
<string name="continue_route">Continue to route</string>
<string name="routes_title">Routes</string>
<string name="new_route">New Route calculation</string>
<!-- NavigationDemosScreen -->
<string name="place_list_nav_template_demo_title">Place List Navigation Template Demo</string>
<string name="route_preview_template_demo_title">Route Preview Template Demo</string>
<string name="notification_template_demo_title">Notification Template Demo</string>
<string name="nav_map_template_demo_title">Navigation Template with map only Demo</string>
<string name="nav_demos_title">Navigation Demos</string>
<string name="navigation_alert_title">Still a speed trap?</string>
<string name="navigation_alert_subtitle">Reported 10m ago</string>
<!-- CarHardwareRenderer -->
<string name="no_toll_card_permission">No TollCard Permission.</string>
<string name="no_energy_level_permission">No EnergyLevel Permission.</string>
<string name="no_speed_permission">No Speed Permission.</string>
<string name="no_mileage_permission">No Mileage Permission.</string>
<string name="no_ev_status_permission">No EV status Permission.</string>
<string name="no_accelerometer_permission">No Accelerometer Permission.</string>
<string name="no_gyroscope_permission">No Gyroscope Permission.</string>
<string name="no_compass_permission">No Compass Permission.</string>
<string name="no_car_hardware_location">No CarHardwareLocation Permission.</string>
<string name="fetch_toll_info">Fetching Toll information.</string>
<string name="fetch_energy_level">Fetching Energy Level.</string>
<string name="fetch_speed">Fetching Speed.</string>
<string name="fetch_mileage">Fetching Mileage.</string>
<string name="fetch_ev_status">Fetching EV status.</string>
<string name="fetch_accelerometer">Fetching Accelerometer.</string>
<string name="fetch_gyroscope">Fetching Gyroscope.</string>
<string name="fetch_compass">Fetching Compass.</string>
<string name="fetch_location">Fetching Location.</string>
<string name="toll_card_state">Toll card state</string>
<string name="low_energy">Low energy</string>
<string name="range">Range</string>
<string name="fuel">Fuel</string>
<string name="battery">Battery</string>
<string name="display_speed">Display Speed</string>
<string name="raw_speed">Raw Speed</string>
<string name="unit">Unit</string>
<string name="odometer">Odometer</string>
<string name="ev_connected">Ev Charge Port Connected</string>
<string name="ev_open">Ev Charge Port Open</string>
<string name="accelerometer">Accelerometer</string>
<string name="gyroscope">Gyroscope</string>
<string name="compass">Compass</string>
<string name="car_hardware_location">Car Hardware Location</string>
<!-- GridTemplateDemoScreen -->
<string name="non_actionable">Non-actionable</string>
<string name="second_item">Second Item</string>
<string name="third_item">Third Item</string>
<string name="fourth_item">Fourth Item</string>
<string name="fifth_item">Fifth Item has a long title set</string>
<string name="sixth_item">Sixth Item has a long title set</string>
<string name="grid_template_demo_title">Grid Template Demo</string>
<!-- ListTemplateDemoScreen -->
<string name="parked_only_title">Parked Only Title</string>
<string name="parked_only_text">More Parked only text.</string>
<string name="clicked_row_prefix">Clicked row</string>
<string name="first_line_text">First line of text</string>
<string name="second_line_text">Second line of text</string>
<string name="long_line_text">This subtext can fully display in unrestricted mode (ex. parking mode, restricted low speed mode). But this will truncate to only two lines while in restricted mode (ex. driving mode). For testing purposes, this subtext is super super super super super long</string>
<string name="title_prefix">Title</string>
<string name="list_template_demo_title">List Template Demo</string>
<!-- LongMessageTemplateDemoScreen -->
<string name="long_msg_template_demo_title">Long Message Template Demo</string>
<string name="long_msg_template_text" translatable="false">Lorem ipsum dolor sit amet, consectetur adipiscing elit. \nAliquam laoreet ac metus eu commodo. Sed a congue diam, sed dictum lectus. Nam nec\ntristique dolor, quis sodales arcu. Etiam at metus eu nulla auctor varius. \nInteger dolor lorem, placerat sit amet lacus in, imperdiet semper dui. Vestibulum \nante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; \nQuisque gravida fermentum egestas.\n\n\n\nUt ut sodales mi. Aenean porta vel ipsum sed lacinia. Morbi odio ipsum, hendrerit \neu est et, sollicitudin finibus diam. Nunc sit amet felis elit. Orci varius \nnatoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed \nvestibulum, tellus a rutrum auctor, diam arcu vestibulum purus, nec mollis ligula \nnisi in nisi. Donec sem tortor, pharetra sed fermentum sit amet, ullamcorper nec \nsapien. Aliquam risus arcu, porttitor eu dui nec, vulputate tempus libero. \nCurabitur sit amet tristique orci. Suspendisse et odio tempus, tempus turpis quis,\n euismod est.\n\n\n\nVestibulum mauris ante, luctus viverra nisi eget, blandit facilisis nulla. \nPhasellus ex lorem, semper in vestibulum nec, aliquet vel elit. Aliquam vitae \nligula nec enim dictum lobortis. Sed varius turpis quis nisi tempus varius. Sed \nnon sollicitudin magna, at mattis tortor. Curabitur quis ligula eget lorem mattis \ntincidunt et in sapien. Curabitur a elit nisi. Aliquam ex arcu, hendrerit eget \nturpis vitae, bibendum vulputate nibh. Fusce vitae ex aliquet, tristique magna eu,\n vulputate dui. Aenean tempor viverra tortor non pharetra. Pellentesque convallis \nnec risus a auctor. Praesent non sem non eros tincidunt ullamcorper efficitur non \nlacus.\n\n\n\nSuspendisse accumsan ultricies egestas. Aenean leo ligula, congue ac erat eu, \nlobortis ultricies lorem. Nulla finibus, arcu sed tincidunt lobortis, magna justo \nrutrum ligula, et mattis felis turpis vel ex. Morbi ac auctor ex, at bibendum sem.\n Vestibulum a tortor iaculis, viverra felis vitae, lobortis est. Duis sit amet \ncondimentum sem. Ut molestie, dolor pretium imperdiet maximus, enim orci porta \nquam, id gravida enim nunc vitae lacus. Pellentesque habitant morbi tristique \nsenectus et netus et malesuada fames ac turpis egestas. Nullam vel justo eu risus \nlobortis dignissim sit amet ullamcorper nulla. Donec finibus cursus purus \nporttitor pellentesque.\n\n\n\nDonec at vehicula ante. Suspendisse rutrum nisl quis metus faucibus lacinia. \nVestibulum eros sapien, eleifend nec accumsan a, interdum sed nisi. Aenean posuere\n ultrices lorem non pharetra. Nulla non porta ligula. Maecenas at elit diam. \nNullam gravida augue et semper eleifend. Fusce venenatis ac arcu et luctus. Mauris\n ultricies urna non dui interdum, vel hendrerit est aliquam. Fusce id dictum leo, \nfringilla egestas ipsum.</string>
<string name="long_msg_template_not_supported_text">Your host doesn\'t support Long Message template</string>
<string name="long_msg_template_not_supported_title">Incompatible host</string>
<string name="no_places">No Places</string>
<!-- SignInTemplateDemoScreen -->
<string name="additional_text">Please review our <annotation link="terms_of_service">terms of service</annotation></string>
<string name="google_sign_in">Google sign-in</string>
<string name="use_pin">Use PIN</string>
<string name="qr_code">QR Code</string>
<string name="sign_in_template_not_supported_text">Your host doesn\'t support Sign In template</string>
<string name="sign_in_template_not_supported_title">Incompatible host</string>
<string name="email_hint">Email</string>
<string name="sign_in_title">Sign in</string>
<string name="sign_in_instructions">Enter your credentials</string>
<string name="invalid_email_error_msg">User name must be a valid email address</string>
<string name="invalid_length_error_msg">User name must be at least %s characters long</string>
<string name="invalid_password_error_msg">Invalid password</string>
<string name="password_hint">password</string>
<string name="password_sign_in_instruction_prefix">Username</string>
<string name="pin_sign_in_instruction">Type this PIN in your phone</string>
<string name="qr_code_sign_in_title">Scan QR Code to sign in</string>
<string name="sign_in_with_google_title">Sign in with Google</string>
<string name="provider_sign_in_instruction">Use this button to complete your Google sign-in</string>
<string name="sign_in_complete_text">You are signed in!</string>
<string name="sign_in_complete_title">Sign in completed</string>
<string name="sign_in_template_demo_title">Sign In Template Demo</string>
<!-- TabTemplateScreen -->
<string name="tab_template_layouts_demo_title">Tab Template Demos</string>
<string name="tab_template_demo_title">Tab Template Demo</string>
<string name="tab_title_message">Message Tab</string>
<string name="tab_title_pane">Pane Tab</string>
<string name="tab_title_list">List Tab</string>
<string name="tab_title_grid">Grid Tab with Long Tab Title</string>
<string name="tab_title_search">Search Tab</string>
<string name="tab_title_loading">Loading Tab</string>
<string name="tab_template_loading_demo_title">Tab Template Loading Demo</string>
<string name="tab_template_no_tabs_demo_title">Tab Template No Tabs Demo</string>
<!-- ContentProviderIconsDemoScreen -->
<string name="images_unknown_host_error">Images cannot be displayed for an unknown host</string>
<string name="icon_title_prefix">Icon</string>
<string name="content_provider_icons_demo_title">Content Provider Icons Demo</string>
<!-- IconsDemoScreen -->
<string name="icons_demo_title">Icons Demo</string>
<string name="app_icon_title">The app icon</string>
<string name="vector_no_tint_title">A vector drawable, without a tint</string>
<string name="vector_with_tint_title">A vector drawable, with a tint</string>
<string name="vector_with_app_theme_attr_title">A vector drawable, with an app\'s theme attribute for its color</string>
<string name="png_res_title">A PNG, sent as a resource</string>
<string name="png_bitmap_title">A PNG, sent as a bitmap</string>
<!-- RowDemoScreen -->
<string name="just_row_title">Just a title</string>
<string name="title_with_app_icon_row_title">Title with app icon</string>
<string name="title_with_res_id_image_row_title">Title with resource ID image</string>
<string name="title_with_svg_image_row_title">Title with SVG image</string>
<string name="colored_secondary_row_title">Colored secondary text</string>
<string name="title_with_secondary_lines_row_title">Title with multiple secondary text lines</string>
<string name="title_with_secondary_lines_row_text_1">Err and err and err again, but less and less and less.</string>
<string name="title_with_secondary_lines_row_text_2">- Piet Hein</string>
<string name="rows_demo_title">Rows Demo</string>
<!-- TextAndIconsDemosScreen -->
<string name="text_icons_demo_title">Text and Icons Demos</string>
<string name="row_text_icons_demo_title">Rows with Text and Icons Demo</string>
<!-- SelectableListsDemoScreen -->
<string name="radio_button_list_demo_title">Radio Button Lists Demo</string>
<string name="selectable_lists_demo_title">Selectable Lists Demo</string>
<string name="option_1_title">Option 1</string>
<string name="option_2_title">Option 2</string>
<string name="option_3_title">Option 3</string>
<string name="option_row_radio_title">Row with Radio Button</string>
<string name="option_row_radio_icon_title">Row with Radio Button and Icon</string>
<string name="option_row_radio_icon_colored_text_title">Row with Radio Button and Icon and Colored Text</string>
<string name="some_additional_text">Some additional text</string>
<string name="sample_additional_list">Sample selectable list</string>
<!-- TaskRestrictionDemoScreen -->
<string name="task_restriction_demo_title">Task Restriction Demo</string>
<string name="task_limit_reached_msg">This will overflow the step count, and lead you to a new screen. </string>
<string name="task_step_of_title">Task step %1$d of %2$d</string>
<string name="task_step_of_text">Click to go forward</string>
<string name="task_content_allowed">Please visit the different templates and ensure the car is in driving mode</string>
<!-- ToggleButtonDemoScreen -->
<string name="toggle_button_demo_title">Toggle Button Demo</string>
<string name="toggle_test_title">Toggle test</string>
<string name="toggle_test_text">Stateful changes are allowed</string>
<string name="toggle_test_first_toggle_title">Enable Toggle Test</string>
<string name="toggle_test_first_toggle_text">Check this one to enable the toggle test</string>
<string name="toggle_test_second_toggle_title">Toggle test</string>
<string name="toggle_test_second_toggle_text">Stateful changes are allowed</string>
<string name="image_test_title">Image test</string>
<string name="image_test_text">Image changes are allowed</string>
<string name="additional_data_title">Additional Data</string>
<string name="additional_data_text">Updates allowed on back operations.</string>
<string name="toggle_test_enabled">Toggle Test Enabled</string>
<string name="toggle_test_disabled">Toggle Test Disabled</string>
<!--SecondaryActionsAndDecorationDemoScreen -->
<string name="secondary_actions_decoration_button_demo_title">Secondary Action and Decoration Demo</string>
<string name="secondary_actions_test_title">Secondary Action Test</string>
<string name="secondary_actions_test_subtitle">Only the secondary action can be selected</string>
<string name="decoration_test_title">Decoration Test</string>
<string name="secondary_actions_decoration_test_title">Secondary Actions and Decoration</string>
<string name="secondary_actions_decoration_test_title_long">Row with Secondary Actions and Decoration with a really long title</string>
<string name="secondary_actions_decoration_test_subtitle">The row can also be selected</string>
<string name="recent_Item_deleted">Place deleted</string>
<string name="row_primary_action_toast">Row primary action is selected</string>
<!--SectionedItemListDemoScreen -->
<string name="sectioned_item_list_demo_title">Sectioned Item List Demo</string>
<string name="sectioned_item_list_one_title">List 1</string>
<string name="sectioned_item_list_two_title">List 2</string>
<string name="sectioned_item_list_subtext">Subtext under each list</string>
<!-- EmptyListDemoScreen -->
<string name="empty_list_demo_title">Empty List Demo</string>
<string name="empty_list_message">The list is empty</string>
<!-- StartScreen -->
<string name="misc_templates_demos_title">Misc Templates Demos</string>
<string name="cal_api_level_prefix" translatable="false">CAL API Level: %d</string>
<string name="showcase_demos_title">Showcase Demos</string>
<string name="template_layouts_demo_title">Template Layout Demos</string>
<string name="grid_template_menu_demo_title">Grid Template Demos</string>
<!-- User Interactions Screen -->
<string name="voice_access_demo_title">Voice Access Demo Screen</string>
<string name="user_interactions_demo_title">User Interactions</string>
<string name="request_permission_menu_demo_title">Request Permissions Demos</string>
<!-- Task Overflow Demo Screen -->
<string name="application_overflow_title">Application Overflow Validator</string>
<string name="application_overflow_subtitle1">Please test the following templates while changing</string>
<string name="application_overflow_subtitle2">the vehicle from parked to driving state</string>
<!-- Manifest file permissions -->
<string name="perm_group">Permission Group</string>
<string name="perm_group_description">Permission Group for Showcase App</string>
<string name="perm_fine_location">Access to Fine Location</string>
<string name="perm_fine_location_desc">Permission for Access to Fine Location</string>
<string name="perm_coarse_location">Access to Coarse Location</string>
<string name="perm_coarse_location_desc">Permission for Access to Coarse Location</string>
<string name="perm_record_audio">Access to Record Audio</string>
<string name="perm_record_audio_desc">Permission for Access to Record Audio</string>
<!-- Location Strings -->
<string name="location_1_title" translatable="false">Google Kirkland</string>
<string name="location_1_address" translatable="false">747 6th St South, Kirkland, WA 98033</string>
<string name="location_1_description">Tinted resource vector</string>
<string name="location_1_phone" translatable="false">+14257395600</string>
<string name="location_2_title" translatable="false">Google Bellevue</string>
<string name="location_2_address" translatable="false">1120 112th Ave NE, Bellevue, WA 98004</string>
<string name="location_2_description">Image resource bitmap</string>
<string name="location_2_phone" translatable="false">+14252301301</string>
<string name="location_3_title" translatable="false">Google South Lake Union</string>
<string name="location_3_address" translatable="false">1021 Valley St, Seattle, WA 98109</string>
<string name="location_3_description">Colored text marker</string>
<string name="location_3_phone" translatable="false">+12065311800</string>
<string name="location_4_title" translatable="false">Google Seattle</string>
<string name="location_4_address" translatable="false">601 N 34th St, Seattle, WA 98103</string>
<string name="location_4_description">Image bitmap</string>
<string name="location_4_phone" translatable="false">+12068761800</string>
<string name="location_5_address" translatable="false">1600 Amphitheatre Pkwy, Mountain View, CA 94043</string>
<string name="location_5_phone" translatable="false">+16502530000</string>
<string name="location_6_title" translatable="false">Google Bothell</string>
<string name="location_6_address" translatable="false">11831 North Creek Pkwy, Bothell, WA 98011</string>
<string name="location_7_title" translatable="false">Seward Park</string>
<string name="location_7_address" translatable="false">5900 Lake Washington Blvd S, Seattle, WA 98118</string>
<string name="location_8_title" translatable="false">Luther Burbank Park</string>
<string name="location_8_address" translatable="false">2040 84th Ave SE, Mercer Island, WA 98040</string>
<string name="location_9_title" translatable="false">Heritage Park</string>
<string name="location_9_address" translatable="false">111 Waverly Way, Kirkland, WA 98033</string>
<string name="location_description_text_label">Text label</string>
<string name="location_phone_not_available" translatable="false">n/a</string>
<string name="parking_vs_driving_demo_title">Parking Vs Driving Demo</string>
<string name="latest_feature_details">Cluster Displays in cars!</string>
<string name="navigation_settings">Navigation</string>
<string name="display">Display</string>
<string name="threed_building">3D Building</string>
<string name="loading_toggle_disabled">Loading disabled</string>
<string name="loading_screen">Loading screen</string>
<string name="vector_toggle_details">Toggle to add/remove color</string>
<string name="map_template_toggle_demo_title">Map Template with Toggles</string>
<string name="avoid_tolls_row_title">Avoid tolls</string>
<string name="route_options_demo_title">Route options</string>
<string name="avoid_highways_row_title">Avoid highways</string>
<string name="avoid_ferries_row_title">Avoid ferry</string>
<string name="map_demos_title">Map Demos</string>
<string name="map_with_content_demo_title">Map With Content Demos</string>
<string name="map_with_message_demo_title">Map With Message Template Demo</string>
<string name="map_with_grid_demo_title">Map With Grid Template Demo</string>
<string name="route_preview">Routes</string>
<string name="recent_destinations">Recent</string>
<string name="contacts">Contacts</string>
<string name="drive_now">Drive now</string>
</resources>

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<style name="CarAppTheme">
<item name="themedIconColor">#FFFF0000</item>
<item name="carColorPrimary">#ff7f39fb</item>
<item name="carColorPrimaryDark">#5904DF</item>
<item name="carColorSecondary">#328E10</item>
<item name="carColorSecondaryDark">#1A6004</item>
<item name="markerIconTintColor">#FF7F39FB</item>
<item name="markerIconTintColorDark">#FF5904DF</item>
</style>
</resources>

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2023 Google LLC
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.
-->
<automotiveApp>
<uses name="template"/>
</automotiveApp>

View File

@@ -1,4 +1,5 @@
import org.gradle.kotlin.dsl.annotationProcessor import org.gradle.kotlin.dsl.annotationProcessor
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins { plugins {
@@ -8,8 +9,6 @@ plugins {
kotlin("kapt") kotlin("kapt")
} }
android { android {
namespace = "com.kouros.data" namespace = "com.kouros.data"
compileSdk = 36 compileSdk = 36
@@ -33,13 +32,14 @@ android {
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11
} }
kotlinOptions { kotlin {
jvmTarget = "11" compilerOptions {
jvmTarget = JvmTarget.JVM_11
}
} }
} }
dependencies { dependencies {
implementation(libs.android.sdk.turf)
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat) implementation(libs.androidx.appcompat)
implementation(libs.material) implementation(libs.material)
@@ -47,6 +47,9 @@ dependencies {
implementation(libs.koin.core) implementation(libs.koin.core)
implementation(libs.koin.android) implementation(libs.koin.android)
implementation(libs.koin.compose.viewmodel) implementation(libs.koin.compose.viewmodel)
implementation(libs.androidx.car.app)
implementation(libs.android.sdk.turf)
// objectbox // objectbox
implementation(libs.objectbox.kotlin) implementation(libs.objectbox.kotlin)

View File

@@ -16,19 +16,12 @@
package com.kouros.navigation.data package com.kouros.navigation.data
import android.R
import android.location.Location import android.location.Location
import android.location.LocationManager import android.location.LocationManager
import android.net.Uri import android.net.Uri
import com.google.gson.GsonBuilder
import com.kouros.navigation.data.valhalla.Maneuvers
import com.kouros.navigation.data.valhalla.ValhallaJson
import com.kouros.navigation.utils.NavigationUtils.createGeoJson
import com.kouros.navigation.utils.NavigationUtils.decodePolyline
import io.objectbox.annotation.Entity import io.objectbox.annotation.Entity
import io.objectbox.annotation.Id import io.objectbox.annotation.Id
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.maplibre.geojson.Point
data class Category( data class Category(
val id: String, val id: String,
@@ -61,7 +54,16 @@ data class ContactData(
data class StepData ( data class StepData (
var instruction: String, var instruction: String,
var leftDistance: Double,
var leftStepDistance: Double,
var maneuverType: Int,
var icon: Int,
var arrivalTime : Long,
var leftDistance: Double
) )

View File

@@ -2,7 +2,12 @@ package com.kouros.navigation.model
import android.location.Location import android.location.Location
import android.location.LocationManager import android.location.LocationManager
import androidx.car.app.navigation.model.Maneuver
import androidx.car.app.navigation.model.Step
import com.kouros.data.R
import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD
import com.kouros.navigation.data.ManeuverType
import com.kouros.navigation.data.Place import com.kouros.navigation.data.Place
import com.kouros.navigation.data.Route import com.kouros.navigation.data.Route
import com.kouros.navigation.data.StepData import com.kouros.navigation.data.StepData
@@ -10,6 +15,7 @@ import com.kouros.navigation.utils.location
import org.maplibre.geojson.FeatureCollection import org.maplibre.geojson.FeatureCollection
import org.maplibre.geojson.Point import org.maplibre.geojson.Point
import org.maplibre.turf.TurfMeasurement import org.maplibre.turf.TurfMeasurement
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt import kotlin.math.roundToInt
open class RouteModel() { open class RouteModel() {
@@ -44,25 +50,51 @@ open class RouteModel() {
navigating = true navigating = true
} }
fun stopNavigation() {
private fun createCenterLocation(): Location { route.clear()
navigating = false
val future = TurfMeasurement.center(FeatureCollection.fromJson(route.routeGeoJson)) currentShapeIndex = 0
val point = future.geometry() as Point distanceToStepEnd = 0F
return location(point.longitude(), point.latitude()) beginIndex = 0
endIndex = 0
} }
/**
* Calculates the geographic center of the route's GeoJSON data.
*
* @return A [Location] object representing the center point.
* @throws IllegalStateException if the calculated center does not have valid Point geometry.
*/
private fun createCenterLocation(): Location {
// 1. Create a FeatureCollection from the raw GeoJSON string.
val featureCollection = FeatureCollection.fromJson(route.routeGeoJson)
// 2. Calculate the center feature of the collection.
val centerFeature = TurfMeasurement.center(featureCollection)
// 3. Safely access and cast the geometry, throwing an informative error if it fails.
val centerPoint = centerFeature.geometry() as? Point
?: throw IllegalStateException("Center of GeoJSON is not a valid Point.")
// 4. Create and return the Location object.
return location(centerPoint.longitude(), centerPoint.latitude())
}
/**
* The remaining distance to the step, rounded to the nearest 10 units.
*/
val currentDistance: Double val currentDistance: Double
/** Returns the current [Step] with information such as the cue text and images. */
get() { get() {
return ((leftStepDistance()).roundToInt().toDouble() / 10.0).roundToInt() * 10.0 // This is a more direct way to round to the nearest multiple of 10.
return (leftStepDistance() / 10.0).roundToInt() * 10.0
} }
fun updateLocation(location: Location) { fun updateLocation(location: Location) {
var nearestDistance = 100000.0f var nearestDistance = 100000.0f
route.currentManeuverIndex = -1 for (i in route.currentManeuverIndex..<route.maneuvers.size) {
// find maneuver val maneuver = route.maneuvers[i]
for ((i, maneuver) in route.maneuvers.withIndex()) {
val beginShapeIndex = maneuver.beginShapeIndex val beginShapeIndex = maneuver.beginShapeIndex
val endShapeIndex = maneuver.endShapeIndex val endShapeIndex = maneuver.endShapeIndex
val distance = calculateDistance(beginShapeIndex, endShapeIndex, location) val distance = calculateDistance(beginShapeIndex, endShapeIndex, location)
@@ -74,30 +106,6 @@ open class RouteModel() {
} }
} }
fun currentStep(): StepData {
val maneuver = route.currentManeuver()
var text = ""
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
text = maneuver.streetNames[0]
}
val curLocation = location(
route.pointLocations[currentShapeIndex].longitude(),
route.pointLocations[currentShapeIndex].latitude()
)
val distanceStepLeft = leftStepDistance()
when (distanceStepLeft) {
in 0.0..NEXT_STEP_THRESHOLD -> {
if (route.currentManeuverIndex < route.maneuvers.size) {
val maneuver = route.nextManeuver()
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
text = maneuver.streetNames[0]
}
}
}
}
return StepData(text, distanceStepLeft)
}
/** Calculates the index in a maneuver. */ /** Calculates the index in a maneuver. */
private fun calculateCurrentShapeIndex( private fun calculateCurrentShapeIndex(
beginShapeIndex: Int, beginShapeIndex: Int,
@@ -105,7 +113,7 @@ open class RouteModel() {
location: Location location: Location
) { ) {
var nearestLocation = 100000.0f var nearestLocation = 100000.0f
for (i in beginShapeIndex..endShapeIndex) { for (i in currentShapeIndex..endShapeIndex) {
val waypoint = Location(LocationManager.GPS_PROVIDER) val waypoint = Location(LocationManager.GPS_PROVIDER)
waypoint.longitude = route.waypoints[i][0] waypoint.longitude = route.waypoints[i][0]
waypoint.latitude = route.waypoints[i][1] waypoint.latitude = route.waypoints[i][1]
@@ -131,6 +139,97 @@ open class RouteModel() {
} }
} }
fun currentStep(): StepData {
// Determine if we should display the current or the next maneuver
val distanceToNextStep = leftStepDistance()
val isNearNextManeuver = distanceToNextStep in 0.0..NEXT_STEP_THRESHOLD
val shouldAdvance =
isNearNextManeuver && route.currentManeuverIndex < (route.maneuvers.size - 1)
// Get the single, correct maneuver for this state
val relevantManeuver = if (shouldAdvance) {
route.nextManeuver() // This advances the route's state
} else {
route.currentManeuver()
}
// Safely get the street name from the maneuver
val streetName = relevantManeuver.streetNames?.firstOrNull() ?: ""
// Determine the maneuver type and corresponding icon
val maneuverType = if (hasArrived(relevantManeuver.type)) {
relevantManeuver.type
} else {
ManeuverType.None.value
}
val maneuverIconPair = maneuverIcon(maneuverType)
// Construct and return the final StepData object
return StepData(
streetName,
distanceToNextStep,
maneuverIconPair.first,
maneuverIconPair.second,
arrivalTime(),
travelLeftDistance()
)
}
fun currentStepx(): StepData {
val maneuver = route.currentManeuver()
var text = ""
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
text = maneuver.streetNames[0]
}
val distanceStepLeft = leftStepDistance()
when (distanceStepLeft) {
in 0.0..Constants.NEXT_STEP_THRESHOLD -> {
if (route.currentManeuverIndex < route.maneuvers.size) {
val maneuver = route.nextManeuver()
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
text = maneuver.streetNames[0]
}
}
}
}
val type = if (hasArrived(maneuverType)) {
maneuver.type
} else {
ManeuverType.None.value
}
var routing: (Pair<Int, Int>) = maneuverIcon(type)
when (distanceStepLeft) {
in 0.0..NEXT_STEP_THRESHOLD -> {
if (route.currentManeuverIndex < route.maneuvers.size) {
val maneuver = route.nextManeuver()
val maneuverType = maneuver.type
routing = maneuverIcon(maneuverType)
}
}
}
return StepData(text, distanceStepLeft, routing.first, routing.second, arrivalTime(), travelLeftDistance())
}
fun nextStep(): StepData {
val maneuver = route.nextManeuver()
val maneuverType = maneuver.type
val distanceLeft = leftStepDistance()
var text = ""
when (distanceLeft) {
in 0.0..NEXT_STEP_THRESHOLD -> {
}
else -> {
if (maneuver.streetNames != null && maneuver.streetNames!!.isNotEmpty()) {
text = maneuver.streetNames[0]
}
}
}
val routing: (Pair<Int, Int>) = maneuverIcon(maneuverType)
return StepData(text, distanceLeft, routing.first, routing.second, arrivalTime(), travelLeftDistance())
}
private fun calculateDistance( private fun calculateDistance(
beginShapeIndex: Int, beginShapeIndex: Int,
endShapeIndex: Int, endShapeIndex: Int,
@@ -138,9 +237,7 @@ open class RouteModel() {
): Float { ): Float {
var nearestLocation = 100000.0f var nearestLocation = 100000.0f
for (i in beginShapeIndex..endShapeIndex) { for (i in beginShapeIndex..endShapeIndex) {
val polylineLocation = Location(LocationManager.GPS_PROVIDER) val polylineLocation = location(route.waypoints[i][0], route.waypoints[i][1])
polylineLocation.longitude = route.waypoints[i][0]
polylineLocation.latitude = route.waypoints[i][1]
val distance: Float = location.distanceTo(polylineLocation) val distance: Float = location.distanceTo(polylineLocation)
if (distance < nearestLocation) { if (distance < nearestLocation) {
nearestLocation = distance nearestLocation = distance
@@ -165,12 +262,21 @@ open class RouteModel() {
return timeLeft return timeLeft
} }
fun arrivalTime(): Long {
val timeLeft = travelLeftTime()
// Calculate the time to destination from the current time.
val nowUtcMillis = System.currentTimeMillis()
val timeToDestinationMillis =
TimeUnit.SECONDS.toMillis(timeLeft.toLong())
return nowUtcMillis + timeToDestinationMillis
}
/** Returns the current [Step] left distance in m. */ /** Returns the current [Step] left distance in m. */
fun leftStepDistance(): Double { fun leftStepDistance(): Double {
val maneuver = route.currentManeuver() val maneuver = route.currentManeuver()
var leftDistance = maneuver.length var leftDistance = maneuver.length
if (endIndex > 0) { if (endIndex > 0) {
leftDistance = distanceToStepEnd.toDouble() leftDistance = (distanceToStepEnd / 1000).toDouble()
} }
return leftDistance * 1000 return leftDistance * 1000
} }
@@ -192,6 +298,72 @@ open class RouteModel() {
return leftDistance return leftDistance
} }
fun maneuverIcon(routeManeuverType: Int): (Pair<Int, Int>) {
var type = Maneuver.TYPE_DEPART
var currentTurnIcon = R.drawable.ic_turn_name_change
when (routeManeuverType) {
ManeuverType.None.value -> {
type = Maneuver.TYPE_STRAIGHT
currentTurnIcon = R.drawable.ic_turn_name_change
}
ManeuverType.Destination.value,
ManeuverType.DestinationRight.value,
ManeuverType.DestinationLeft.value,
-> {
type = Maneuver.TYPE_DESTINATION
currentTurnIcon = R.drawable.ic_turn_destination
}
ManeuverType.Right.value -> {
type = Maneuver.TYPE_TURN_NORMAL_RIGHT
currentTurnIcon = R.drawable.ic_turn_normal_right
}
ManeuverType.Left.value -> {
type = Maneuver.TYPE_TURN_NORMAL_LEFT
currentTurnIcon = R.drawable.ic_turn_normal_left
}
ManeuverType.RampRight.value -> {
type = Maneuver.TYPE_OFF_RAMP_SLIGHT_RIGHT
currentTurnIcon = R.drawable.ic_turn_slight_right
}
ManeuverType.RampLeft.value -> {
type = Maneuver.TYPE_TURN_NORMAL_LEFT
currentTurnIcon = R.drawable.ic_turn_normal_left
}
ManeuverType.ExitRight.value -> {
type = Maneuver.TYPE_TURN_SLIGHT_RIGHT
currentTurnIcon = R.drawable.ic_turn_slight_right
}
ManeuverType.StayRight.value -> {
type = Maneuver.TYPE_KEEP_RIGHT
currentTurnIcon = R.drawable.ic_turn_name_change
}
ManeuverType.StayLeft.value -> {
type = Maneuver.TYPE_KEEP_LEFT
currentTurnIcon = R.drawable.ic_turn_name_change
}
ManeuverType.RoundaboutEnter.value -> {
type = Maneuver.TYPE_ROUNDABOUT_ENTER_CCW
currentTurnIcon = R.drawable.ic_roundabout_ccw
}
ManeuverType.RoundaboutExit.value -> {
type = Maneuver.TYPE_ROUNDABOUT_EXIT_CCW
currentTurnIcon = R.drawable.ic_roundabout_ccw
}
}
maneuverType = type
return Pair(type, currentTurnIcon)
}
fun isNavigating(): Boolean { fun isNavigating(): Boolean {
return navigating return navigating
} }
@@ -200,12 +372,9 @@ open class RouteModel() {
return arrived return arrived
} }
fun stopNavigation() { fun hasArrived(type: Int): Boolean {
route.clear() return type == ManeuverType.DestinationRight.value
navigating = false || maneuverType == ManeuverType.Destination.value
currentShapeIndex = 0 || maneuverType == ManeuverType.DestinationLeft.value
distanceToStepEnd = 0F
beginIndex = 0
endIndex = 0
} }
} }

View File

@@ -13,10 +13,17 @@ import org.maplibre.geojson.Point
import org.maplibre.turf.TurfMisc import org.maplibre.turf.TurfMisc
import java.lang.Math.toDegrees import java.lang.Math.toDegrees
import java.lang.Math.toRadians import java.lang.Math.toRadians
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import kotlin.math.asin import kotlin.math.asin
import kotlin.math.atan2 import kotlin.math.atan2
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.roundToInt
import kotlin.math.sin import kotlin.math.sin
@@ -191,4 +198,16 @@ fun location(longitude : Double, latitude: Double): Location {
location.longitude = longitude location.longitude = longitude
location.latitude = latitude location.latitude = latitude
return location return location
}
fun formatDateTime(time: Long): String {
val dateFormatter = DateTimeFormatter.ofLocalizedTime( FormatStyle.SHORT)
val dateTime = LocalDateTime.ofEpochSecond(time / 1000, 0, ZoneOffset.UTC)
val zdt = ZonedDateTime.of(dateTime, ZoneId.of("Europe/Berlin"))
return zdt.format(dateFormatter)
}
fun Double.round(numFractionDigits: Int): Double {
val factor = 10.0.pow(numFractionDigits.toDouble())
return (this * factor).roundToInt() / factor
} }

View File

@@ -13,30 +13,31 @@ junitVersion = "1.3.0"
espressoCore = "3.7.0" espressoCore = "3.7.0"
kotlinxSerializationJson = "1.9.0" kotlinxSerializationJson = "1.9.0"
lifecycleRuntimeKtx = "2.10.0" lifecycleRuntimeKtx = "2.10.0"
composeBom = "2025.11.01" composeBom = "2025.12.00"
appcompat = "1.7.1" appcompat = "1.7.1"
material = "1.13.0" material = "1.13.0"
carApp = "1.7.0" carApp = "1.7.0"
androidx-car = "1.7.0-beta01" androidx-car = "1.7.0"
objectboxKotlin = "5.0.1" objectboxKotlin = "5.0.1"
objectboxProcessor = "5.0.1" objectboxProcessor = "5.0.1"
ui = "1.9.5" ui = "1.10.0"
material3 = "1.4.0" material3 = "1.4.0"
runtimeLivedata = "1.9.5" runtimeLivedata = "1.10.0"
foundation = "1.9.5" foundation = "1.10.0"
maplibre-composeMaterial3 = "0.12.2" maplibre-composeMaterial3 = "0.12.2"
maplibre-compose = "0.12.1" maplibre-compose = "0.12.1"
playServicesLocation = "21.3.0" playServicesLocation = "21.3.0"
runtime = "1.9.5" runtime = "1.10.0"
accompanist = "0.37.3" accompanist = "0.37.3"
uiVersion = "1.9.5" uiVersion = "1.10.0"
uiText = "1.9.5" uiText = "1.10.0"
navigationCompose = "2.9.6" navigationCompose = "2.9.6"
uiToolingPreview = "1.9.5" uiToolingPreview = "1.10.0"
uiTooling = "1.9.5" uiTooling = "1.10.0"
material3WindowSizeClass = "1.4.0" material3WindowSizeClass = "1.4.0"
uiGraphics = "1.10.0" uiGraphics = "1.10.0"
window = "1.5.1" window = "1.5.1"
foundationLayout = "1.10.0"
[libraries] [libraries]
@@ -59,7 +60,6 @@ material = { group = "com.google.android.material", name = "material", version.r
androidx-car-app = { group = "androidx.car.app", name = "app", version.ref = "carApp" } androidx-car-app = { group = "androidx.car.app", name = "app", version.ref = "carApp" }
objectbox-kotlin = { module = "io.objectbox:objectbox-kotlin", version.ref = "objectboxKotlin" } objectbox-kotlin = { module = "io.objectbox:objectbox-kotlin", version.ref = "objectboxKotlin" }
objectbox-processor = { module = "io.objectbox:objectbox-processor", version.ref = "objectboxProcessor" } objectbox-processor = { module = "io.objectbox:objectbox-processor", version.ref = "objectboxProcessor" }
ui = { group = "androidx.compose.ui", name = "ui", version.ref = "ui" }
maplibre-compose = { module = "org.maplibre.compose:maplibre-compose", version.ref = "maplibre-compose" } maplibre-compose = { module = "org.maplibre.compose:maplibre-compose", version.ref = "maplibre-compose" }
maplibre-composeMaterial3 = { module = "org.maplibre.compose:maplibre-compose-material3", version = "maplibre-composeMaterial3" } maplibre-composeMaterial3 = { module = "org.maplibre.compose:maplibre-compose-material3", version = "maplibre-composeMaterial3" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" } androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" }
@@ -77,6 +77,7 @@ androidx-compose-material3-window-size-class1 = { group = "androidx.compose.mate
androidx-app-automotive = { module = "androidx.car.app:app-automotive", version.ref = "androidx-car" } androidx-app-automotive = { module = "androidx.car.app:app-automotive", version.ref = "androidx-car" }
androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics", version.ref = "uiGraphics" } androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics", version.ref = "uiGraphics" }
androidx-window = { group = "androidx.window", name = "window", version.ref = "window" } androidx-window = { group = "androidx.window", name = "window", version.ref = "window" }
androidx-compose-foundation-layout = { group = "androidx.compose.foundation", name = "foundation-layout", version.ref = "foundationLayout" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }