TomTom Routing
This commit is contained in:
@@ -14,8 +14,8 @@ android {
|
||||
applicationId = "com.kouros.navigation"
|
||||
minSdk = 33
|
||||
targetSdk = 36
|
||||
versionCode = 32
|
||||
versionName = "0.1.3.32"
|
||||
versionCode = 36
|
||||
versionName = "0.2.0.36"
|
||||
base.archivesName = "navi-$versionName"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
@@ -95,6 +95,12 @@ dependencies {
|
||||
implementation(libs.androidx.window)
|
||||
implementation(libs.androidx.compose.foundation.layout)
|
||||
implementation("com.github.ticofab:android-gpx-parser:2.3.1")
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation("com.github.alorma.compose-settings:ui-tiles:2.25.0")
|
||||
implementation("com.github.alorma.compose-settings:ui-tiles-extended:2.25.0")
|
||||
implementation("com.github.alorma.compose-settings:ui-tiles-expressive:2.25.0")
|
||||
implementation(libs.androidx.foundation.layout)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
|
||||
@@ -48,8 +48,8 @@ class MockLocation (private var locationManager: LocationManager) {
|
||||
this.latitude = latitude
|
||||
this.longitude = longitude
|
||||
this.altitude = 0.0
|
||||
this.accuracy = 1.0f
|
||||
this.speed = 10f
|
||||
this.accuracy = 0f
|
||||
this.speed = 0f
|
||||
this.time = System.currentTimeMillis()
|
||||
this.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
|
||||
|
||||
@@ -71,8 +71,8 @@ class MockLocation (private var locationManager: LocationManager) {
|
||||
this.latitude = latitude
|
||||
this.longitude = longitude
|
||||
this.altitude = 0.0
|
||||
this.accuracy = 1.0f
|
||||
this.speed = 10f
|
||||
this.accuracy = 0f
|
||||
this.speed = 0f
|
||||
this.time = System.currentTimeMillis()
|
||||
this.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
|
||||
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
package com.kouros.navigation.ui
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CenterAlignedTopAppBar
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.alorma.compose.settings.ui.SettingsCheckbox
|
||||
import com.alorma.compose.settings.ui.SettingsGroup
|
||||
import com.alorma.compose.settings.ui.SettingsRadioButton
|
||||
import com.alorma.compose.settings.ui.base.internal.LocalSettingsTileColors
|
||||
import com.alorma.compose.settings.ui.base.internal.SettingsTileDefaults
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.data.Constants.DARK_MODE_SETTINGS
|
||||
import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING
|
||||
import com.kouros.navigation.utils.NavigationUtils
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun DisplayScreenSettings(context: Context, navigateBack: () -> Unit) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
CenterAlignedTopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
stringResource(id = R.string.display_settings),
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = navigateBack) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.arrow_back_24px),
|
||||
contentDescription = stringResource(id = R.string.accept_action_title),
|
||||
modifier = Modifier.size(48.dp, 48.dp),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
) { padding ->
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.consumeWindowInsets(padding)
|
||||
.verticalScroll(scrollState)
|
||||
.padding(top = padding.calculateTopPadding()),
|
||||
) {
|
||||
DisplaySettings(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun DisplaySettings(context: Context) {
|
||||
Section(title = "Anzeige") {
|
||||
val state = remember {
|
||||
mutableStateOf(
|
||||
NavigationUtils.getBooleanKeyValue(
|
||||
context,
|
||||
SHOW_THREED_BUILDING
|
||||
)
|
||||
)
|
||||
}
|
||||
SettingsCheckbox(
|
||||
state = state.value,
|
||||
title = { Text(text = stringResource(R.string.threed_building)) },
|
||||
onCheckedChange = {
|
||||
state.value = it
|
||||
NavigationUtils.setBooleanKeyValue(context, it, SHOW_THREED_BUILDING)
|
||||
},
|
||||
)
|
||||
}
|
||||
Section(title = "Dunkles Design") {
|
||||
val state = remember {
|
||||
mutableIntStateOf(
|
||||
NavigationUtils.getIntKeyValue(
|
||||
context,
|
||||
DARK_MODE_SETTINGS
|
||||
)
|
||||
)
|
||||
}
|
||||
DarkModeData(context).darkDesign.forEach { sampleItem ->
|
||||
SettingsRadioButton(
|
||||
state = state.intValue == sampleItem.key,
|
||||
title = { Text(text = sampleItem.title) },
|
||||
onClick = {
|
||||
state.intValue = sampleItem.key
|
||||
NavigationUtils.setIntKeyValue(context, state.intValue, DARK_MODE_SETTINGS)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun Section(
|
||||
title: String,
|
||||
enabled: Boolean = true,
|
||||
verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(4.dp),
|
||||
content: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
SettingsGroup(
|
||||
contentPadding = PaddingValues(0.dp),
|
||||
verticalArrangement = verticalArrangement,
|
||||
enabled = enabled,
|
||||
title = { Text(text = title) },
|
||||
) {
|
||||
Card(
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = (LocalSettingsTileColors.current
|
||||
?: SettingsTileDefaults.colors()).containerColor
|
||||
),
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
internal class DarkModeData(context: Context) {
|
||||
val darkDesign =
|
||||
listOf(
|
||||
Item(
|
||||
key = 0,
|
||||
title = context.getString(R.string.off_action_title),
|
||||
),
|
||||
Item(
|
||||
key = 1,
|
||||
title = context.getString(R.string.on_action_title),
|
||||
),
|
||||
Item(
|
||||
key = 2,
|
||||
title = context.getString(R.string.use_telephon_settings),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
internal data class Item(
|
||||
val key: Int,
|
||||
val title: String,
|
||||
)
|
||||
@@ -15,9 +15,13 @@ import androidx.activity.enableEdgeToEdge
|
||||
import androidx.annotation.RequiresPermission
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.BottomSheetScaffold
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
@@ -33,17 +37,23 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
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.compose.ui.unit.sp
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.google.android.gms.location.FusedLocationProviderClient
|
||||
import com.google.android.gms.location.LocationServices
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.MainApplication.Companion.navigationViewModel
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE
|
||||
import com.kouros.navigation.data.Constants.homeHohenwaldeck
|
||||
import com.kouros.navigation.data.Constants.homeVogelhart
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.model.BaseStyleModel
|
||||
@@ -78,6 +88,7 @@ class MainActivity : ComponentActivity() {
|
||||
val routeModel = RouteModel()
|
||||
var tilt = 50.0
|
||||
val useMock = false
|
||||
val type = 1 // simulate 2 test 3 gpx
|
||||
|
||||
var currentIndex = 0
|
||||
val stepData: MutableLiveData<StepData> by lazy {
|
||||
@@ -92,9 +103,13 @@ class MainActivity : ComponentActivity() {
|
||||
routeModel.startNavigation(newRoute, applicationContext)
|
||||
routeData.value = routeModel.curRoute.routeGeoJson
|
||||
if (useMock) {
|
||||
simulate()
|
||||
//test()
|
||||
///gpx(applicationContext)
|
||||
when (type) {
|
||||
1 -> simulate()
|
||||
2 -> test()
|
||||
3 -> gpx(
|
||||
context = applicationContext
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,9 +129,6 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
lateinit var baseStyle: BaseStyle.Json
|
||||
|
||||
init {
|
||||
|
||||
}
|
||||
|
||||
@RequiresPermission(allOf = [Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION])
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -156,24 +168,28 @@ class MainActivity : ComponentActivity() {
|
||||
permissions = permissions,
|
||||
requiredPermissions = listOf(permissions.first()),
|
||||
onGranted = {
|
||||
Content()
|
||||
App()
|
||||
// auto navigate
|
||||
if (useMock) {
|
||||
navigationViewModel.loadRoute(
|
||||
applicationContext,
|
||||
homeVogelhart,
|
||||
homeHohenwaldeck,
|
||||
0F
|
||||
)
|
||||
// navigationViewModel.loadRoute(
|
||||
// applicationContext,
|
||||
// homeVogelhart,
|
||||
// homeHohenwaldeck,
|
||||
// 0F
|
||||
// )
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("AutoboxingStateCreation")
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Content() {
|
||||
fun StartScreen(
|
||||
navController: NavHostController
|
||||
|
||||
) {
|
||||
|
||||
val scaffoldState = rememberBottomSheetScaffoldState()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -226,6 +242,42 @@ class MainActivity : ComponentActivity() {
|
||||
baseStyle
|
||||
)
|
||||
}
|
||||
if (!routeModel.isNavigating()) {
|
||||
Settings(navController, modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun App() {
|
||||
val navController = rememberNavController()
|
||||
NavHost(navController = navController, startDestination = "startScreen") {
|
||||
composable("startScreen") { StartScreen(navController) }
|
||||
composable("settings") { SettingsScreen(navController) { navController.popBackStack() } }
|
||||
composable("display_settings") { DisplayScreenSettings(applicationContext) { navController.popBackStack() } }
|
||||
composable("nav_settings") { NavigationScreenSettings(applicationContext) { navController.popBackStack() } }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Settings(navController: NavController, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
) {
|
||||
FloatingActionButton(
|
||||
modifier = Modifier
|
||||
.padding(start = 10.dp, top = 40.dp),
|
||||
onClick = {
|
||||
navController.navigate("settings")
|
||||
},
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.menu_24px),
|
||||
contentDescription = stringResource(id = R.string.accept_action_title),
|
||||
modifier = Modifier.size(24.dp, 24.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,7 +317,7 @@ class MainActivity : ComponentActivity() {
|
||||
if (isNavigating()) {
|
||||
updateLocation(currentLocation, navigationViewModel)
|
||||
stepData.value = currentStep()
|
||||
if (route.currentStep + 1 <= curLeg.steps.size) {
|
||||
if (route.currentStepIndex + 1 <= curLeg.steps.size) {
|
||||
nextStepData.value = nextStep()
|
||||
}
|
||||
if (maneuverType in 39..42
|
||||
@@ -302,7 +354,7 @@ class MainActivity : ComponentActivity() {
|
||||
mock.setMockLocation(latitude, longitude)
|
||||
}
|
||||
routeData.value = ""
|
||||
stepData.value = StepData("", 0.0, 0, 0, 0, 0.0)
|
||||
stepData.value = StepData("", 0.0, 0, 0, 0, 0.0)
|
||||
}
|
||||
|
||||
fun simulateNavigation() {
|
||||
@@ -338,8 +390,8 @@ class MainActivity : ComponentActivity() {
|
||||
for ((index, waypoint) in routeModel.curRoute.waypoints.withIndex()) {
|
||||
if (routeModel.isNavigating()) {
|
||||
val deviation = 0.0
|
||||
if (index in 0..routeModel.curRoute.waypoints.size) {
|
||||
mock.setMockLocation(waypoint[1] + deviation, waypoint[0])
|
||||
if (index in 300..routeModel.curRoute.waypoints.size) {
|
||||
mock.setMockLocation(waypoint[1], waypoint[0])
|
||||
delay(500L) //
|
||||
}
|
||||
}
|
||||
@@ -349,13 +401,14 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
fun test() {
|
||||
for ((index, step) in routeModel.curLeg.steps.withIndex()) {
|
||||
if (index in 3..3) {
|
||||
//if (index in 3..3) {
|
||||
for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) {
|
||||
routeModel.updateLocation(
|
||||
location(waypoint[0], waypoint[1]),
|
||||
navigationViewModel
|
||||
)
|
||||
val step = routeModel.currentStep()
|
||||
println("Step: ${step}")
|
||||
if (step.leftStepDistance == 70.0) {
|
||||
println("")
|
||||
}
|
||||
@@ -363,7 +416,7 @@ class MainActivity : ComponentActivity() {
|
||||
//nextStepData.value = routeModel.nextStep()
|
||||
}
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,7 +430,7 @@ class MainActivity : ComponentActivity() {
|
||||
fun gpx(context: Context) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val parser = GPXParser()
|
||||
val input = context.resources.openRawResource(R.raw.hv)
|
||||
val input = context.resources.openRawResource(R.raw.vh)
|
||||
val parsedGpx: Gpx? = parser.parse(input) // consider using a background thread
|
||||
parsedGpx?.let {
|
||||
val tracks = parsedGpx.tracks
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
package com.kouros.navigation.ui
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.CenterAlignedTopAppBar
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.alorma.compose.settings.ui.SettingsCheckbox
|
||||
import com.alorma.compose.settings.ui.SettingsRadioButton
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Constants.DARK_MODE_SETTINGS
|
||||
import com.kouros.navigation.data.Constants.ROUTING_ENGINE
|
||||
import com.kouros.navigation.data.RouteEngine
|
||||
import com.kouros.navigation.utils.NavigationUtils
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun NavigationScreenSettings(context: Context, navigateBack: () -> Unit) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
CenterAlignedTopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
stringResource(id = R.string.navigation_settings),
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = navigateBack) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.arrow_back_24px),
|
||||
contentDescription = stringResource(id = R.string.accept_action_title),
|
||||
modifier = Modifier.size(48.dp, 48.dp),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
) { padding ->
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.consumeWindowInsets(padding)
|
||||
.verticalScroll(scrollState)
|
||||
.padding(top = padding.calculateTopPadding()),
|
||||
) {
|
||||
NavigationSettings(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NavigationSettings(context: Context) {
|
||||
Section(title = stringResource(id = R.string.options)) {
|
||||
val avoidMotorwayState = remember {
|
||||
mutableStateOf(
|
||||
NavigationUtils.getBooleanKeyValue(
|
||||
context,
|
||||
Constants.AVOID_MOTORWAY
|
||||
)
|
||||
)
|
||||
}
|
||||
SettingsCheckbox(
|
||||
state = avoidMotorwayState.value,
|
||||
title = { Text(text = stringResource(id = R.string.avoid_highways_row_title)) },
|
||||
onCheckedChange = {
|
||||
avoidMotorwayState.value = it
|
||||
NavigationUtils.setBooleanKeyValue(context, it, Constants.AVOID_MOTORWAY)
|
||||
},
|
||||
)
|
||||
|
||||
val avoidTollwayState = remember {
|
||||
mutableStateOf(
|
||||
NavigationUtils.getBooleanKeyValue(
|
||||
context,
|
||||
Constants.AVOID_TOLLWAY
|
||||
)
|
||||
)
|
||||
}
|
||||
SettingsCheckbox(
|
||||
state = avoidTollwayState.value,
|
||||
title = { Text(text = stringResource(id = R.string.avoid_tolls_row_title)) },
|
||||
onCheckedChange = {
|
||||
avoidTollwayState.value = it
|
||||
NavigationUtils.setBooleanKeyValue(context, it, Constants.AVOID_TOLLWAY)
|
||||
},
|
||||
)
|
||||
|
||||
val carLocationState = remember {
|
||||
mutableStateOf(
|
||||
NavigationUtils.getBooleanKeyValue(
|
||||
context,
|
||||
Constants.CAR_LOCATION
|
||||
)
|
||||
)
|
||||
}
|
||||
SettingsCheckbox(
|
||||
state = carLocationState.value,
|
||||
title = { Text(text = stringResource(id = R.string.use_car_location)) },
|
||||
onCheckedChange = {
|
||||
carLocationState.value = it
|
||||
NavigationUtils.setBooleanKeyValue(context, it, Constants.CAR_LOCATION)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Section(title = stringResource(id = R.string.routing_engine)) {
|
||||
val state = remember {
|
||||
mutableIntStateOf(
|
||||
NavigationUtils.getIntKeyValue(
|
||||
context,
|
||||
ROUTING_ENGINE
|
||||
)
|
||||
)
|
||||
}
|
||||
RoutingEngineData.engines.forEach { sampleItem ->
|
||||
SettingsRadioButton(
|
||||
state = state.intValue == sampleItem.key,
|
||||
title = { Text(text = sampleItem.title) },
|
||||
onClick = {
|
||||
state.intValue = sampleItem.key
|
||||
NavigationUtils.setIntKeyValue(context, state.intValue, ROUTING_ENGINE)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object RoutingEngineData {
|
||||
val engines =
|
||||
listOf(
|
||||
Item(
|
||||
key = 0,
|
||||
title = RouteEngine.VALHALLA.toString(),
|
||||
),
|
||||
Item(
|
||||
key = 1,
|
||||
title = RouteEngine.OSRM.toString(),
|
||||
),
|
||||
Item(
|
||||
key = 2,
|
||||
title = RouteEngine.TOMTOM.toString(),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD
|
||||
import com.kouros.navigation.data.StepData
|
||||
@@ -30,21 +31,19 @@ fun NavigationSheet(
|
||||
stopNavigation: () -> Unit,
|
||||
simulateNavigation: () -> Unit,
|
||||
) {
|
||||
val distance = step.leftDistance.round(1)
|
||||
val distance = (step.leftDistance / 1000).round(1)
|
||||
|
||||
step.lane.forEach {
|
||||
if (it.indications.isNotEmpty()) {
|
||||
routeModel.createLaneIcon(applicationContext, step)
|
||||
}
|
||||
if (step.lane.isNotEmpty()) {
|
||||
routeModel.addLanes( step)
|
||||
}
|
||||
|
||||
|
||||
Column {
|
||||
FlowRow(horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
Text(formatDateTime(step.arrivalTime), fontSize = 22.sp)
|
||||
Spacer(Modifier.size(30.dp))
|
||||
Text("$distance km", fontSize = 22.sp)
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
FlowRow(horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
if (routeModel.isNavigating()) {
|
||||
|
||||
86
app/src/main/java/com/kouros/navigation/ui/SettingsScreen.kt
Normal file
86
app/src/main/java/com/kouros/navigation/ui/SettingsScreen.kt
Normal file
@@ -0,0 +1,86 @@
|
||||
package com.kouros.navigation.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.CenterAlignedTopAppBar
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
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.navigation.NavHostController
|
||||
import com.alorma.compose.settings.ui.SettingsMenuLink
|
||||
import com.kouros.data.R
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun SettingsScreen(navController: NavHostController, navigateBack: () -> Unit) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
CenterAlignedTopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
stringResource(id = R.string.settings_action_title),
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = navigateBack) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.arrow_back_24px),
|
||||
contentDescription = stringResource(id = R.string.accept_action_title),
|
||||
modifier = Modifier.size(48.dp, 48.dp),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
) { padding ->
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.consumeWindowInsets(padding)
|
||||
.verticalScroll(scrollState)
|
||||
.padding(top = padding.calculateTopPadding()),
|
||||
) {
|
||||
SettingsMenuLink(
|
||||
title = { Text(text = stringResource(R.string.display_settings)) },
|
||||
modifier = Modifier,
|
||||
enabled = true,
|
||||
onClick = { navController.navigate("display_settings")},
|
||||
icon = {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_place_white_24dp),
|
||||
contentDescription = stringResource(id = R.string.display_settings),
|
||||
modifier = Modifier.size(48.dp, 48.dp),
|
||||
)
|
||||
}
|
||||
)
|
||||
SettingsMenuLink(
|
||||
title = { Text(text = stringResource(R.string.navigation_settings)) },
|
||||
modifier = Modifier,
|
||||
enabled = true,
|
||||
onClick = { navController.navigate("nav_settings")},
|
||||
icon = {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.navigation_24px),
|
||||
contentDescription = stringResource(id = R.string.navigation_settings),
|
||||
modifier = Modifier.size(48.dp, 48.dp),
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,75 @@ package com.kouros.navigation.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val Purple80 = Color(0xFFD0BCFF)
|
||||
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||
val Pink80 = Color(0xFFEFB8C8)
|
||||
//val Purple80 = Color(0xFFD0BCFF)
|
||||
//val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||
//val Pink80 = Color(0xFFEFB8C8)
|
||||
//
|
||||
//val Purple40 = Color(0xFF6650a4)
|
||||
//val PurpleGrey40 = Color(0xFF625b71)
|
||||
//val Pink40 = Color(0xFF7D5260)
|
||||
|
||||
val Purple40 = Color(0xFF6650a4)
|
||||
val PurpleGrey40 = Color(0xFF625b71)
|
||||
val Pink40 = Color(0xFF7D5260)
|
||||
val md_theme_light_primary = Color(0xFF825500)
|
||||
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
|
||||
val md_theme_light_primaryContainer = Color(0xFFFFDDB3)
|
||||
val md_theme_light_onPrimaryContainer = Color(0xFF291800)
|
||||
val md_theme_light_secondary = Color(0xFF6F5B40)
|
||||
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
|
||||
val md_theme_light_secondaryContainer = Color(0xFFFBDEBC)
|
||||
val md_theme_light_onSecondaryContainer = Color(0xFF271904)
|
||||
val md_theme_light_tertiary = Color(0xFF51643F)
|
||||
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
|
||||
val md_theme_light_tertiaryContainer = Color(0xFFD4EABB)
|
||||
val md_theme_light_onTertiaryContainer = Color(0xFF102004)
|
||||
val md_theme_light_error = Color(0xFFBA1A1A)
|
||||
val md_theme_light_errorContainer = Color(0xFFFFDAD6)
|
||||
val md_theme_light_onError = Color(0xFFFFFFFF)
|
||||
val md_theme_light_onErrorContainer = Color(0xFF410002)
|
||||
val md_theme_light_background = Color(0xFFFFFBFF)
|
||||
val md_theme_light_onBackground = Color(0xFF1F1B16)
|
||||
val md_theme_light_surface = Color(0xFFFFFBFF)
|
||||
val md_theme_light_onSurface = Color(0xFF1F1B16)
|
||||
val md_theme_light_surfaceVariant = Color(0xFFF0E0CF)
|
||||
val md_theme_light_onSurfaceVariant = Color(0xFF4F4539)
|
||||
val md_theme_light_outline = Color(0xFF817567)
|
||||
val md_theme_light_inverseOnSurface = Color(0xFFF9EFE7)
|
||||
val md_theme_light_inverseSurface = Color(0xFF34302A)
|
||||
val md_theme_light_inversePrimary = Color(0xFFFFB951)
|
||||
val md_theme_light_shadow = Color(0xFF000000)
|
||||
val md_theme_light_surfaceTint = Color(0xFF825500)
|
||||
val md_theme_light_outlineVariant = Color(0xFFD3C4B4)
|
||||
val md_theme_light_scrim = Color(0xFF000000)
|
||||
|
||||
val md_theme_dark_primary = Color(0xFFFFB951)
|
||||
val md_theme_dark_onPrimary = Color(0xFF452B00)
|
||||
val md_theme_dark_primaryContainer = Color(0xFF633F00)
|
||||
val md_theme_dark_onPrimaryContainer = Color(0xFFFFDDB3)
|
||||
val md_theme_dark_secondary = Color(0xFFDDC2A1)
|
||||
val md_theme_dark_onSecondary = Color(0xFF3E2D16)
|
||||
val md_theme_dark_secondaryContainer = Color(0xFF56442A)
|
||||
val md_theme_dark_onSecondaryContainer = Color(0xFFFBDEBC)
|
||||
val md_theme_dark_tertiary = Color(0xFFB8CEA1)
|
||||
val md_theme_dark_onTertiary = Color(0xFF243515)
|
||||
val md_theme_dark_tertiaryContainer = Color(0xFF3A4C2A)
|
||||
val md_theme_dark_onTertiaryContainer = Color(0xFFD4EABB)
|
||||
val md_theme_dark_error = Color(0xFFFFB4AB)
|
||||
val md_theme_dark_errorContainer = Color(0xFF93000A)
|
||||
val md_theme_dark_onError = Color(0xFF690005)
|
||||
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
|
||||
val md_theme_dark_background = Color(0xFF1F1B16)
|
||||
val md_theme_dark_onBackground = Color(0xFFEAE1D9)
|
||||
val md_theme_dark_surface = Color(0xFF1F1B16)
|
||||
val md_theme_dark_onSurface = Color(0xFFEAE1D9)
|
||||
val md_theme_dark_surfaceVariant = Color(0xFF4F4539)
|
||||
val md_theme_dark_onSurfaceVariant = Color(0xFFD3C4B4)
|
||||
val md_theme_dark_outline = Color(0xFF9C8F80)
|
||||
val md_theme_dark_inverseOnSurface = Color(0xFF1F1B16)
|
||||
val md_theme_dark_inverseSurface = Color(0xFFEAE1D9)
|
||||
val md_theme_dark_inversePrimary = Color(0xFF825500)
|
||||
val md_theme_dark_shadow = Color(0xFF000000)
|
||||
val md_theme_dark_surfaceTint = Color(0xFFFFB951)
|
||||
val md_theme_dark_outlineVariant = Color(0xFF4F4539)
|
||||
val md_theme_dark_scrim = Color(0xFF000000)
|
||||
|
||||
|
||||
val seed = Color(0xFF825500)
|
||||
|
||||
29
app/src/main/java/com/kouros/navigation/ui/theme/Shapes.kt
Normal file
29
app/src/main/java/com/kouros/navigation/ui/theme/Shapes.kt
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.kouros.navigation.ui.theme
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Shapes
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
val shapes = Shapes(
|
||||
extraSmall = RoundedCornerShape(4.dp),
|
||||
small = RoundedCornerShape(8.dp),
|
||||
medium = RoundedCornerShape(16.dp),
|
||||
large = RoundedCornerShape(24.dp),
|
||||
extraLarge = RoundedCornerShape(32.dp)
|
||||
)
|
||||
@@ -1,57 +1,111 @@
|
||||
package com.kouros.navigation.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.core.view.WindowCompat
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Purple80,
|
||||
secondary = PurpleGrey80,
|
||||
tertiary = Pink80
|
||||
private val LightColors = lightColorScheme(
|
||||
primary = md_theme_light_primary,
|
||||
onPrimary = md_theme_light_onPrimary,
|
||||
primaryContainer = md_theme_light_primaryContainer,
|
||||
onPrimaryContainer = md_theme_light_onPrimaryContainer,
|
||||
secondary = md_theme_light_secondary,
|
||||
onSecondary = md_theme_light_onSecondary,
|
||||
secondaryContainer = md_theme_light_secondaryContainer,
|
||||
onSecondaryContainer = md_theme_light_onSecondaryContainer,
|
||||
tertiary = md_theme_light_tertiary,
|
||||
onTertiary = md_theme_light_onTertiary,
|
||||
tertiaryContainer = md_theme_light_tertiaryContainer,
|
||||
onTertiaryContainer = md_theme_light_onTertiaryContainer,
|
||||
error = md_theme_light_error,
|
||||
errorContainer = md_theme_light_errorContainer,
|
||||
onError = md_theme_light_onError,
|
||||
onErrorContainer = md_theme_light_onErrorContainer,
|
||||
background = md_theme_light_background,
|
||||
onBackground = md_theme_light_onBackground,
|
||||
surface = md_theme_light_surface,
|
||||
onSurface = md_theme_light_onSurface,
|
||||
surfaceVariant = md_theme_light_surfaceVariant,
|
||||
onSurfaceVariant = md_theme_light_onSurfaceVariant,
|
||||
outline = md_theme_light_outline,
|
||||
inverseOnSurface = md_theme_light_inverseOnSurface,
|
||||
inverseSurface = md_theme_light_inverseSurface,
|
||||
inversePrimary = md_theme_light_inversePrimary,
|
||||
surfaceTint = md_theme_light_surfaceTint,
|
||||
outlineVariant = md_theme_light_outlineVariant,
|
||||
scrim = md_theme_light_scrim,
|
||||
)
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Purple40,
|
||||
secondary = PurpleGrey40,
|
||||
tertiary = Pink40
|
||||
|
||||
/* Other default colors to override
|
||||
background = Color(0xFFFFFBFE),
|
||||
surface = Color(0xFFFFFBFE),
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.White,
|
||||
onTertiary = Color.White,
|
||||
onBackground = Color(0xFF1C1B1F),
|
||||
onSurface = Color(0xFF1C1B1F),
|
||||
*/
|
||||
private val DarkColors = darkColorScheme(
|
||||
primary = md_theme_dark_primary,
|
||||
onPrimary = md_theme_dark_onPrimary,
|
||||
primaryContainer = md_theme_dark_primaryContainer,
|
||||
onPrimaryContainer = md_theme_dark_onPrimaryContainer,
|
||||
secondary = md_theme_dark_secondary,
|
||||
onSecondary = md_theme_dark_onSecondary,
|
||||
secondaryContainer = md_theme_dark_secondaryContainer,
|
||||
onSecondaryContainer = md_theme_dark_onSecondaryContainer,
|
||||
tertiary = md_theme_dark_tertiary,
|
||||
onTertiary = md_theme_dark_onTertiary,
|
||||
tertiaryContainer = md_theme_dark_tertiaryContainer,
|
||||
onTertiaryContainer = md_theme_dark_onTertiaryContainer,
|
||||
error = md_theme_dark_error,
|
||||
errorContainer = md_theme_dark_errorContainer,
|
||||
onError = md_theme_dark_onError,
|
||||
onErrorContainer = md_theme_dark_onErrorContainer,
|
||||
background = md_theme_dark_background,
|
||||
onBackground = md_theme_dark_onBackground,
|
||||
surface = md_theme_dark_surface,
|
||||
onSurface = md_theme_dark_onSurface,
|
||||
surfaceVariant = md_theme_dark_surfaceVariant,
|
||||
onSurfaceVariant = md_theme_dark_onSurfaceVariant,
|
||||
outline = md_theme_dark_outline,
|
||||
inverseOnSurface = md_theme_dark_inverseOnSurface,
|
||||
inverseSurface = md_theme_dark_inverseSurface,
|
||||
inversePrimary = md_theme_dark_inversePrimary,
|
||||
surfaceTint = md_theme_dark_surfaceTint,
|
||||
outlineVariant = md_theme_dark_outlineVariant,
|
||||
scrim = md_theme_dark_scrim,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun NavigationTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
// Dynamic color is available on Android 12+
|
||||
dynamicColor: Boolean = true,
|
||||
useDarkTheme: Boolean = isSystemInDarkTheme(),
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme = when {
|
||||
dynamicColor -> {
|
||||
val context = LocalContext.current
|
||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||
}
|
||||
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
val context = LocalContext.current
|
||||
val colors = run {
|
||||
if (useDarkTheme) dynamicDarkColorScheme(context)
|
||||
else dynamicLightColorScheme(context)
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
val view = LocalView.current
|
||||
if (!view.isInEditMode) {
|
||||
SideEffect {
|
||||
val window = (view.context as Activity).window
|
||||
window.statusBarColor = colors.primary.toArgb()
|
||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars =
|
||||
useDarkTheme
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = typography,
|
||||
content = content,
|
||||
shapes = shapes,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -7,28 +7,35 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
// Set of Material typography styles to start with
|
||||
val Typography = Typography(
|
||||
val typography = Typography(
|
||||
headlineSmall = TextStyle(
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 24.sp,
|
||||
lineHeight = 32.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
titleLarge = TextStyle(
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 18.sp,
|
||||
lineHeight = 32.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
/* Other default text styles to override
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
letterSpacing = 0.15.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
bodyMedium = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp,
|
||||
letterSpacing = 0.25.sp
|
||||
),
|
||||
labelMedium = TextStyle(
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
*/
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user