NavigationImage and padding

This commit is contained in:
Dimitris
2025-11-29 15:17:39 +01:00
parent 372cf504e2
commit c353a1d74e
11 changed files with 174 additions and 64 deletions

View File

@@ -20,12 +20,12 @@ android {
} }
signingConfigs { signingConfigs {
getByName("debug") { // getByName("debug") {
keyAlias = "alias" // keyAlias = "alias"
keyPassword = "alpha2000" // keyPassword = "alpha2000"
storeFile = file("/home/kouros/work/keystore/keystoreDebug") // storeFile = file("/home/kouros/work/keystore/keystoreRelease")
storePassword = "alpha2000" // storePassword = "alpha2000"
} // }
create("release") { create("release") {
keyAlias = "release" keyAlias = "release"
keyPassword = "zeta67#g" keyPassword = "zeta67#g"

View File

@@ -256,6 +256,7 @@ class MainActivity : ComponentActivity() {
fun Map() { fun Map() {
val step: StepData? by instruction.observeAsState() val step: StepData? by instruction.observeAsState()
Column { Column {
//SimpleSearchBar()
if (step != null) { if (step != null) {
NavigationInfo(step) NavigationInfo(step)
} }

View File

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

View File

@@ -3,22 +3,18 @@ package com.kouros.navigation.car
import android.location.Location import android.location.Location
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size 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.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.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.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.vectorResource import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
@@ -54,7 +50,7 @@ fun cameraState(
tilt: Double, tilt: Double,
preview: Boolean preview: Boolean
): CameraState { ): CameraState {
val padding = getPaddingValues(width, height, preview) val padding = getPaddingValues(height, preview)
return rememberCameraState( return rememberCameraState(
firstPosition = firstPosition =
CameraPosition( CameraPosition(
@@ -118,29 +114,46 @@ fun BuildingLayer(tiles: Source) {
} }
@Composable @Composable
fun DrawImage(location: Location) { fun DrawImage(width: Int, height: Int, location: Location) {
val textMeasurer = rememberTextMeasurer() NavigationImage(height)
Speed(width, height, location)
}
@Composable
fun NavigationImage(height: Int) {
val vector = ImageVector.vectorResource(id = R.drawable.assistant_navigation_48px) val vector = ImageVector.vectorResource(id = R.drawable.assistant_navigation_48px)
val painter = rememberVectorPainter(image = vector) val color = remember { NavigationColor }
val tint = remember { ColorFilter.tint(NavigationColor) } BadgedBox(
Box(
modifier = Modifier modifier = Modifier
.size(48.dp, 48.dp) .padding(
.padding(start = 450.dp - 30.dp, top = 350.dp - 30.dp) start = 0.dp, top = distanceFromTop(height).dp
.drawBehind { ),
with(painter) { badge = {
draw( Badge()
size = Size(60F, 60F), }
colorFilter = tint, ) {
) Icon(
} imageVector = vector,
}) contentDescription = "Navigation",
tint = color
)
}
}
@Composable
private fun Speed(
width: Int,
height: Int,
location: Location
) {
val textMeasurer = rememberTextMeasurer()
Box( Box(
modifier = Modifier modifier = Modifier
.size(30.dp, 30.dp) .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 { .drawWithCache {
val measuredText = val measuredText =
textMeasurer.measure( 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 @Composable
fun Puck(cameraState: CameraState, location: Location) { fun Puck(cameraState: CameraState, location: Location) {
LocationPuck( 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
}
}

View File

@@ -206,7 +206,6 @@ class NavigationSession : Session(), NavigationScreen.Listener {
if (routeModel.isNavigating()) { if (routeModel.isNavigating()) {
val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations()) val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations())
val distance = location.distanceTo(snapedLocation) val distance = location.distanceTo(snapedLocation)
println(distance)
if (distance > MAXIMAL_ROUTE_DEVIATION) { if (distance > MAXIMAL_ROUTE_DEVIATION) {
// navigationScreen.calculateNewRoute() // navigationScreen.calculateNewRoute()
//return //return

View File

@@ -6,7 +6,9 @@ import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay import android.hardware.display.VirtualDisplay
import android.location.Location import android.location.Location
import android.location.LocationManager import android.location.LocationManager
import android.os.Build
import android.util.Log import android.util.Log
import androidx.annotation.RequiresApi
import androidx.car.app.AppManager import androidx.car.app.AppManager
import androidx.car.app.CarContext import androidx.car.app.CarContext
import androidx.car.app.SurfaceCallback import androidx.car.app.SurfaceCallback
@@ -25,14 +27,10 @@ import androidx.lifecycle.setViewTreeLifecycleOwner
import androidx.savedstate.setViewTreeSavedStateRegistryOwner import androidx.savedstate.setViewTreeSavedStateRegistryOwner
import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.data.Constants 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.data.Constants.SHOW_THREED_BUILDING
import com.kouros.navigation.model.RouteModel import com.kouros.navigation.model.RouteModel
import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue 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.calculateZoom
import com.kouros.navigation.utils.location
import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.CameraPosition
import org.maplibre.compose.camera.CameraState import org.maplibre.compose.camera.CameraState
import org.maplibre.compose.map.MaplibreMap import org.maplibre.compose.map.MaplibreMap
@@ -87,6 +85,7 @@ class SurfaceRenderer(
lateinit var presentation: Presentation lateinit var presentation: Presentation
@RequiresApi(Build.VERSION_CODES.M)
override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) { override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) {
synchronized(this@SurfaceRenderer) { synchronized(this@SurfaceRenderer) {
Log.i(TAG, "Surface available $surfaceContainer") Log.i(TAG, "Surface available $surfaceContainer")
@@ -136,6 +135,7 @@ class SurfaceRenderer(
} }
} }
@RequiresApi(Build.VERSION_CODES.KITKAT)
override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) { override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) {
synchronized(this@SurfaceRenderer) { synchronized(this@SurfaceRenderer) {
Log.i(TAG, "SurfaceRenderer destroyed") Log.i(TAG, "SurfaceRenderer destroyed")
@@ -168,10 +168,11 @@ class SurfaceRenderer(
val route: String? by routeData.observeAsState() val route: String? by routeData.observeAsState()
val previewRoute: String? by previewRouteData.observeAsState() val previewRoute: String? by previewRouteData.observeAsState()
val cameraState = cameraState(width, height, position, tilt, preview) val cameraState = cameraState(width, height, position, tilt, preview)
val baseStyle =
if (isSystemInDarkTheme()) BaseStyle.Uri(Constants.STYLE_DARK) else BaseStyle.Uri( val baseStyle =BaseStyle.Uri(Constants.STYLE)
Constants.STYLE // if (isSystemInDarkTheme()) BaseStyle.Uri(Constants.STYLE_DARK) else BaseStyle.Uri(
) // Constants.STYLE
// )
MaplibreMap( MaplibreMap(
cameraState = cameraState, cameraState = cameraState,
@@ -196,7 +197,7 @@ class SurfaceRenderer(
var target = position.target var target = position.target
var localTilt = tilt var localTilt = tilt
if (!preview) { if (!preview) {
DrawImage(lastLocation) DrawImage(width, height,lastLocation)
} else { } else {
bearing = 0.0 bearing = 0.0
zoom = previewZoom() zoom = previewZoom()
@@ -210,7 +211,7 @@ class SurfaceRenderer(
zoom = zoom, zoom = zoom,
target = target, target = target,
tilt = localTilt, tilt = localTilt,
padding = getPaddingValues(width, height, preview) padding = getPaddingValues(height, preview)
), ),
duration = cameraDuration duration = cameraDuration
) )
@@ -230,7 +231,7 @@ class SurfaceRenderer(
val cameraDuration = if ((lastBearing - position!!.bearing).absoluteValue > 20.0) { val cameraDuration = if ((lastBearing - position!!.bearing).absoluteValue > 20.0) {
2.seconds 2.seconds
} else { } else {
2.seconds 1.seconds
} }
return cameraDuration return cameraDuration
} }
@@ -286,7 +287,7 @@ class SurfaceRenderer(
bearing = bearing, bearing = bearing,
zoom = zoom, zoom = zoom,
tilt = 0.0, tilt = 0.0,
padding = getPaddingValues(width, height, preview), padding = getPaddingValues(height, preview),
target = target target = target
) )
) )

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M190,840L160,810L480,80L800,810L770,840L480,708L190,840ZM258,742L480,644L702,742L480,228L258,742ZM480,644L480,644L480,644L480,644Z"/>
</vector>

View File

@@ -17,8 +17,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android" <resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="back_caps_action_title" msgid="6392829425035919422">"ZURÜCK"</string>
<string name="home_caps_action_title" msgid="4853167242566949502">"STARTSEITE"</string>
<string name="exit_action_title" msgid="9086586388884500731">"Beenden"</string> <string name="exit_action_title" msgid="9086586388884500731">"Beenden"</string>
<string name="refresh_action_title" msgid="3674260822403151377">"Aktualisieren"</string> <string name="refresh_action_title" msgid="3674260822403151377">"Aktualisieren"</string>
<string name="close_action_title" msgid="2661907510124308560">"Schließen"</string> <string name="close_action_title" msgid="2661907510124308560">"Schließen"</string>
@@ -28,7 +26,6 @@
<string name="stop_action_title" msgid="1187619482795416314">"Stopp"</string> <string name="stop_action_title" msgid="1187619482795416314">"Stopp"</string>
<string name="more_action_title" msgid="1039516575011403837">"Mehr"</string> <string name="more_action_title" msgid="1039516575011403837">"Mehr"</string>
<string name="call_action_title" msgid="6218977436905001611">"Anrufen"</string> <string name="call_action_title" msgid="6218977436905001611">"Anrufen"</string>
<string name="primary_action_title" msgid="7042003552215710683">"Primär"</string>
<string name="options_action_title" msgid="1168121856107932984">"Optionen"</string> <string name="options_action_title" msgid="1168121856107932984">"Optionen"</string>
<string name="search_action_title" msgid="3483459674263446335">"Suchen"</string> <string name="search_action_title" msgid="3483459674263446335">"Suchen"</string>
<string name="checked_action_title" msgid="906023941445896399">"Aktiviert"</string> <string name="checked_action_title" msgid="906023941445896399">"Aktiviert"</string>
@@ -42,7 +39,6 @@
<string name="throw_action_title" msgid="7163710562670220163">"Auslösen"</string> <string name="throw_action_title" msgid="7163710562670220163">"Auslösen"</string>
<string name="commute_action_title" msgid="2585755255290185096">"Arbeitsweg"</string> <string name="commute_action_title" msgid="2585755255290185096">"Arbeitsweg"</string>
<string name="sign_out_action_title" msgid="1653943000866713010">"Abmelden"</string> <string name="sign_out_action_title" msgid="1653943000866713010">"Abmelden"</string>
<string name="try_anyway_action_title" msgid="7384500054249311718">"Trotzdem versuchen"</string>
<string name="yes_action_title" msgid="5507096013762092189">"Ja"</string> <string name="yes_action_title" msgid="5507096013762092189">"Ja"</string>
<string name="no_action_title" msgid="1452124604210014010">"Nein"</string> <string name="no_action_title" msgid="1452124604210014010">"Nein"</string>
<string name="disable_all_rows" msgid="3003225080532928046">"Alle Zeilen deaktivieren"</string> <string name="disable_all_rows" msgid="3003225080532928046">"Alle Zeilen deaktivieren"</string>
@@ -77,7 +73,6 @@
<string name="car_hardware_demo_title" msgid="3679106197233262689">"Demo der Auto-Hardware"</string> <string name="car_hardware_demo_title" msgid="3679106197233262689">"Demo der Auto-Hardware"</string>
<string name="car_hardware_info" msgid="1244783247616395012">"Informationen zur Auto-Hardware"</string> <string name="car_hardware_info" msgid="1244783247616395012">"Informationen zur Auto-Hardware"</string>
<string name="model_info" msgid="494224423025683030">"Modellinformationen"</string> <string name="model_info" msgid="494224423025683030">"Modellinformationen"</string>
<string name="no_model_permission" msgid="5333629877014978947">"Keine Berechtigung für Modell"</string>
<string name="manufacturer_unavailable" msgid="4978995415869838056">"Hersteller nicht verfügbar"</string> <string name="manufacturer_unavailable" msgid="4978995415869838056">"Hersteller nicht verfügbar"</string>
<string name="model_unavailable" msgid="4075463010215406573">"Modell nicht verfügbar"</string> <string name="model_unavailable" msgid="4075463010215406573">"Modell nicht verfügbar"</string>
<string name="year_unavailable" msgid="994338773299644607">"Jahr nicht verfügbar"</string> <string name="year_unavailable" msgid="994338773299644607">"Jahr nicht verfügbar"</string>

View File

@@ -17,8 +17,6 @@
<string name="app_name" translatable="false">Navigation</string> <string name="app_name" translatable="false">Navigation</string>
<!-- Action Titles --> <!-- Action Titles -->
<string name="back_caps_action_title">BACK</string>
<string name="home_caps_action_title">HOME</string>
<string name="exit_action_title">Exit</string> <string name="exit_action_title">Exit</string>
<string name="refresh_action_title">Refresh</string> <string name="refresh_action_title">Refresh</string>
<string name="close_action_title">Close</string> <string name="close_action_title">Close</string>
@@ -28,7 +26,6 @@
<string name="stop_action_title">Stop</string> <string name="stop_action_title">Stop</string>
<string name="more_action_title">More</string> <string name="more_action_title">More</string>
<string name="call_action_title">Call</string> <string name="call_action_title">Call</string>
<string name="primary_action_title">Primary</string>
<string name="options_action_title">Options</string> <string name="options_action_title">Options</string>
<string name="search_action_title">Search</string> <string name="search_action_title">Search</string>
<string name="checked_action_title">Checked</string> <string name="checked_action_title">Checked</string>
@@ -42,7 +39,6 @@
<string name="throw_action_title">Throw</string> <string name="throw_action_title">Throw</string>
<string name="commute_action_title">Commute</string> <string name="commute_action_title">Commute</string>
<string name="sign_out_action_title">Sign out</string> <string name="sign_out_action_title">Sign out</string>
<string name="try_anyway_action_title">Try Anyway</string>
<string name="yes_action_title">Yes</string> <string name="yes_action_title">Yes</string>
<string name="no_action_title">No</string> <string name="no_action_title">No</string>
<string name="disable_all_rows">Disable All Rows</string> <string name="disable_all_rows">Disable All Rows</string>
@@ -87,7 +83,6 @@
<!-- CarHardwareInfoScreen --> <!-- CarHardwareInfoScreen -->
<string name="car_hardware_info">Car Hardware Information</string> <string name="car_hardware_info">Car Hardware Information</string>
<string name="model_info">Model Information</string> <string name="model_info">Model Information</string>
<string name="no_model_permission">No Model Permission</string>
<string name="manufacturer_unavailable">Manufacturer unavailable</string> <string name="manufacturer_unavailable">Manufacturer unavailable</string>
<string name="model_unavailable">Model unavailable</string> <string name="model_unavailable">Model unavailable</string>
<string name="year_unavailable">Year unavailable</string> <string name="year_unavailable">Year unavailable</string>

View File

@@ -2,6 +2,6 @@ package com.kouros.navigation.data
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
val NavigationColor = Color(0xFF094DB6) val NavigationColor = Color(0xFF052086)
val RouteColor = Color(0xFF5582D0) val RouteColor = Color(0xFF5582D0)

View File

@@ -3,6 +3,8 @@ package com.kouros.navigation.utils
import android.content.Context import android.content.Context
import android.location.Location import android.location.Location
import android.location.LocationManager import android.location.LocationManager
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.content.edit import androidx.core.content.edit
import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION
import com.kouros.navigation.data.Constants.SHARED_PREF_KEY import com.kouros.navigation.data.Constants.SHARED_PREF_KEY
@@ -43,6 +45,7 @@ object NavigationUtils {
.getBoolean(key, false) .getBoolean(key, false)
} }
@RequiresApi(Build.VERSION_CODES.GINGERBREAD)
fun setBooleanKeyValue(context: Context, `val`: Boolean, key: String) { fun setBooleanKeyValue(context: Context, `val`: Boolean, key: String) {
context context
.getSharedPreferences( .getSharedPreferences(
@@ -64,6 +67,11 @@ object NavigationUtils {
val point = pointFeature.geometry() as Point val point = pointFeature.geometry() as Point
newLocation.latitude = point.latitude() newLocation.latitude = point.latitude()
newLocation.longitude = point.longitude() 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 return newLocation
} }