From c353a1d74e497cb80ed9dcd1584e3f2ed42f982b Mon Sep 17 00:00:00 2001 From: Dimitris Date: Sat, 29 Nov 2025 15:17:39 +0100 Subject: [PATCH] NavigationImage and padding --- app/build.gradle.kts | 12 +-- .../com/kouros/navigation/MainActivity.kt | 1 + .../java/com/kouros/navigation/SearchBar.kt | 79 ++++++++++++++++ .../java/com/kouros/navigation/car/MapView.kt | 90 ++++++++++++------- .../navigation/car/NavigationSession.kt | 1 - .../kouros/navigation/car/SurfaceRenderer.kt | 25 +++--- .../src/main/res/drawable/navigation_48px.xml | 10 +++ common/car/src/main/res/values-de/strings.xml | 5 -- common/car/src/main/res/values/strings.xml | 5 -- .../java/com/kouros/navigation/data/Color.kt | 2 +- .../navigation/utils/NavigationUtils.kt | 8 ++ 11 files changed, 174 insertions(+), 64 deletions(-) create mode 100644 app/src/main/java/com/kouros/navigation/SearchBar.kt create mode 100644 common/car/src/main/res/drawable/navigation_48px.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9b89e50..123e686 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,12 +20,12 @@ android { } signingConfigs { - getByName("debug") { - keyAlias = "alias" - keyPassword = "alpha2000" - storeFile = file("/home/kouros/work/keystore/keystoreDebug") - storePassword = "alpha2000" - } +// getByName("debug") { +// keyAlias = "alias" +// keyPassword = "alpha2000" +// storeFile = file("/home/kouros/work/keystore/keystoreRelease") +// storePassword = "alpha2000" +// } create("release") { keyAlias = "release" keyPassword = "zeta67#g" diff --git a/app/src/main/java/com/kouros/navigation/MainActivity.kt b/app/src/main/java/com/kouros/navigation/MainActivity.kt index f8eba19..1703e13 100644 --- a/app/src/main/java/com/kouros/navigation/MainActivity.kt +++ b/app/src/main/java/com/kouros/navigation/MainActivity.kt @@ -256,6 +256,7 @@ class MainActivity : ComponentActivity() { fun Map() { val step: StepData? by instruction.observeAsState() Column { + //SimpleSearchBar() if (step != null) { NavigationInfo(step) } diff --git a/app/src/main/java/com/kouros/navigation/SearchBar.kt b/app/src/main/java/com/kouros/navigation/SearchBar.kt new file mode 100644 index 0000000..e030665 --- /dev/null +++ b/app/src/main/java/com/kouros/navigation/SearchBar.kt @@ -0,0 +1,79 @@ +package com.kouros.navigation + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ListItem +import androidx.compose.material3.SearchBar +import androidx.compose.material3.SearchBarDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.isTraversalGroup +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.traversalIndex + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SimpleSearchBar( + textFieldState: TextFieldState, + onSearch: (String) -> Unit, + searchResults: List, + modifier: Modifier = Modifier +) { + // Controls expansion state of the search bar + var expanded by rememberSaveable { mutableStateOf(false) } + + Box( + modifier + .fillMaxSize() + .semantics { isTraversalGroup = true } + ) { + SearchBar( + modifier = Modifier + .align(Alignment.TopCenter) + .semantics { traversalIndex = 0f }, + inputField = { + SearchBarDefaults.InputField( + query = textFieldState.text.toString(), + onQueryChange = { textFieldState.edit { replace(0, length, it) } }, + onSearch = { + onSearch(textFieldState.text.toString()) + expanded = false + }, + expanded = expanded, + onExpandedChange = { expanded = it }, + placeholder = { Text("Search") } + ) + }, + expanded = expanded, + onExpandedChange = { expanded = it }, + ) { + // Display search results in a scrollable column + Column(Modifier.verticalScroll(rememberScrollState())) { + searchResults.forEach { result -> + ListItem( + headlineContent = { Text(result) }, + modifier = Modifier + .clickable { + textFieldState.edit { replace(0, length, result) } + expanded = false + } + .fillMaxWidth() + ) + } + } + } + } +} \ No newline at end of file diff --git a/common/car/src/main/java/com/kouros/navigation/car/MapView.kt b/common/car/src/main/java/com/kouros/navigation/car/MapView.kt index a12a6c9..54c4e20 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/MapView.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/MapView.kt @@ -3,22 +3,18 @@ package com.kouros.navigation.car import android.location.Location import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.material3.Badge +import androidx.compose.material3.BadgedBox +import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.graphics.Path -import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle @@ -54,7 +50,7 @@ fun cameraState( tilt: Double, preview: Boolean ): CameraState { - val padding = getPaddingValues(width, height, preview) + val padding = getPaddingValues(height, preview) return rememberCameraState( firstPosition = CameraPosition( @@ -118,29 +114,46 @@ fun BuildingLayer(tiles: Source) { } @Composable -fun DrawImage(location: Location) { - val textMeasurer = rememberTextMeasurer() +fun DrawImage(width: Int, height: Int, location: Location) { + NavigationImage(height) + Speed(width, height, location) +} + +@Composable +fun NavigationImage(height: Int) { val vector = ImageVector.vectorResource(id = R.drawable.assistant_navigation_48px) - val painter = rememberVectorPainter(image = vector) - val tint = remember { ColorFilter.tint(NavigationColor) } - - Box( + val color = remember { NavigationColor } + BadgedBox( modifier = Modifier - .size(48.dp, 48.dp) - .padding(start = 450.dp - 30.dp, top = 350.dp - 30.dp) - .drawBehind { - with(painter) { - draw( - size = Size(60F, 60F), - colorFilter = tint, - ) - } - }) + .padding( + start = 0.dp, top = distanceFromTop(height).dp + ), + badge = { + Badge() + } + ) { + Icon( + imageVector = vector, + contentDescription = "Navigation", + tint = color + ) + } +} +@Composable +private fun Speed( + width: Int, + height: Int, + location: Location +) { + val textMeasurer = rememberTextMeasurer() Box( modifier = Modifier .size(30.dp, 30.dp) - .padding(start = 650.dp, top = 350.dp) + .padding( + start = width.dp - percent(width, 20).dp, + top = height.dp - 60.dp + ) .drawWithCache { val measuredText = textMeasurer.measure( @@ -157,6 +170,24 @@ fun DrawImage(location: Location) { ) } +fun getPaddingValues(height: Int, preView: Boolean): PaddingValues { + val padding = PaddingValues(start = 0.dp, top = distanceFromTop(height).dp) + val prePadding = PaddingValues(start = 150.dp, bottom = 0.dp) + return if (preView) { + prePadding + } else { + padding + } +} + +fun distanceFromTop(height: Int): Int { + return height - percent(height, 20) +} + +fun percent(maxValue: Int, value: Int): Int { + return value * maxValue / 100 +} + @Composable fun Puck(cameraState: CameraState, location: Location) { LocationPuck( @@ -189,12 +220,3 @@ fun PuckState(cameraState: CameraState, userLocationState: UserLocationState) { ) } -fun getPaddingValues(width: Int, height: Int, preView: Boolean): PaddingValues { - val padding = PaddingValues(start = 100.dp, top = 300.dp) - val prePadding = PaddingValues(start = 150.dp, bottom = 0.dp) - return if (preView) { - prePadding - } else { - padding - } -} \ No newline at end of file diff --git a/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt b/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt index 8a9b3ab..27ff33c 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt @@ -206,7 +206,6 @@ class NavigationSession : Session(), NavigationScreen.Listener { if (routeModel.isNavigating()) { val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations()) val distance = location.distanceTo(snapedLocation) - println(distance) if (distance > MAXIMAL_ROUTE_DEVIATION) { // navigationScreen.calculateNewRoute() //return diff --git a/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt b/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt index 6ba6c73..dddfed5 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt @@ -6,7 +6,9 @@ import android.hardware.display.DisplayManager import android.hardware.display.VirtualDisplay import android.location.Location import android.location.LocationManager +import android.os.Build import android.util.Log +import androidx.annotation.RequiresApi import androidx.car.app.AppManager import androidx.car.app.CarContext import androidx.car.app.SurfaceCallback @@ -25,14 +27,10 @@ import androidx.lifecycle.setViewTreeLifecycleOwner import androidx.savedstate.setViewTreeSavedStateRegistryOwner import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.data.Constants -import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION -import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING import com.kouros.navigation.model.RouteModel import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue -import com.kouros.navigation.utils.NavigationUtils.snapLocation import com.kouros.navigation.utils.calculateZoom -import com.kouros.navigation.utils.location import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.CameraState import org.maplibre.compose.map.MaplibreMap @@ -87,6 +85,7 @@ class SurfaceRenderer( lateinit var presentation: Presentation + @RequiresApi(Build.VERSION_CODES.M) override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) { synchronized(this@SurfaceRenderer) { Log.i(TAG, "Surface available $surfaceContainer") @@ -136,6 +135,7 @@ class SurfaceRenderer( } } + @RequiresApi(Build.VERSION_CODES.KITKAT) override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) { synchronized(this@SurfaceRenderer) { Log.i(TAG, "SurfaceRenderer destroyed") @@ -168,10 +168,11 @@ class SurfaceRenderer( val route: String? by routeData.observeAsState() val previewRoute: String? by previewRouteData.observeAsState() val cameraState = cameraState(width, height, position, tilt, preview) - val baseStyle = - if (isSystemInDarkTheme()) BaseStyle.Uri(Constants.STYLE_DARK) else BaseStyle.Uri( - Constants.STYLE - ) + + val baseStyle =BaseStyle.Uri(Constants.STYLE) +// if (isSystemInDarkTheme()) BaseStyle.Uri(Constants.STYLE_DARK) else BaseStyle.Uri( +// Constants.STYLE +// ) MaplibreMap( cameraState = cameraState, @@ -196,7 +197,7 @@ class SurfaceRenderer( var target = position.target var localTilt = tilt if (!preview) { - DrawImage(lastLocation) + DrawImage(width, height,lastLocation) } else { bearing = 0.0 zoom = previewZoom() @@ -210,7 +211,7 @@ class SurfaceRenderer( zoom = zoom, target = target, tilt = localTilt, - padding = getPaddingValues(width, height, preview) + padding = getPaddingValues(height, preview) ), duration = cameraDuration ) @@ -230,7 +231,7 @@ class SurfaceRenderer( val cameraDuration = if ((lastBearing - position!!.bearing).absoluteValue > 20.0) { 2.seconds } else { - 2.seconds + 1.seconds } return cameraDuration } @@ -286,7 +287,7 @@ class SurfaceRenderer( bearing = bearing, zoom = zoom, tilt = 0.0, - padding = getPaddingValues(width, height, preview), + padding = getPaddingValues(height, preview), target = target ) ) diff --git a/common/car/src/main/res/drawable/navigation_48px.xml b/common/car/src/main/res/drawable/navigation_48px.xml new file mode 100644 index 0000000..e87c0a6 --- /dev/null +++ b/common/car/src/main/res/drawable/navigation_48px.xml @@ -0,0 +1,10 @@ + + + diff --git a/common/car/src/main/res/values-de/strings.xml b/common/car/src/main/res/values-de/strings.xml index da3c299..01339df 100644 --- a/common/car/src/main/res/values-de/strings.xml +++ b/common/car/src/main/res/values-de/strings.xml @@ -17,8 +17,6 @@ - "ZURÜCK" - "STARTSEITE" "Beenden" "Aktualisieren" "Schließen" @@ -28,7 +26,6 @@ "Stopp" "Mehr" "Anrufen" - "Primär" "Optionen" "Suchen" "Aktiviert" @@ -42,7 +39,6 @@ "Auslösen" "Arbeitsweg" "Abmelden" - "Trotzdem versuchen" "Ja" "Nein" "Alle Zeilen deaktivieren" @@ -77,7 +73,6 @@ "Demo der Auto-Hardware" "Informationen zur Auto-Hardware" "Modellinformationen" - "Keine Berechtigung für Modell" "Hersteller nicht verfügbar" "Modell nicht verfügbar" "Jahr nicht verfügbar" diff --git a/common/car/src/main/res/values/strings.xml b/common/car/src/main/res/values/strings.xml index e2fe462..ea7db48 100644 --- a/common/car/src/main/res/values/strings.xml +++ b/common/car/src/main/res/values/strings.xml @@ -17,8 +17,6 @@ Navigation - BACK - HOME Exit Refresh Close @@ -28,7 +26,6 @@ Stop More Call - Primary Options Search Checked @@ -42,7 +39,6 @@ Throw Commute Sign out - Try Anyway Yes No Disable All Rows @@ -87,7 +83,6 @@ Car Hardware Information Model Information - No Model Permission Manufacturer unavailable Model unavailable Year unavailable diff --git a/common/data/src/main/java/com/kouros/navigation/data/Color.kt b/common/data/src/main/java/com/kouros/navigation/data/Color.kt index cc61e1f..c0c5b74 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/Color.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/Color.kt @@ -2,6 +2,6 @@ package com.kouros.navigation.data import androidx.compose.ui.graphics.Color -val NavigationColor = Color(0xFF094DB6) +val NavigationColor = Color(0xFF052086) val RouteColor = Color(0xFF5582D0) diff --git a/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt b/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt index 9a03b66..c7169a9 100644 --- a/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt +++ b/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt @@ -3,6 +3,8 @@ package com.kouros.navigation.utils import android.content.Context import android.location.Location import android.location.LocationManager +import android.os.Build +import androidx.annotation.RequiresApi import androidx.core.content.edit import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION import com.kouros.navigation.data.Constants.SHARED_PREF_KEY @@ -43,6 +45,7 @@ object NavigationUtils { .getBoolean(key, false) } + @RequiresApi(Build.VERSION_CODES.GINGERBREAD) fun setBooleanKeyValue(context: Context, `val`: Boolean, key: String) { context .getSharedPreferences( @@ -64,6 +67,11 @@ object NavigationUtils { val point = pointFeature.geometry() as Point newLocation.latitude = point.latitude() newLocation.longitude = point.longitude() + newLocation.speed = location.speed + newLocation.bearing = location.bearing + newLocation.time = location.time + newLocation.accuracy = location.accuracy + newLocation.altitude = location.altitude } return newLocation }