Lanes
@@ -13,8 +13,8 @@ android {
|
|||||||
applicationId = "com.kouros.navigation"
|
applicationId = "com.kouros.navigation"
|
||||||
minSdk = 33
|
minSdk = 33
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 66
|
versionCode = 68
|
||||||
versionName = "0.2.0.66"
|
versionName = "0.2.0.68"
|
||||||
base.archivesName = "navi-$versionName"
|
base.archivesName = "navi-$versionName"
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.annotation.RequiresPermission
|
import androidx.annotation.RequiresPermission
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
@@ -172,6 +173,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
setContent {
|
setContent {
|
||||||
|
NavigationTheme {
|
||||||
CheckPermissionScreen(app = {
|
CheckPermissionScreen(app = {
|
||||||
AppNavGraph(
|
AppNavGraph(
|
||||||
mainActivity = this
|
mainActivity = this
|
||||||
@@ -179,15 +181,21 @@ class MainActivity : ComponentActivity() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun StartScreen(
|
fun StartScreen(
|
||||||
navController: NavHostController
|
navController: NavHostController
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val appViewModel: AppViewModel = appViewModel()
|
val appViewModel: AppViewModel = appViewModel()
|
||||||
val darkMode by appViewModel.darkMode.collectAsState()
|
val darkMode by appViewModel.darkMode.collectAsState()
|
||||||
|
|
||||||
|
if (darkMode == 1) {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||||
|
} else {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||||
|
}
|
||||||
val baseStyle = BaseStyleModel().readStyle(applicationContext, darkMode, darkMode == 1)
|
val baseStyle = BaseStyleModel().readStyle(applicationContext, darkMode, darkMode == 1)
|
||||||
val locationProvider = rememberDefaultLocationProvider(
|
val locationProvider = rememberDefaultLocationProvider(
|
||||||
updateInterval = 0.5.seconds, desiredAccuracy = DesiredAccuracy.Highest
|
updateInterval = 0.5.seconds, desiredAccuracy = DesiredAccuracy.Highest
|
||||||
|
|||||||
@@ -16,10 +16,37 @@ fun AppNavGraph(mainActivity: MainActivity) {
|
|||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
NavHost(navController = navController, startDestination = "startScreen") {
|
NavHost(navController = navController, startDestination = "startScreen") {
|
||||||
composable("startScreen") { mainActivity.StartScreen(navController) }
|
composable("startScreen") { mainActivity.StartScreen(navController) }
|
||||||
composable("display_settings") { SettingsRoute("display_settings", navController) { navController.popBackStack() } }
|
composable("display_settings") {
|
||||||
composable("nav_settings") { SettingsRoute("nav_settings", navController) { navController.popBackStack() } }
|
SettingsRoute(
|
||||||
composable("settings") { SettingsRoute("settings", navController) { navController.popBackStack() } }
|
"display_settings",
|
||||||
composable("search") { SearchScreen(navController, navController.context, navigationViewModel, mainActivity.lastLocation) { navController.popBackStack() }
|
navController
|
||||||
|
) { navController.popBackStack() }
|
||||||
|
}
|
||||||
|
composable("nav_settings") {
|
||||||
|
SettingsRoute(
|
||||||
|
"nav_settings",
|
||||||
|
navController
|
||||||
|
) { navController.popBackStack() }
|
||||||
|
}
|
||||||
|
composable("settings") {
|
||||||
|
SettingsRoute(
|
||||||
|
"settings",
|
||||||
|
navController
|
||||||
|
) { navController.popBackStack() }
|
||||||
|
}
|
||||||
|
composable("search") {
|
||||||
|
SearchScreen(
|
||||||
|
navController,
|
||||||
|
navController.context,
|
||||||
|
navigationViewModel,
|
||||||
|
mainActivity.lastLocation
|
||||||
|
) { navController.popBackStack() }
|
||||||
|
}
|
||||||
|
composable("settings_screen") {
|
||||||
|
SettingsRoute(
|
||||||
|
"settings_screen",
|
||||||
|
navController
|
||||||
|
) { navController.popBackStack() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package com.kouros.navigation.ui.search
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.horizontalScroll
|
import androidx.compose.foundation.horizontalScroll
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
@@ -28,14 +30,17 @@ import androidx.compose.material3.Scaffold
|
|||||||
import androidx.compose.material3.SearchBar
|
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.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.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
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
@@ -49,8 +54,11 @@ 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
|
||||||
import com.kouros.navigation.model.NavigationViewModel
|
import com.kouros.navigation.model.NavigationViewModel
|
||||||
|
import com.kouros.navigation.ui.app.AppViewModel
|
||||||
|
import com.kouros.navigation.ui.app.appViewModel
|
||||||
import com.kouros.navigation.ui.theme.NavigationTheme
|
import com.kouros.navigation.ui.theme.NavigationTheme
|
||||||
import com.kouros.navigation.utils.location
|
import com.kouros.navigation.utils.location
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
|
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
|
||||||
@@ -64,10 +72,18 @@ fun SearchScreen(
|
|||||||
function: () -> Unit
|
function: () -> Unit
|
||||||
) {
|
) {
|
||||||
|
|
||||||
NavigationTheme(true) {
|
val appViewModel: AppViewModel = appViewModel()
|
||||||
|
val darkMode by appViewModel.darkMode.collectAsState()
|
||||||
|
|
||||||
|
if (darkMode == 1 || darkMode == 2 && isSystemInDarkTheme()) {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||||
|
} else {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||||
|
}
|
||||||
|
//NavigationTheme(darkMode == 1 || darkMode == 2 && isSystemInDarkTheme()) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
CenterAlignedTopAppBar(
|
TopAppBar(
|
||||||
title = {
|
title = {
|
||||||
Text(
|
Text(
|
||||||
stringResource(id = R.string.search_action_title),
|
stringResource(id = R.string.search_action_title),
|
||||||
@@ -92,7 +108,7 @@ fun SearchScreen(
|
|||||||
Categories(context, navigationViewModel, location, closeSheet = { })
|
Categories(context, navigationViewModel, location, closeSheet = { })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@@ -118,9 +134,6 @@ fun SearchBar(
|
|||||||
}
|
}
|
||||||
|
|
||||||
SearchBar(
|
SearchBar(
|
||||||
colors = SearchBarDefaults.colors(
|
|
||||||
containerColor = MaterialTheme.colorScheme.secondaryContainer
|
|
||||||
),
|
|
||||||
inputField = {
|
inputField = {
|
||||||
SearchBarDefaults.InputField(
|
SearchBarDefaults.InputField(
|
||||||
modifier = Modifier.focusRequester(focusRequester),
|
modifier = Modifier.focusRequester(focusRequester),
|
||||||
@@ -206,11 +219,11 @@ private fun SearchPlaces(
|
|||||||
) {
|
) {
|
||||||
val color = remember { PlaceColor }
|
val color = remember { PlaceColor }
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 10.dp),
|
contentPadding = PaddingValues(horizontal = 6.dp, vertical = 10.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
) {
|
) {
|
||||||
items(searchResults, key = { it.placeId }) { place ->
|
items(searchResults, key = { it.placeId }) { place ->
|
||||||
Row {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(id = R.drawable.ic_place_white_24dp),
|
painter = painterResource(id = R.drawable.ic_place_white_24dp),
|
||||||
"Navigation",
|
"Navigation",
|
||||||
@@ -218,8 +231,11 @@ private fun SearchPlaces(
|
|||||||
modifier = Modifier.size(24.dp, 24.dp),
|
modifier = Modifier.size(24.dp, 24.dp),
|
||||||
)
|
)
|
||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = { Text(place.displayName) },
|
headlineContent = {Text(place.address.road)},
|
||||||
|
leadingContent = {Text(place.name)},
|
||||||
|
trailingContent = { Text("${(place.distance/1000).roundToInt()} km") },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.animateItem()
|
||||||
.clickable {
|
.clickable {
|
||||||
val pl = Place(
|
val pl = Place(
|
||||||
name = place.name,
|
name = place.name,
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ private fun RecentPlaces(
|
|||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(id = R.drawable.ic_place_white_24dp),
|
painter = painterResource(id = R.drawable.ic_place_white_24dp),
|
||||||
"Navigation",
|
"Navigation",
|
||||||
tint = color.copy(alpha = 1f),
|
//tint = color.copy(alpha = 1f),
|
||||||
modifier = Modifier.size(24.dp, 24.dp),
|
modifier = Modifier.size(24.dp, 24.dp),
|
||||||
)
|
)
|
||||||
ListItem(
|
ListItem(
|
||||||
|
|||||||
@@ -1,35 +1,41 @@
|
|||||||
package com.kouros.navigation.ui.settings
|
package com.kouros.navigation.ui.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.CenterAlignedTopAppBar
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedCard
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.SegmentedButtonDefaults.Icon
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
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.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.navigation.NavHostController
|
|
||||||
import com.kouros.data.R
|
import com.kouros.data.R
|
||||||
import com.kouros.navigation.model.SettingsViewModel
|
import com.kouros.navigation.model.SettingsViewModel
|
||||||
import com.kouros.navigation.ui.components.RadioButtonSingleSelection
|
import com.kouros.navigation.ui.components.RadioButtonSingleSelection
|
||||||
import com.kouros.navigation.ui.components.SectionTitle
|
import com.kouros.navigation.ui.components.SectionTitle
|
||||||
import com.kouros.navigation.ui.components.SettingSwitch
|
import com.kouros.navigation.ui.components.SettingSwitch
|
||||||
import com.kouros.navigation.ui.theme.NavigationTheme
|
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -37,10 +43,12 @@ fun DisplayScreen(viewModel: SettingsViewModel, navigateBack: () -> Unit) {
|
|||||||
|
|
||||||
val darkMode by viewModel.darkMode.collectAsState()
|
val darkMode by viewModel.darkMode.collectAsState()
|
||||||
val show3D by viewModel.show3D.collectAsState()
|
val show3D by viewModel.show3D.collectAsState()
|
||||||
NavigationTheme(useDarkTheme = viewModel.darkMode.collectAsState().value == 1) {
|
val showTraffic by viewModel.traffic.collectAsState()
|
||||||
|
val distanceMode by viewModel.distanceMode.collectAsState()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
CenterAlignedTopAppBar(
|
TopAppBar(
|
||||||
title = {
|
title = {
|
||||||
Text(
|
Text(
|
||||||
stringResource(id = R.string.display_settings),
|
stringResource(id = R.string.display_settings),
|
||||||
@@ -58,31 +66,39 @@ fun DisplayScreen(viewModel: SettingsViewModel, navigateBack: () -> Unit) {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
{ padding ->
|
{ paddingValues ->
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.padding(paddingValues)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(top = 20.dp)
|
.padding(top = 10.dp)
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
) {
|
) {
|
||||||
|
OutlinedCard(modifier = Modifier.fillMaxWidth()) {
|
||||||
Text(
|
Column(
|
||||||
text = stringResource(R.string.settings_action_title),
|
modifier = Modifier.padding(10.dp),
|
||||||
style = MaterialTheme.typography.headlineMedium
|
) {
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
|
|
||||||
// Appearance
|
|
||||||
SectionTitle(stringResource(R.string.threed_building))
|
|
||||||
|
|
||||||
SettingSwitch(
|
SettingSwitch(
|
||||||
title = stringResource(R.string.threed_building),
|
title = stringResource(R.string.threed_building),
|
||||||
checked = show3D,
|
checked = show3D,
|
||||||
onCheckedChange = viewModel::onShow3DChanged
|
onCheckedChange = viewModel::onShow3DChanged
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SettingSwitch(
|
||||||
|
title = stringResource(R.string.traffic),
|
||||||
|
checked = showTraffic,
|
||||||
|
onCheckedChange = viewModel::onTraffic
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
|
OutlinedCard(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(10.dp),
|
||||||
|
) {
|
||||||
SectionTitle(stringResource(R.string.dark_mode))
|
SectionTitle(stringResource(R.string.dark_mode))
|
||||||
|
|
||||||
val radioOptions = listOf(
|
val radioOptions = listOf(
|
||||||
@@ -98,19 +114,29 @@ fun DisplayScreen(viewModel: SettingsViewModel, navigateBack: () -> Unit) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
|
OutlinedCard(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(10.dp),
|
||||||
|
) {
|
||||||
|
SectionTitle(stringResource(R.string.distance_units))
|
||||||
|
|
||||||
|
val radioOptions = listOf(
|
||||||
|
stringResource(R.string.automatically),
|
||||||
|
stringResource(R.string.kilometer),
|
||||||
|
stringResource(R.string.miles)
|
||||||
|
)
|
||||||
|
RadioButtonSingleSelection(
|
||||||
|
modifier = Modifier.padding(),
|
||||||
|
selectedOption = distanceMode,
|
||||||
|
radioOptions = radioOptions,
|
||||||
|
onClick = viewModel::onDistanceModeChanged
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package com.kouros.navigation.ui.settings
|
package com.kouros.navigation.ui.settings
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
@@ -10,9 +13,11 @@ import androidx.compose.material3.CenterAlignedTopAppBar
|
|||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.OutlinedCard
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextField
|
import androidx.compose.material3.TextField
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -38,11 +43,9 @@ import com.kouros.navigation.ui.theme.NavigationTheme
|
|||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun NavigationScreen(viewModel: SettingsViewModel, navigateBack: () -> Unit) {
|
fun NavigationScreen(viewModel: SettingsViewModel, navigateBack: () -> Unit) {
|
||||||
|
|
||||||
NavigationTheme(useDarkTheme = viewModel.darkMode.collectAsState().value == 1) {
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
CenterAlignedTopAppBar(
|
TopAppBar(
|
||||||
title = {
|
title = {
|
||||||
Text(
|
Text(
|
||||||
stringResource(id = R.string.navigation_settings),
|
stringResource(id = R.string.navigation_settings),
|
||||||
@@ -64,14 +67,12 @@ fun NavigationScreen(viewModel: SettingsViewModel, navigateBack: () -> Unit) {
|
|||||||
Column(
|
Column(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.consumeWindowInsets(padding)
|
.padding(padding)
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
.padding(top = padding.calculateTopPadding()),
|
|
||||||
) {
|
) {
|
||||||
NavigationSettings(viewModel)
|
NavigationSettings(viewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -82,6 +83,10 @@ fun NavigationSettings(viewModel: SettingsViewModel) {
|
|||||||
val routingEngine by viewModel.routingEngine.collectAsState()
|
val routingEngine by viewModel.routingEngine.collectAsState()
|
||||||
val tomTomApiKey by viewModel.tomTomApiKey.collectAsState()
|
val tomTomApiKey by viewModel.tomTomApiKey.collectAsState()
|
||||||
|
|
||||||
|
OutlinedCard(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(10.dp),
|
||||||
|
) {
|
||||||
SettingSwitch(
|
SettingSwitch(
|
||||||
title = stringResource(R.string.avoid_highways_row_title),
|
title = stringResource(R.string.avoid_highways_row_title),
|
||||||
checked = avoidMotorway,
|
checked = avoidMotorway,
|
||||||
@@ -99,7 +104,15 @@ fun NavigationSettings(viewModel: SettingsViewModel) {
|
|||||||
checked = carLocation,
|
checked = carLocation,
|
||||||
onCheckedChange = viewModel::onCarLocation
|
onCheckedChange = viewModel::onCarLocation
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
|
OutlinedCard(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(10.dp),
|
||||||
|
) {
|
||||||
SectionTitle(stringResource(R.string.routing_engine))
|
SectionTitle(stringResource(R.string.routing_engine))
|
||||||
|
|
||||||
val routingEngineOptions = listOf(
|
val routingEngineOptions = listOf(
|
||||||
@@ -127,4 +140,6 @@ fun NavigationSettings(viewModel: SettingsViewModel) {
|
|||||||
modifier = Modifier.padding(20.dp)
|
modifier = Modifier.padding(20.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
120
app/src/main/java/com/kouros/navigation/ui/settings/Settings.kt
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
package com.kouros.navigation.ui.settings
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.RowScope
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedCard
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
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.navigation.NavHostController
|
||||||
|
import com.kouros.data.R
|
||||||
|
import com.kouros.navigation.model.SettingsViewModel
|
||||||
|
import com.kouros.navigation.ui.theme.NavigationTheme
|
||||||
|
|
||||||
|
data class Settings(val id: String, val name: String, val icon: Int)
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun Settings(
|
||||||
|
viewModel: SettingsViewModel,
|
||||||
|
navController: NavHostController,
|
||||||
|
navigateBack: () -> Unit
|
||||||
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
val items = listOf(
|
||||||
|
Settings(
|
||||||
|
id = "favorites_screen",
|
||||||
|
name = "Favoriten",
|
||||||
|
icon = R.drawable.ic_favorite_white_24dp
|
||||||
|
),
|
||||||
|
Settings(
|
||||||
|
id = "settings_screen",
|
||||||
|
name = "Einstellungen",
|
||||||
|
icon = R.drawable.speed_camera_24px
|
||||||
|
),
|
||||||
|
Settings(id = "info_screen", name = "Info", icon = R.drawable.ic_place_white_24dp),
|
||||||
|
)
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text(stringResource(id = R.string.settings_action_title)) },
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { paddingValues ->
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(paddingValues)
|
||||||
|
.padding(8.dp),
|
||||||
|
) {
|
||||||
|
item {
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
}
|
||||||
|
items(items) { subItem ->
|
||||||
|
ScreenItem(item = subItem, onClick = { navController.navigate(subItem.id) })
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ScreenItem(
|
||||||
|
item: Settings,
|
||||||
|
onClick: (Settings) -> Unit,
|
||||||
|
) {
|
||||||
|
OutlinedCard(onClick = { onClick(item) }, modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(10.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(item.icon),
|
||||||
|
contentDescription = stringResource(id = R.string.accept_action_title),
|
||||||
|
modifier = Modifier.align(Alignment.CenterVertically),
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
Text(text = item.name, style = MaterialTheme.typography.titleMedium)
|
||||||
|
}
|
||||||
|
IconForward()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RowScope.IconForward() {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.arrow_back_24px),
|
||||||
|
contentDescription = stringResource(id = R.string.on_action_title),
|
||||||
|
modifier = Modifier.align(Alignment.CenterVertically),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -34,6 +34,9 @@ fun SettingsRoute(route: String, navController: NavHostController, function: ()
|
|||||||
NavigationScreen (viewModel = viewModel, function)
|
NavigationScreen (viewModel = viewModel, function)
|
||||||
}
|
}
|
||||||
if (route == "settings") {
|
if (route == "settings") {
|
||||||
|
Settings(viewModel, navController, function)
|
||||||
|
}
|
||||||
|
if (route == "settings_screen") {
|
||||||
SettingsScreen(viewModel, navController, function)
|
SettingsScreen(viewModel, navController, function)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
package com.kouros.navigation.ui.settings
|
package com.kouros.navigation.ui.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.CenterAlignedTopAppBar
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedCard
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
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.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@@ -24,49 +28,79 @@ import com.kouros.data.R
|
|||||||
import com.kouros.navigation.model.SettingsViewModel
|
import com.kouros.navigation.model.SettingsViewModel
|
||||||
import com.kouros.navigation.ui.theme.NavigationTheme
|
import com.kouros.navigation.ui.theme.NavigationTheme
|
||||||
|
|
||||||
|
|
||||||
|
data class Item(val id: String, val name: String, val description: String, val icon: Int)
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsScreen(viewModel: SettingsViewModel, navController: NavHostController, navigateBack: () -> Unit) {
|
fun SettingsScreen(
|
||||||
NavigationTheme(useDarkTheme = viewModel.darkMode.collectAsState().value == 1) {
|
viewModel: SettingsViewModel,
|
||||||
|
navController: NavHostController,
|
||||||
|
navigateBack: () -> Unit
|
||||||
|
) {
|
||||||
|
|
||||||
|
val items = listOf(
|
||||||
|
Item(
|
||||||
|
id = "display_settings",
|
||||||
|
name = "Display Settings",
|
||||||
|
description = "",
|
||||||
|
icon = R.drawable.dark_mode_24px
|
||||||
|
),
|
||||||
|
Item(
|
||||||
|
id = "nav_settings",
|
||||||
|
name = "Navigation Settings",
|
||||||
|
description = "",
|
||||||
|
icon = R.drawable.navigation_24px
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
CenterAlignedTopAppBar(
|
TopAppBar(
|
||||||
title = {
|
title = { Text("Settings") },
|
||||||
Text(
|
|
||||||
stringResource(id = R.string.settings_action_title),
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
navigationIcon = {
|
) { paddingValues ->
|
||||||
IconButton(onClick = navigateBack) {
|
LazyColumn(
|
||||||
Icon(
|
modifier = Modifier
|
||||||
painter = painterResource(R.drawable.arrow_back_24px),
|
.padding(paddingValues)
|
||||||
contentDescription = stringResource(id = R.string.accept_action_title),
|
.padding(8.dp),
|
||||||
modifier = Modifier.size(48.dp, 48.dp),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) { padding ->
|
|
||||||
val scrollState = rememberScrollState()
|
|
||||||
Column(
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.consumeWindowInsets(padding)
|
|
||||||
.verticalScroll(scrollState)
|
|
||||||
.padding(top = padding.calculateTopPadding()),
|
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.padding(16.dp)) {
|
item {
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
Button(onClick = { navController.navigate("display_settings") }) {
|
|
||||||
Text(stringResource(R.string.display_settings))
|
|
||||||
}
|
|
||||||
Button(onClick = { navController.navigate("nav_settings") }) {
|
|
||||||
Text(stringResource(R.string.navigation_settings))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
items(items) { subItem ->
|
||||||
|
ScreenItem(item = subItem, onClick = { navController.navigate(subItem.id) })
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ScreenItem(
|
||||||
|
item: Item,
|
||||||
|
onClick: (Item) -> Unit,
|
||||||
|
) {
|
||||||
|
OutlinedCard(onClick = { onClick(item) }, modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(10.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(item.icon),
|
||||||
|
contentDescription = stringResource(id = R.string.accept_action_title),
|
||||||
|
modifier = Modifier.align(Alignment.CenterVertically),
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
Text(text = item.name, style = MaterialTheme.typography.titleMedium)
|
||||||
|
}
|
||||||
|
IconForward()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,28 +84,24 @@ private val DarkColors = darkColorScheme(
|
|||||||
@Composable
|
@Composable
|
||||||
fun NavigationTheme(
|
fun NavigationTheme(
|
||||||
useDarkTheme: Boolean = isSystemInDarkTheme(),
|
useDarkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
|
dynamicColor: Boolean = true,
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
val colorScheme = when {
|
||||||
|
dynamicColor -> {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val colors = run {
|
if (useDarkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||||
if (useDarkTheme) dynamicDarkColorScheme(context)
|
|
||||||
else dynamicLightColorScheme(context)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val view = LocalView.current
|
useDarkTheme -> DarkColors
|
||||||
if (!view.isInEditMode) {
|
else -> LightColors
|
||||||
SideEffect {
|
|
||||||
val window = (view.context as Activity).window
|
|
||||||
window.statusBarColor = colors.primary.toArgb()
|
|
||||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars =
|
|
||||||
useDarkTheme
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialTheme(
|
MaterialTheme(
|
||||||
colorScheme = if (useDarkTheme) DarkColors else colorScheme,
|
|
||||||
|
colorScheme = colorScheme,
|
||||||
typography = typography,
|
typography = typography,
|
||||||
content = content,
|
content = content,
|
||||||
shapes = shapes,
|
shapes = shapes,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -176,14 +176,20 @@ class RouteModelTest {
|
|||||||
@Test
|
@Test
|
||||||
fun simulate() {
|
fun simulate() {
|
||||||
for ((index, waypoint) in routeModel.curRoute.waypoints.withIndex()) {
|
for ((index, waypoint) in routeModel.curRoute.waypoints.withIndex()) {
|
||||||
val curLocation = location(waypoint[0], waypoint[1])
|
|
||||||
if (routeModel.isNavigating()) {
|
if (routeModel.isNavigating()) {
|
||||||
|
val curLocation = location(waypoint[0], waypoint[1])
|
||||||
if (index in 0..routeModel.curRoute.waypoints.size) {
|
if (index in 0..routeModel.curRoute.waypoints.size) {
|
||||||
//runBlocking { delay(1000) }
|
//runBlocking { delay(1000) }
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
routeModel.updateLocation(curLocation, NavigationViewModel(TomTomRepository()))
|
routeModel.updateLocation(curLocation, NavigationViewModel(TomTomRepository()))
|
||||||
val stepData = routeModel.currentStep()
|
val stepData = routeModel.currentStep()
|
||||||
println("${stepData.instruction} ${System.currentTimeMillis() - start}")
|
//println("${stepData.instruction} ${System.currentTimeMillis() - start}")
|
||||||
|
if (stepData.lane.isNotEmpty()) {
|
||||||
|
println(stepData.street)
|
||||||
|
stepData.lane.forEach {
|
||||||
|
println("${it.indications} ${it.valid}")
|
||||||
|
}
|
||||||
|
}
|
||||||
// val nextData = routeModel.nextStep()
|
// val nextData = routeModel.nextStep()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,17 +198,17 @@ class RouteModelTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `leftStepDistance Inglolstädter `() {
|
fun `leftStepDistance Inglolstädter `() {
|
||||||
val location: Location = location( 11.584578, 48.183653)
|
val location: Location = location(11.584578, 48.183653)
|
||||||
routeModel.updateLocation(location, NavigationViewModel(TomTomRepository()) )
|
routeModel.updateLocation(location, NavigationViewModel(TomTomRepository()))
|
||||||
val step = routeModel.currentStep()
|
val step = routeModel.currentStep()
|
||||||
assertEquals(step.leftStepDistance, 645.0, 1.0)
|
assertEquals(step.leftStepDistance, 645.0, 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `leftStepDistance Vogelhart `() {
|
fun `leftStepDistance Vogelhart `() {
|
||||||
val location: Location = location( 11.578911, 48.185565)
|
val location: Location = location(11.578911, 48.185565)
|
||||||
routeModel.updateLocation(location, NavigationViewModel(TomTomRepository()) )
|
routeModel.updateLocation(location, NavigationViewModel(TomTomRepository()))
|
||||||
val step = routeModel.currentStep()
|
val step = routeModel.currentStep()
|
||||||
assertEquals(step.leftStepDistance , 34.0, 1.0)
|
assertEquals(step.leftStepDistance, 34.0, 1.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,13 +2,11 @@ package com.kouros.navigation.car.map
|
|||||||
|
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
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.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.text.BasicText
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@@ -17,10 +15,8 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.scale
|
import androidx.compose.ui.draw.scale
|
||||||
import androidx.compose.ui.geometry.CornerRadius
|
import androidx.compose.ui.geometry.CornerRadius
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.geometry.Size
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.drawscope.scale
|
import androidx.compose.ui.graphics.drawscope.scale
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.drawText
|
import androidx.compose.ui.text.drawText
|
||||||
@@ -36,7 +32,6 @@ 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
|
||||||
import com.kouros.navigation.utils.isMetricSystem
|
import com.kouros.navigation.utils.isMetricSystem
|
||||||
import com.kouros.navigation.utils.location
|
|
||||||
import org.maplibre.compose.camera.CameraPosition
|
import org.maplibre.compose.camera.CameraPosition
|
||||||
import org.maplibre.compose.camera.CameraState
|
import org.maplibre.compose.camera.CameraState
|
||||||
import org.maplibre.compose.camera.rememberCameraState
|
import org.maplibre.compose.camera.rememberCameraState
|
||||||
@@ -63,7 +58,6 @@ import org.maplibre.compose.sources.Source
|
|||||||
import org.maplibre.compose.sources.getBaseSource
|
import org.maplibre.compose.sources.getBaseSource
|
||||||
import org.maplibre.compose.sources.rememberGeoJsonSource
|
import org.maplibre.compose.sources.rememberGeoJsonSource
|
||||||
import org.maplibre.compose.style.BaseStyle
|
import org.maplibre.compose.style.BaseStyle
|
||||||
import org.maplibre.spatialk.geojson.BoundingBox
|
|
||||||
import org.maplibre.spatialk.geojson.Position
|
import org.maplibre.spatialk.geojson.Position
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,11 @@ class RouteCarModel : RouteModel() {
|
|||||||
)
|
)
|
||||||
.setRemainingTimeColor(CarColor.GREEN)
|
.setRemainingTimeColor(CarColor.GREEN)
|
||||||
.setRemainingDistanceColor(CarColor.BLUE)
|
.setRemainingDistanceColor(CarColor.BLUE)
|
||||||
.setTripText(CarText.create("$traffic min"))
|
if (traffic > 0) {
|
||||||
|
travelBuilder.setTripText(CarText.create("$traffic min"))
|
||||||
|
travelBuilder.setTripIcon(createCarIcon(carContext, R.drawable.warning_24px))
|
||||||
|
}
|
||||||
|
|
||||||
if (navState.travelMessage.isNotEmpty()) {
|
if (navState.travelMessage.isNotEmpty()) {
|
||||||
travelBuilder.setTripIcon(createCarIcon(carContext, R.drawable.warning_24px))
|
travelBuilder.setTripIcon(createCarIcon(carContext, R.drawable.warning_24px))
|
||||||
travelBuilder.setTripText(CarText.create(navState.travelMessage))
|
travelBuilder.setTripText(CarText.create(navState.travelMessage))
|
||||||
@@ -143,7 +147,7 @@ class RouteCarModel : RouteModel() {
|
|||||||
}
|
}
|
||||||
val laneType =
|
val laneType =
|
||||||
Lane.Builder()
|
Lane.Builder()
|
||||||
.addDirection(LaneDirection.create(laneDirection, true))
|
.addDirection(LaneDirection.create(laneDirection, it.valid))
|
||||||
.build()
|
.build()
|
||||||
step.addLane(laneType)
|
step.addLane(laneType)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import android.location.Location
|
|||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import androidx.lifecycle.LifecycleCoroutineScope
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
|
import com.kouros.navigation.data.Constants.homeVogelhart
|
||||||
|
import com.kouros.navigation.utils.location
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -17,6 +19,10 @@ class Simulation {
|
|||||||
lifecycleScope: LifecycleCoroutineScope,
|
lifecycleScope: LifecycleCoroutineScope,
|
||||||
updateLocation: (Location) -> Unit
|
updateLocation: (Location) -> Unit
|
||||||
) {
|
) {
|
||||||
|
// A92
|
||||||
|
//updateLocation(location(11.709508, 48.338923 ))
|
||||||
|
//updateLocation(homeVogelhart)
|
||||||
|
|
||||||
if (routeModel.navState.route.isRouteValid()) {
|
if (routeModel.navState.route.isRouteValid()) {
|
||||||
val points = routeModel.curRoute.waypoints
|
val points = routeModel.curRoute.waypoints
|
||||||
if (points.isEmpty()) return
|
if (points.isEmpty()) return
|
||||||
@@ -38,7 +44,7 @@ class Simulation {
|
|||||||
// Update your app's state as if a real GPS update occurred
|
// Update your app's state as if a real GPS update occurred
|
||||||
updateLocation(fakeLocation)
|
updateLocation(fakeLocation)
|
||||||
// Wait before moving to the next point (e.g., every 1 second)
|
// Wait before moving to the next point (e.g., every 1 second)
|
||||||
delay(1000)
|
delay(500)
|
||||||
lastLocation = fakeLocation
|
lastLocation = fakeLocation
|
||||||
}
|
}
|
||||||
routeModel.stopNavigation()
|
routeModel.stopNavigation()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.kouros.navigation.car.screen
|
package com.kouros.navigation.car.screen
|
||||||
|
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.car.app.CarContext
|
import androidx.car.app.CarContext
|
||||||
import androidx.car.app.Screen
|
import androidx.car.app.Screen
|
||||||
import androidx.car.app.model.Action
|
import androidx.car.app.model.Action
|
||||||
@@ -40,8 +41,17 @@ class CategoriesScreen(
|
|||||||
Category(id = CHARGING_STATION, name = carContext.getString(R.string.charging_station))
|
Category(id = CHARGING_STATION, name = carContext.getString(R.string.charging_station))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val backPressedCallback = object : OnBackPressedCallback(false) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
navigationViewModel.elements.value = emptyList()
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
navigationViewModel.elements.value = emptyList()
|
||||||
navigationViewModel.elements.observe(this, categoryObserver)
|
navigationViewModel.elements.observe(this, categoryObserver)
|
||||||
|
carContext.onBackPressedDispatcher.addCallback(this, backPressedCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGetTemplate(): Template {
|
override fun onGetTemplate(): Template {
|
||||||
|
|||||||
@@ -530,8 +530,7 @@ class NavigationScreen(
|
|||||||
* Pushes the search screen and handles the search result.
|
* Pushes the search screen and handles the search result.
|
||||||
*/
|
*/
|
||||||
private fun startSearchScreen() {
|
private fun startSearchScreen() {
|
||||||
navigationViewModel.recentPlaces.value = emptyList()
|
|
||||||
navigationViewModel.previewRoute.value = ""
|
|
||||||
screenManager
|
screenManager
|
||||||
.pushForResult(
|
.pushForResult(
|
||||||
SearchScreen(
|
SearchScreen(
|
||||||
|
|||||||
@@ -39,11 +39,12 @@ class PlaceListScreen(
|
|||||||
private val places: List<Place>
|
private val places: List<Place>
|
||||||
) : Screen(carContext) {
|
) : Screen(carContext) {
|
||||||
|
|
||||||
|
|
||||||
val routeModel = RouteCarModel()
|
val routeModel = RouteCarModel()
|
||||||
|
|
||||||
var place = Place()
|
var place = Place()
|
||||||
|
|
||||||
|
var mPlaces = mutableListOf<Place>()
|
||||||
|
|
||||||
val previewObserver = Observer<String> { route ->
|
val previewObserver = Observer<String> { route ->
|
||||||
if (route.isNotEmpty()) {
|
if (route.isNotEmpty()) {
|
||||||
val repository = getSettingsRepository(carContext)
|
val repository = getSettingsRepository(carContext)
|
||||||
@@ -70,21 +71,25 @@ class PlaceListScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
loadPlaces()
|
// loadPlaces()
|
||||||
|
navigationViewModel.recentPlaces.value = emptyList()
|
||||||
|
navigationViewModel.previewRoute.value = ""
|
||||||
|
|
||||||
|
mPlaces.addAll(places)
|
||||||
navigationViewModel.previewRoute.observe(this, previewObserver)
|
navigationViewModel.previewRoute.observe(this, previewObserver)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGetTemplate(): Template {
|
override fun onGetTemplate(): Template {
|
||||||
val itemListBuilder = ItemList.Builder()
|
val itemListBuilder = ItemList.Builder()
|
||||||
.setNoItemsMessage(carContext.getString(R.string.no_places))
|
.setNoItemsMessage(carContext.getString(R.string.no_places))
|
||||||
places.forEach {
|
mPlaces.forEach {
|
||||||
val street = if (it.street != null) {
|
val street = if (it.street != null) {
|
||||||
it.street
|
it.street
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
val row = Row.Builder()
|
val row = Row.Builder()
|
||||||
// .setImage(contactIcon(it.avatar, it.category))
|
.setImage(contactIcon(null, it.category))
|
||||||
.setTitle("$street ${it.city}")
|
.setTitle("$street ${it.city}")
|
||||||
.setOnClickListener {
|
.setOnClickListener {
|
||||||
place = Place(
|
place = Place(
|
||||||
@@ -155,7 +160,7 @@ class PlaceListScreen(
|
|||||||
carContext,
|
carContext,
|
||||||
R.string.recent_Item_deleted, CarToast.LENGTH_LONG
|
R.string.recent_Item_deleted, CarToast.LENGTH_LONG
|
||||||
).show()
|
).show()
|
||||||
loadPlaces()
|
mPlaces.remove(place)
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
.build()
|
.build()
|
||||||
|
|||||||
@@ -3,16 +3,17 @@ package com.kouros.navigation.car.screen.settings
|
|||||||
import androidx.car.app.CarContext
|
import androidx.car.app.CarContext
|
||||||
import androidx.car.app.Screen
|
import androidx.car.app.Screen
|
||||||
import androidx.car.app.model.Action
|
import androidx.car.app.model.Action
|
||||||
|
import androidx.car.app.model.CarIcon
|
||||||
import androidx.car.app.model.Header
|
import androidx.car.app.model.Header
|
||||||
import androidx.car.app.model.ItemList
|
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 androidx.car.app.model.Toggle
|
||||||
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.kouros.data.R
|
import com.kouros.data.R
|
||||||
import com.kouros.navigation.car.screen.settings.PasswordSettings
|
import com.kouros.navigation.car.navigation.NavigationUtils
|
||||||
import com.kouros.navigation.car.screen.settings.RoutingSettings
|
|
||||||
import com.kouros.navigation.model.NavigationViewModel
|
import com.kouros.navigation.model.NavigationViewModel
|
||||||
import com.kouros.navigation.utils.getSettingsViewModel
|
import com.kouros.navigation.utils.getSettingsViewModel
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
@@ -61,7 +62,8 @@ class NavigationSettings(
|
|||||||
listBuilder.addItem(
|
listBuilder.addItem(
|
||||||
buildRowForTemplate(
|
buildRowForTemplate(
|
||||||
R.string.avoid_highways_row_title,
|
R.string.avoid_highways_row_title,
|
||||||
highwayToggle
|
highwayToggle,
|
||||||
|
NavigationUtils(carContext).createCarIcon(R.drawable.baseline_add_road_24)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -71,7 +73,7 @@ class NavigationSettings(
|
|||||||
settingsViewModel.onAvoidTollway(checked)
|
settingsViewModel.onAvoidTollway(checked)
|
||||||
tollWayToggleState = !tollWayToggleState
|
tollWayToggleState = !tollWayToggleState
|
||||||
}.setChecked(tollWayToggleState).build()
|
}.setChecked(tollWayToggleState).build()
|
||||||
listBuilder.addItem(buildRowForTemplate(R.string.avoid_tolls_row_title, tollwayToggle))
|
listBuilder.addItem(buildRowForTemplate(R.string.avoid_tolls_row_title, tollwayToggle, NavigationUtils(carContext).createCarIcon(R.drawable.baseline_toll_24)))
|
||||||
|
|
||||||
// Ferry
|
// Ferry
|
||||||
val ferryToggle: Toggle =
|
val ferryToggle: Toggle =
|
||||||
@@ -79,7 +81,7 @@ class NavigationSettings(
|
|||||||
settingsViewModel.onAvoidFerry(checked)
|
settingsViewModel.onAvoidFerry(checked)
|
||||||
ferryToggleState = !ferryToggleState
|
ferryToggleState = !ferryToggleState
|
||||||
}.setChecked(ferryToggleState).build()
|
}.setChecked(ferryToggleState).build()
|
||||||
listBuilder.addItem(buildRowForTemplate(R.string.avoid_ferries, ferryToggle))
|
listBuilder.addItem(buildRowForTemplate(R.string.avoid_ferries, ferryToggle, NavigationUtils(carContext).createCarIcon(R.drawable.baseline_directions_boat_filled_24)))
|
||||||
|
|
||||||
// CarLocation
|
// CarLocation
|
||||||
val carLocationToggle: Toggle =
|
val carLocationToggle: Toggle =
|
||||||
@@ -91,7 +93,8 @@ class NavigationSettings(
|
|||||||
listBuilder.addItem(
|
listBuilder.addItem(
|
||||||
buildRowForTemplate(
|
buildRowForTemplate(
|
||||||
R.string.use_car_location,
|
R.string.use_car_location,
|
||||||
carLocationToggle
|
carLocationToggle,
|
||||||
|
NavigationUtils(carContext).createCarIcon(R.drawable.ic_place_white_24dp)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -118,10 +121,11 @@ class NavigationSettings(
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildRowForTemplate(title: Int, toggle: Toggle): Row {
|
private fun buildRowForTemplate(title: Int, toggle: Toggle, icon: CarIcon): Row {
|
||||||
return Row.Builder()
|
return Row.Builder()
|
||||||
.setTitle(carContext.getString(title))
|
.setTitle(carContext.getString(title))
|
||||||
.setToggle(toggle)
|
.setToggle(toggle)
|
||||||
|
.setImage(icon)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation(libs.kotlinx.serialization.json)
|
implementation(libs.kotlinx.serialization.json)
|
||||||
implementation(libs.maplibre.compose)
|
implementation(libs.maplibre.compose)
|
||||||
implementation(libs.androidx.compose.material.icons.extended)
|
//implementation(libs.androidx.compose.material.icons.extended)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
testImplementation(libs.mockito.core)
|
testImplementation(libs.mockito.core)
|
||||||
testImplementation(libs.mockito.kotlin)
|
testImplementation(libs.mockito.kotlin)
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ data class StepData (
|
|||||||
var icon: Int,
|
var icon: Int,
|
||||||
var arrivalTime : Long,
|
var arrivalTime : Long,
|
||||||
var leftDistance: Double,
|
var leftDistance: Double,
|
||||||
var lane: List<Lane> = listOf(Lane(location(0.0, 0.0), valid = false, indications = emptyList())),
|
var lane: List<Lane> = listOf(Lane(location(0.0, 0.0), valid = false, indications = emptyList(), 0, 0)),
|
||||||
var exitNumber: Int = 0,
|
var exitNumber: Int = 0,
|
||||||
var message: String = "",
|
var message: String = "",
|
||||||
)
|
)
|
||||||
@@ -116,7 +116,7 @@ object Constants {
|
|||||||
val homeVogelhart = location(11.5793748, 48.185749)
|
val homeVogelhart = location(11.5793748, 48.185749)
|
||||||
val homeHohenwaldeck = location( 11.594322, 48.1164817)
|
val homeHohenwaldeck = location( 11.594322, 48.1164817)
|
||||||
|
|
||||||
const val NEXT_STEP_THRESHOLD = 1000.0
|
const val NEXT_STEP_THRESHOLD = 500.0
|
||||||
|
|
||||||
const val MAXIMAL_SNAP_CORRECTION = 50.0
|
const val MAXIMAL_SNAP_CORRECTION = 50.0
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ data class NavigationState (
|
|||||||
val lastLocation: Location = location(0.0, 0.0),
|
val lastLocation: Location = location(0.0, 0.0),
|
||||||
val currentLocation: Location = location(0.0, 0.0),
|
val currentLocation: Location = location(0.0, 0.0),
|
||||||
val routeBearing: Float = 0F,
|
val routeBearing: Float = 0F,
|
||||||
|
// index of current route in the list of routes
|
||||||
val currentRouteIndex: Int = 0,
|
val currentRouteIndex: Int = 0,
|
||||||
val destination: Place = Place(),
|
val destination: Place = Place(),
|
||||||
val carConnection: Int = 0,
|
val carConnection: Int = 0,
|
||||||
|
|||||||
@@ -48,7 +48,9 @@ class OsrmRoute {
|
|||||||
val lane = Lane(
|
val lane = Lane(
|
||||||
location(it2.location[0], it2.location[1]),
|
location(it2.location[0], it2.location[1]),
|
||||||
it3.valid,
|
it3.valid,
|
||||||
it3.indications
|
it3.indications,
|
||||||
|
0,
|
||||||
|
0
|
||||||
)
|
)
|
||||||
lanes.add(lane)
|
lanes.add(lane)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ import java.util.Collections
|
|||||||
|
|
||||||
data class Intersection(
|
data class Intersection(
|
||||||
val location: List<Double> = listOf(0.0, 0.0),
|
val location: List<Double> = listOf(0.0, 0.0),
|
||||||
val lane : List<Lane> = Collections.emptyList<Lane>(),
|
val lane : List<Lane> = Collections.emptyList(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,4 +6,6 @@ data class Lane (
|
|||||||
val location: Location,
|
val location: Location,
|
||||||
val valid: Boolean,
|
val valid: Boolean,
|
||||||
var indications: List<String>,
|
var indications: List<String>,
|
||||||
|
val startIndex: Int,
|
||||||
|
val endIndex: Int,
|
||||||
)
|
)
|
||||||
@@ -2,5 +2,4 @@ package com.kouros.navigation.data.route
|
|||||||
|
|
||||||
data class Leg(
|
data class Leg(
|
||||||
var steps : List<Step> = arrayListOf(),
|
var steps : List<Step> = arrayListOf(),
|
||||||
var intersection: List<Intersection> = arrayListOf()
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,5 +10,6 @@ data class Maneuver(
|
|||||||
val location: Location,
|
val location: Location,
|
||||||
val exit: Int = 0,
|
val exit: Int = 0,
|
||||||
val street: String = "",
|
val street: String = "",
|
||||||
val message: String = ""
|
val message: String = "",
|
||||||
|
val pointIndex : Int = 0,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ class TomTomRoute {
|
|||||||
}
|
}
|
||||||
var stepDistance = 0.0
|
var stepDistance = 0.0
|
||||||
var stepDuration = 0.0
|
var stepDuration = 0.0
|
||||||
val allIntersections = mutableListOf<Intersection>()
|
|
||||||
val steps = mutableListOf<Step>()
|
val steps = mutableListOf<Step>()
|
||||||
var lastPointIndex = 0
|
var lastPointIndex = 0
|
||||||
for (index in 1..<route.guidance.instructions.size) {
|
for (index in 1..<route.guidance.instructions.size) {
|
||||||
@@ -56,32 +55,44 @@ class TomTomRoute {
|
|||||||
instruction.point.longitude, instruction.point.latitude
|
instruction.point.longitude, instruction.point.latitude
|
||||||
),
|
),
|
||||||
street = maneuverStreet,
|
street = maneuverStreet,
|
||||||
message = instruction.message
|
message = instruction.message,
|
||||||
|
pointIndex = instruction.pointIndex
|
||||||
)
|
)
|
||||||
|
|
||||||
lastPointIndex = instruction.pointIndex
|
lastPointIndex = instruction.pointIndex
|
||||||
val intersections = mutableListOf<Intersection>()
|
val intersections = mutableListOf<Intersection>()
|
||||||
route.sections?.forEach { section ->
|
route.sections?.forEach { section ->
|
||||||
|
if (section.sectionType == "LANES" && section.startPointIndex <= lastPointIndex && section.endPointIndex >= lastPointIndex) {
|
||||||
val lanes = mutableListOf<Lane>()
|
val lanes = mutableListOf<Lane>()
|
||||||
var startIndex = 0
|
var startIndex = 0
|
||||||
|
var lastLane: Lane? = null
|
||||||
section.lanes?.forEach { itLane ->
|
section.lanes?.forEach { itLane ->
|
||||||
val lane = Lane(
|
val lane = Lane(
|
||||||
location(
|
location = location(
|
||||||
waypoints[section.startPointIndex][0],
|
waypoints[section.startPointIndex][0],
|
||||||
waypoints[section.startPointIndex][1]
|
waypoints[section.startPointIndex][1]
|
||||||
),
|
),
|
||||||
itLane.directions.first() == itLane.follow,
|
valid = itLane.directions.first() == itLane.follow,
|
||||||
itLane.directions
|
indications = itLane.directions,
|
||||||
|
startIndex = startIndex,
|
||||||
|
endIndex = section.endPointIndex
|
||||||
)
|
)
|
||||||
startIndex = section.startPointIndex
|
startIndex = section.startPointIndex
|
||||||
|
if (lastLane == null
|
||||||
|
|| (!(lastLane.valid && lane.valid
|
||||||
|
&& lastLane.indications == lane.indications))
|
||||||
|
) {
|
||||||
lanes.add(lane)
|
lanes.add(lane)
|
||||||
}
|
}
|
||||||
|
lastLane = lane
|
||||||
|
}
|
||||||
intersections.add(Intersection(waypoints[startIndex], lanes))
|
intersections.add(Intersection(waypoints[startIndex], lanes))
|
||||||
|
|
||||||
}
|
}
|
||||||
allIntersections.addAll(intersections)
|
stepDistance =
|
||||||
stepDistance = route.guidance.instructions[index].routeOffsetInMeters - stepDistance
|
route.guidance.instructions[index].routeOffsetInMeters - stepDistance
|
||||||
stepDuration = route.guidance.instructions[index].travelTimeInSeconds - stepDuration
|
stepDuration =
|
||||||
|
route.guidance.instructions[index].travelTimeInSeconds - stepDuration
|
||||||
val step = Step(
|
val step = Step(
|
||||||
index = stepIndex,
|
index = stepIndex,
|
||||||
street = street,
|
street = street,
|
||||||
@@ -95,7 +106,8 @@ class TomTomRoute {
|
|||||||
steps.add(step)
|
steps.add(step)
|
||||||
stepIndex += 1
|
stepIndex += 1
|
||||||
}
|
}
|
||||||
legs.add(Leg(steps, allIntersections))
|
}
|
||||||
|
legs.add(Leg(steps))
|
||||||
val routeGeoJson = createLineStringCollection(waypoints)
|
val routeGeoJson = createLineStringCollection(waypoints)
|
||||||
val centerLocation = createCenterLocation(createLineStringCollection(waypoints))
|
val centerLocation = createCenterLocation(createLineStringCollection(waypoints))
|
||||||
val newRoute = com.kouros.navigation.data.route.Routes(
|
val newRoute = com.kouros.navigation.data.route.Routes(
|
||||||
@@ -184,8 +196,7 @@ class TomTomRoute {
|
|||||||
}
|
}
|
||||||
|
|
||||||
"TAKE_EXIT" -> {
|
"TAKE_EXIT" -> {
|
||||||
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SHARP_RIGHT
|
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newType
|
return newType
|
||||||
@@ -195,8 +206,7 @@ class TomTomRoute {
|
|||||||
private fun exitNumber(
|
private fun exitNumber(
|
||||||
instruction: Instruction
|
instruction: Instruction
|
||||||
): Int {
|
): Int {
|
||||||
return if (instruction.exitNumber == null
|
return if (instruction.exitNumber.isNullOrEmpty()
|
||||||
|| instruction.exitNumber.isEmpty()
|
|
||||||
) {
|
) {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -65,12 +65,15 @@ class IconMapper() {
|
|||||||
|
|
||||||
currentTurnIcon = R.drawable.ic_roundabout_ccw
|
currentTurnIcon = R.drawable.ic_roundabout_ccw
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_U_TURN_LEFT -> {
|
Maneuver.TYPE_U_TURN_LEFT -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_u_turn_left
|
currentTurnIcon = R.drawable.ic_turn_u_turn_left
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_U_TURN_RIGHT -> {
|
Maneuver.TYPE_U_TURN_RIGHT -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_u_turn_right
|
currentTurnIcon = R.drawable.ic_turn_u_turn_right
|
||||||
}
|
}
|
||||||
|
|
||||||
Maneuver.TYPE_MERGE_LEFT -> {
|
Maneuver.TYPE_MERGE_LEFT -> {
|
||||||
currentTurnIcon = R.drawable.ic_turn_merge_symmetrical
|
currentTurnIcon = R.drawable.ic_turn_merge_symmetrical
|
||||||
}
|
}
|
||||||
@@ -136,10 +139,12 @@ class IconMapper() {
|
|||||||
"right_slight", "slight_right" -> {
|
"right_slight", "slight_right" -> {
|
||||||
when (stepData.currentManeuverType) {
|
when (stepData.currentManeuverType) {
|
||||||
Maneuver.TYPE_TURN_SLIGHT_RIGHT -> LaneDirection.SHAPE_NORMAL_RIGHT
|
Maneuver.TYPE_TURN_SLIGHT_RIGHT -> LaneDirection.SHAPE_NORMAL_RIGHT
|
||||||
|
Maneuver.TYPE_KEEP_RIGHT -> LaneDirection.SHAPE_SLIGHT_RIGHT
|
||||||
else
|
else
|
||||||
-> LaneDirection.SHAPE_UNKNOWN
|
-> LaneDirection.SHAPE_UNKNOWN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
LaneDirection.SHAPE_UNKNOWN
|
LaneDirection.SHAPE_UNKNOWN
|
||||||
}
|
}
|
||||||
@@ -151,8 +156,7 @@ class IconMapper() {
|
|||||||
val bitmaps = mutableListOf<Bitmap>()
|
val bitmaps = mutableListOf<Bitmap>()
|
||||||
stepData.lane.forEach { lane ->
|
stepData.lane.forEach { lane ->
|
||||||
if (lane.indications.isNotEmpty()) {
|
if (lane.indications.isNotEmpty()) {
|
||||||
Collections.sort<String>(lane.indications)
|
val resource = laneToResource(lane.indications.sorted(), stepData)
|
||||||
val resource = laneToResource(lane.indications, stepData)
|
|
||||||
if (resource.isNotEmpty()) {
|
if (resource.isNotEmpty()) {
|
||||||
val id = resourceId(resource)
|
val id = resourceId(resource)
|
||||||
val bitMap = BitmapFactory.decodeResource(context.resources, id)
|
val bitMap = BitmapFactory.decodeResource(context.resources, id)
|
||||||
@@ -222,11 +226,21 @@ class IconMapper() {
|
|||||||
|
|
||||||
"right" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT) "${direction}_o" else "${direction}_x"
|
"right" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT) "${direction}_o" else "${direction}_x"
|
||||||
"left" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_LEFT) "${direction}_o" else "${direction}_x"
|
"left" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_LEFT) "${direction}_o" else "${direction}_x"
|
||||||
"straight" -> if (stepData.currentManeuverType == Maneuver.TYPE_STRAIGHT) "${direction}_o" else "${direction}_x"
|
"straight" -> if (stepData.currentManeuverType == Maneuver.TYPE_STRAIGHT
|
||||||
|
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_LEFT
|
||||||
|
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_RIGHT
|
||||||
|
) "${direction}_o" else "${direction}_x"
|
||||||
|
|
||||||
"right_slight", "slight_right" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_SLIGHT_RIGHT
|
"right_slight", "slight_right" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_SLIGHT_RIGHT
|
||||||
|| stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT) "slight_right_o" else "slight_right_x"
|
|| stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT
|
||||||
|
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_RIGHT
|
||||||
|
) "slight_right_o" else "slight_right_x"
|
||||||
|
|
||||||
"left_slight", "slight_left" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_SLIGHT_LEFT
|
"left_slight", "slight_left" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_SLIGHT_LEFT
|
||||||
|| stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_LEFT) "slight_left_o" else "slight_left_x"
|
|| stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_LEFT
|
||||||
|
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_LEFT
|
||||||
|
) "slight_left_o" else "slight_left_x"
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -550,14 +550,15 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
|||||||
val rp = settingsRepository.recentPlacesFlow.first()
|
val rp = settingsRepository.recentPlacesFlow.first()
|
||||||
val places = mutableListOf<Place>()
|
val places = mutableListOf<Place>()
|
||||||
if (rp.isNotEmpty()) {
|
if (rp.isNotEmpty()) {
|
||||||
val recentPlaces =
|
val rPlaces =
|
||||||
gson.fromJson(rp, Places::class.java).places.sortedBy { it.lastDate }
|
gson.fromJson(rp, Places::class.java).places.sortedBy { it.lastDate }
|
||||||
for (curPlace in recentPlaces) {
|
for (curPlace in rPlaces) {
|
||||||
if (curPlace.name != place.name || curPlace.category != place.category) {
|
if (curPlace.name != place.name || curPlace.category != place.category) {
|
||||||
places.add(curPlace)
|
places.add(curPlace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
settingsRepository.setRecentPlaces(gson.toJson(Places(places)))
|
settingsRepository.setRecentPlaces(gson.toJson(Places(places)))
|
||||||
|
recentPlaces.value = places
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class RouteCalculator(var routeModel: RouteModel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nearestDistance < NEAREST_LOCATION_DISTANCE) {
|
if (nearestDistance < NEAREST_LOCATION_DISTANCE) {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.kouros.navigation.data.StepData
|
|||||||
import com.kouros.navigation.data.route.Lane
|
import com.kouros.navigation.data.route.Lane
|
||||||
import com.kouros.navigation.data.route.Leg
|
import com.kouros.navigation.data.route.Leg
|
||||||
import com.kouros.navigation.data.route.Routes
|
import com.kouros.navigation.data.route.Routes
|
||||||
|
import com.kouros.navigation.data.route.Step
|
||||||
import com.kouros.navigation.utils.location
|
import com.kouros.navigation.utils.location
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
@@ -29,6 +30,9 @@ open class RouteModel {
|
|||||||
val curLeg: Leg
|
val curLeg: Leg
|
||||||
get() = navState.route.routes[navState.currentRouteIndex].legs.first()
|
get() = navState.route.routes[navState.currentRouteIndex].legs.first()
|
||||||
|
|
||||||
|
val currentStep: Step
|
||||||
|
get() = navState.route.nextStep(0)
|
||||||
|
|
||||||
fun startNavigation(routeString: String) {
|
fun startNavigation(routeString: String) {
|
||||||
navState = navState.copy(
|
navState = navState.copy(
|
||||||
route = Route.Builder()
|
route = Route.Builder()
|
||||||
@@ -69,39 +73,8 @@ open class RouteModel {
|
|||||||
navState = navState.copy(lastLocation = navState.currentLocation)
|
navState = navState.copy(lastLocation = navState.currentLocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun currentStep(): StepData {
|
|
||||||
val distanceToNextStep = routeCalculator.leftStepDistance()
|
|
||||||
// Determine the maneuver type and corresponding icon
|
|
||||||
val currentStep = navState.route.nextStep(0)
|
|
||||||
var streetName = currentStep.maneuver.street
|
|
||||||
var curManeuverType = currentStep.maneuver.type
|
|
||||||
if (navState.nextStep) {
|
|
||||||
if (distanceToNextStep > NEXT_STEP_THRESHOLD) {
|
|
||||||
streetName = currentStep.street
|
|
||||||
curManeuverType = Maneuver.TYPE_STRAIGHT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val exitNumber = currentStep.maneuver.exit
|
|
||||||
val maneuverIcon = navState.iconMapper.maneuverIcon(curManeuverType)
|
|
||||||
navState = navState.copy(maneuverType = curManeuverType)
|
|
||||||
// Construct and return the final StepData object
|
|
||||||
return StepData(
|
|
||||||
instruction = streetName,
|
|
||||||
street = currentStep.street,
|
|
||||||
leftStepDistance = distanceToNextStep,
|
|
||||||
currentManeuverType = navState.maneuverType,
|
|
||||||
icon = maneuverIcon,
|
|
||||||
arrivalTime = routeCalculator.arrivalTime(),
|
|
||||||
leftDistance = routeCalculator.travelLeftDistance(),
|
|
||||||
lane = currentLanes(),
|
|
||||||
exitNumber = exitNumber,
|
|
||||||
message = currentStep.maneuver.message
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun nextStep(): StepData {
|
fun nextStep(): StepData {
|
||||||
val distanceToNextStep = routeCalculator.leftStepDistance()
|
val distanceToNextStep = routeCalculator.leftStepDistance()
|
||||||
val currentStep = navState.route.nextStep(0)
|
|
||||||
val nextStep = navState.route.nextStep(1)
|
val nextStep = navState.route.nextStep(1)
|
||||||
var streetName = nextStep.street
|
var streetName = nextStep.street
|
||||||
var maneuverType = currentStep.maneuver.type
|
var maneuverType = currentStep.maneuver.type
|
||||||
@@ -128,16 +101,13 @@ open class RouteModel {
|
|||||||
private fun currentLanes(): List<Lane> {
|
private fun currentLanes(): List<Lane> {
|
||||||
var lanes = emptyList<Lane>()
|
var lanes = emptyList<Lane>()
|
||||||
if (navState.route.legs().isNotEmpty()) {
|
if (navState.route.legs().isNotEmpty()) {
|
||||||
navState.route.legs().first().intersection.forEach {
|
currentStep.intersection.forEach {
|
||||||
if (it.lane.isNotEmpty()) {
|
if (it.lane.isNotEmpty()) {
|
||||||
val distance =
|
val distance =
|
||||||
navState.lastLocation.distanceTo(location(it.location[0], it.location[1]))
|
navState.lastLocation.distanceTo(location(it.location[0], it.location[1]))
|
||||||
val sectionBearing =
|
if (distance < NEXT_STEP_THRESHOLD) {
|
||||||
navState.lastLocation.bearingTo(location(it.location[0], it.location[1]))
|
|
||||||
val bearingDeviation =
|
|
||||||
(navState.routeBearing.absoluteValue - sectionBearing.absoluteValue).absoluteValue
|
|
||||||
if (distance < NEXT_STEP_THRESHOLD && bearingDeviation < 10) {
|
|
||||||
lanes = it.lane
|
lanes = it.lane
|
||||||
|
return@forEach
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,6 +115,36 @@ open class RouteModel {
|
|||||||
return lanes
|
return lanes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun currentStep(): StepData {
|
||||||
|
val distanceToNextStep = routeCalculator.leftStepDistance()
|
||||||
|
// Determine the maneuver type and corresponding icon
|
||||||
|
var streetName = currentStep.maneuver.street
|
||||||
|
var curManeuverType = currentStep.maneuver.type
|
||||||
|
if (navState.nextStep) {
|
||||||
|
if (distanceToNextStep > NEXT_STEP_THRESHOLD) {
|
||||||
|
streetName = currentStep.street
|
||||||
|
curManeuverType = Maneuver.TYPE_STRAIGHT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val exitNumber = currentStep.maneuver.exit
|
||||||
|
val maneuverIcon = navState.iconMapper.maneuverIcon(curManeuverType)
|
||||||
|
navState = navState.copy(maneuverType = curManeuverType)
|
||||||
|
val currentLanes = currentLanes()
|
||||||
|
// Construct and return the final StepData object
|
||||||
|
return StepData(
|
||||||
|
instruction = streetName,
|
||||||
|
street = currentStep.street,
|
||||||
|
leftStepDistance = distanceToNextStep,
|
||||||
|
currentManeuverType = navState.maneuverType,
|
||||||
|
icon = maneuverIcon,
|
||||||
|
arrivalTime = routeCalculator.arrivalTime(),
|
||||||
|
leftDistance = routeCalculator.travelLeftDistance(),
|
||||||
|
lane = currentLanes,
|
||||||
|
exitNumber = exitNumber,
|
||||||
|
message = currentStep.maneuver.message
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun isNavigating(): Boolean {
|
fun isNavigating(): Boolean {
|
||||||
return navState.navigating
|
return navState.navigating
|
||||||
}
|
}
|
||||||
|
|||||||
26
common/data/src/main/res/drawable/baseline_add_road_24.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<!--
|
||||||
|
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 android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
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="M20,18l0,-3l-2,0l0,3l-3,0l0,2l3,0l0,3l2,0l0,-3l3,0l0,-2z"/>
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M18,4h2v9h-2z"/>
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M4,4h2v16h-2z"/>
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M11,4h2v4h-2z"/>
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M11,10h2v4h-2z"/>
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M11,16h2v4h-2z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<!--
|
||||||
|
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 android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
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="M20,21c-1.39,0 -2.78,-0.47 -4,-1.32c-2.44,1.71 -5.56,1.71 -8,0C6.78,20.53 5.39,21 4,21H2v2h2c1.38,0 2.74,-0.35 4,-0.99c2.52,1.29 5.48,1.29 8,0c1.26,0.65 2.62,0.99 4,0.99h2v-2H20zM3.95,19H4c1.6,0 3.02,-0.88 4,-2c0.98,1.12 2.4,2 4,2s3.02,-0.88 4,-2c0.98,1.12 2.4,2 4,2h0.05l1.9,-6.68c0.11,-0.37 0.04,-1.06 -0.66,-1.28L20,10.62V6c0,-1.1 -0.9,-2 -2,-2h-3V1H9v3H6C4.9,4 4,4.9 4,6v4.62l-1.29,0.42c-0.63,0.19 -0.81,0.84 -0.66,1.28L3.95,19zM6,6h12v3.97L12,8L6,9.97V6z"/>
|
||||||
|
</vector>
|
||||||
22
common/data/src/main/res/drawable/baseline_toll_24.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<!--
|
||||||
|
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 android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
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="M15,4c-4.42,0 -8,3.58 -8,8s3.58,8 8,8 8,-3.58 8,-8 -3.58,-8 -8,-8zM15,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6z"/>
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M3,12c0,-2.61 1.67,-4.83 4,-5.65V4.26C3.55,5.15 1,8.27 1,12s2.55,6.85 6,7.74v-2.09c-2.33,-0.82 -4,-3.04 -4,-5.65z"/>
|
||||||
|
</vector>
|
||||||
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.3 KiB |
@@ -2,14 +2,14 @@
|
|||||||
agp = "9.1.0"
|
agp = "9.1.0"
|
||||||
androidGpxParser = "2.3.1"
|
androidGpxParser = "2.3.1"
|
||||||
androidSdkTurf = "6.0.1"
|
androidSdkTurf = "6.0.1"
|
||||||
datastore = "1.2.0"
|
datastore = "1.2.1"
|
||||||
gradle = "9.1.0"
|
gradle = "9.1.0"
|
||||||
koinAndroid = "4.1.1"
|
koinAndroid = "4.1.1"
|
||||||
koinAndroidxCompose = "4.1.1"
|
koinAndroidxCompose = "4.1.1"
|
||||||
koinComposeViewmodel = "4.1.1"
|
koinComposeViewmodel = "4.1.1"
|
||||||
koinCore = "4.1.1"
|
koinCore = "4.1.1"
|
||||||
kotlin = "2.3.10"
|
kotlin = "2.3.10"
|
||||||
coreKtx = "1.17.0"
|
coreKtx = "1.18.0"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.3.0"
|
junitVersion = "1.3.0"
|
||||||
espressoCore = "3.7.0"
|
espressoCore = "3.7.0"
|
||||||
@@ -21,35 +21,35 @@ material = "1.13.0"
|
|||||||
carApp = "1.7.0"
|
carApp = "1.7.0"
|
||||||
androidx-car = "1.7.0"
|
androidx-car = "1.7.0"
|
||||||
materialIconsExtended = "1.7.8"
|
materialIconsExtended = "1.7.8"
|
||||||
mockitoCore = "5.22.0"
|
mockitoCore = "5.23.0"
|
||||||
mockitoKotlin = "6.2.3"
|
mockitoKotlin = "6.2.3"
|
||||||
rules = "1.7.0"
|
rules = "1.7.0"
|
||||||
runner = "1.7.0"
|
runner = "1.7.0"
|
||||||
material3 = "1.4.0"
|
material3 = "1.4.0"
|
||||||
runtimeLivedata = "1.10.4"
|
runtimeLivedata = "1.10.5"
|
||||||
foundation = "1.10.4"
|
foundation = "1.10.5"
|
||||||
maplibre-compose = "0.12.1"
|
maplibre-compose = "0.12.1"
|
||||||
playServicesLocation = "21.3.0"
|
playServicesLocation = "21.3.0"
|
||||||
runtime = "1.10.4"
|
runtime = "1.10.5"
|
||||||
accompanist = "0.37.3"
|
accompanist = "0.37.3"
|
||||||
uiVersion = "1.10.4"
|
uiVersion = "1.10.5"
|
||||||
uiText = "1.10.4"
|
uiText = "1.10.5"
|
||||||
navigationCompose = "2.9.7"
|
navigationCompose = "2.9.7"
|
||||||
uiToolingPreview = "1.10.4"
|
uiToolingPreview = "1.10.5"
|
||||||
uiTooling = "1.10.4"
|
uiTooling = "1.10.5"
|
||||||
material3WindowSizeClass = "1.4.0"
|
material3WindowSizeClass = "1.4.0"
|
||||||
uiGraphics = "1.10.4"
|
uiGraphics = "1.10.5"
|
||||||
window = "1.5.1"
|
window = "1.5.1"
|
||||||
foundationLayout = "1.10.4"
|
foundationLayout = "1.10.5"
|
||||||
datastorePreferences = "1.2.0"
|
datastorePreferences = "1.2.1"
|
||||||
datastoreCore = "1.2.0"
|
datastoreCore = "1.2.1"
|
||||||
monitor = "1.8.0"
|
monitor = "1.8.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
android-gpx-parser = { module = "com.github.ticofab:android-gpx-parser", version.ref = "androidGpxParser" }
|
android-gpx-parser = { module = "com.github.ticofab:android-gpx-parser", version.ref = "androidGpxParser" }
|
||||||
android-sdk-turf = { module = "org.maplibre.gl:android-sdk-turf", version.ref = "androidSdkTurf" }
|
android-sdk-turf = { module = "org.maplibre.gl:android-sdk-turf", version.ref = "androidSdkTurf" }
|
||||||
androidx-app-projected = { module = "androidx.car.app:app-projected" }
|
androidx-app-projected = { module = "androidx.car.app:app-projected" }
|
||||||
androidx-compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "materialIconsExtended" }
|
#androidx-compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "materialIconsExtended" }
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" }
|
androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" }
|
||||||
androidx-rules = { module = "androidx.test:rules", version.ref = "rules" }
|
androidx-rules = { module = "androidx.test:rules", version.ref = "rules" }
|
||||||
|
|||||||