TomTom Routing

This commit is contained in:
Dimitris
2026-02-07 12:56:45 +01:00
parent eac5b56bcb
commit 0d51c6121d
50 changed files with 8923 additions and 5084 deletions

View File

@@ -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)

View File

@@ -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()

View File

@@ -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,
)

View File

@@ -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

View File

@@ -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(),
),
)
}

View File

@@ -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()) {

View 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),
)
}
)
}
}
}

View File

@@ -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)

View 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)
)

View File

@@ -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,
)
}
}

View File

@@ -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
)
*/
)
)