Launcher Icons, NotificationService

This commit is contained in:
Dimitris
2026-03-24 17:04:05 +01:00
parent bc8a53a5d8
commit 5098dad9d6
76 changed files with 930 additions and 478 deletions

View File

@@ -1,10 +1,14 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.util.Properties
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.compose)
}
val properties = Properties().apply {
load(File("signing.properties").reader())
}
android {
namespace = "com.kouros.navigation"
compileSdk = 36
@@ -13,8 +17,8 @@ android {
applicationId = "com.kouros.navigation"
minSdk = 33
targetSdk = 36
versionCode = 76
versionName = "0.2.0.76"
versionCode = 82
versionName = "0.2.0.82"
base.archivesName = "navi-$versionName"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -22,23 +26,22 @@ android {
signingConfigs {
getByName("debug") {
keyAlias = "release"
keyPassword = "zeta67#gAe3aN3"
storeFile = file("/home/kouros/work/keystore/keystoreRelease")
storePassword = "zeta67#gAe3aN3"
keyPassword = properties.getProperty("keyPassword")
storeFile = file(properties.getProperty("storeFile"))
storePassword = properties.getProperty("storePassword")
}
create("release") {
keyAlias = "release"
keyPassword = "zeta67#gAe3aN3"
storeFile = file("/home/kouros/work/keystore/keystoreRelease")
storePassword = "zeta67#gAe3aN3"
keyPassword = properties.getProperty("keyPassword")
storeFile = file(properties.getProperty("storeFile"))
storePassword = properties.getProperty("storePassword")
}
}
buildTypes {
release {
// Enables code-related app optimization.
signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = false
// Enables resource shrinking.
isShrinkResources = false
proguardFiles(
@@ -48,15 +51,20 @@ android {
}
}
// Specifies one flavor dimension.
flavorDimensions += "version"
flavorDimensions += "store"
productFlavors {
create("play") {
dimension = "store"
applicationIdSuffix = ".play"
versionNameSuffix = "-play"
}
create("demo") {
dimension = "version"
dimension = "store"
applicationIdSuffix = ".demo"
versionNameSuffix = "-demo"
}
create("full") {
dimension = "version"
dimension = "store"
applicationIdSuffix = ".full"
versionNameSuffix = "-full"
}
@@ -66,11 +74,20 @@ android {
targetCompatibility = JavaVersion.VERSION_21
}
buildFeatures {
compose = true
packaging {
resources {
excludes +=
setOf(
"/META-INF/{AL2.0,LGPL2.1}",
"/META-INF/*.version",
)
}
}
buildFeatures {
compose = true
buildConfig = true
}
}
dependencies {
@@ -95,7 +112,6 @@ dependencies {
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.window)
implementation(libs.androidx.compose.foundation.layout)
implementation(libs.android.gpx.parser)
implementation(libs.androidx.navigation.compose)
implementation(libs.kotlinx.serialization.json)
implementation(libs.androidx.compose.foundation.layout)
@@ -107,4 +123,3 @@ dependencies {
debugImplementation(libs.androidx.compose.ui.tooling)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -1,20 +1,12 @@
package com.kouros.navigation.model
import android.content.Context
import androidx.lifecycle.lifecycleScope
import com.kouros.data.R
import com.kouros.navigation.MainApplication.Companion.navigationViewModel
import com.kouros.navigation.utils.location
import io.ticofab.androidgpxparser.parser.GPXParser
import io.ticofab.androidgpxparser.parser.domain.Gpx
import io.ticofab.androidgpxparser.parser.domain.TrackSegment
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.joda.time.DateTime
import kotlin.collections.forEach
var simulationJob: Job? = null
fun simulate(routeModel: RouteModel, mock: MockLocation) {
@@ -91,43 +83,6 @@ fun testSingleUpdate(
Thread.sleep(1_000)
}
fun gpx(context: Context, mock: MockLocation) {
CoroutineScope(Dispatchers.IO).launch {
var lastLocation = location(0.0, 0.0)
val parser = GPXParser()
val resourceId: Int = context.resources
.getIdentifier("vh", "raw", context.packageName)
val input = context.resources.openRawResource(resourceId)
val parsedGpx: Gpx? = parser.parse(input) // consider using a background thread
parsedGpx?.let {
val tracks = parsedGpx.tracks
tracks.forEach { tr ->
val segments: MutableList<TrackSegment?>? = tr.trackSegments
segments!!.forEach { seg ->
var lastTime = DateTime.now()
seg!!.trackPoints.forEach { p ->
val curLocation = location(p.longitude, p.latitude)
val ext = p.extensions
val speed: Double?
if (ext != null) {
speed = ext.speed
mock.curSpeed = speed.toFloat()
}
val duration = p.time.millis - lastTime.millis
val bearing = lastLocation.bearingTo(curLocation)
mock.setMockLocation(p.latitude, p.longitude, bearing)
if (duration > 0) {
delay(duration / 5)
}
lastTime = p.time
lastLocation = curLocation
}
}
}
}
}
}
enum class SimulationType {
SIMULATE, TEST, GPX, TEST_SINGLE
}

View File

@@ -50,7 +50,6 @@ import com.kouros.navigation.model.BaseStyleModel
import com.kouros.navigation.model.MockLocation
import com.kouros.navigation.model.RouteModel
import com.kouros.navigation.model.SimulationType
import com.kouros.navigation.model.gpx
import com.kouros.navigation.model.simulate
import com.kouros.navigation.model.simulationJob
import com.kouros.navigation.model.test
@@ -112,11 +111,10 @@ class MainActivity : ComponentActivity() {
when (type) {
SimulationType.SIMULATE -> simulate(routeModel, mock)
SimulationType.TEST -> test(applicationContext, routeModel)
SimulationType.GPX -> gpx(
context = applicationContext, mock
)
SimulationType.TEST_SINGLE -> testSingle(applicationContext, routeModel, mock)
else -> {}
}
}
}

View File

@@ -13,10 +13,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.unit.dp
import androidx.lifecycle.MutableLiveData
import androidx.window.layout.WindowMetricsCalculator
import com.kouros.navigation.car.ViewStyle
import com.kouros.navigation.car.map.MapLibre
import com.kouros.navigation.car.map.NavigationImage
import com.kouros.navigation.data.StepData
import com.kouros.navigation.data.ViewStyle
import com.kouros.navigation.ui.app.AppViewModel
import com.kouros.navigation.ui.app.appViewModel
import com.kouros.navigation.ui.navigation.NavigationInfo

View File

@@ -48,5 +48,11 @@ fun AppNavGraph(mainActivity: MainActivity) {
navController
) { navController.popBackStack() }
}
composable("car_settings") {
SettingsRoute(
"car_settings",
navController
) { navController.popBackStack() }
}
}
}

View File

@@ -0,0 +1,90 @@
package com.kouros.navigation.ui.settings
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
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.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
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.runtime.getValue
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.kouros.data.R
import com.kouros.navigation.model.SettingsViewModel
import com.kouros.navigation.ui.components.RadioButtonSingleSelection
import com.kouros.navigation.ui.components.SectionTitle
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CarScreen(viewModel: SettingsViewModel, navigateBack: () -> Unit) {
val engineType by viewModel.engineType.collectAsState()
Scaffold(
topBar = {
TopAppBar(
title = {
Text(
stringResource(id = R.string.car_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),
)
}
},
)
},
)
{ paddingValues ->
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize()
.padding(top = 10.dp)
.verticalScroll(scrollState)
) {
OutlinedCard(modifier = Modifier.fillMaxWidth()) {
Column(
modifier = Modifier.padding(10.dp),
) {
SectionTitle(stringResource(R.string.engine_type))
val radioOptions = listOf(
stringResource(R.string.combustion),
stringResource(R.string.electric),
)
RadioButtonSingleSelection(
modifier = Modifier.padding(),
selectedOption = engineType,
radioOptions = radioOptions,
onClick = viewModel::onEngineTypeChanged
)
}
}
}
}
}

View File

@@ -39,4 +39,7 @@ fun SettingsRoute(route: String, navController: NavHostController, function: ()
if (route == "settings_screen") {
SettingsScreen(viewModel, navController, function)
}
if (route == "car_settings") {
CarScreen (viewModel = viewModel, function)
}
}

View File

@@ -51,7 +51,14 @@ fun SettingsScreen(
name = "Navigation Settings",
description = "",
icon = R.drawable.navigation_24px
),
Item(
id = "car_settings",
name = "Car Settings",
description = "",
icon = R.drawable.electric_car_24px
)
)
Scaffold(

View File

@@ -3,7 +3,7 @@
android:height="108dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="#000000">
android:tint="#1A7416">
<group android:scaleX="0.7888"
android:scaleY="0.7888"
android:translateX="101.376"

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#98DABB</color>
</resources>