Refactoring
This commit is contained in:
@@ -14,8 +14,8 @@ android {
|
||||
applicationId = "com.kouros.navigation"
|
||||
minSdk = 33
|
||||
targetSdk = 36
|
||||
versionCode = 6
|
||||
versionName = "0.1.3.6"
|
||||
versionCode = 7
|
||||
versionName = "0.1.3.7"
|
||||
base.archivesName = "navi-$versionName"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
@@ -93,6 +93,7 @@ dependencies {
|
||||
implementation(libs.androidx.compose.material3.window.size.class1)
|
||||
implementation(libs.androidx.compose.ui.graphics)
|
||||
implementation(libs.androidx.window)
|
||||
implementation(libs.androidx.compose.foundation.layout)
|
||||
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
|
||||
@@ -13,14 +13,10 @@ import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.annotation.RequiresPermission
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.BottomSheetScaffold
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
@@ -31,31 +27,23 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableDoubleStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
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.window.layout.WindowMetricsCalculator
|
||||
import com.google.android.gms.location.FusedLocationProviderClient
|
||||
import com.google.android.gms.location.LocationServices
|
||||
import com.kouros.android.cars.carappservice.R
|
||||
import com.kouros.navigation.car.map.BuildingLayer
|
||||
import com.kouros.navigation.car.map.NavigationImage
|
||||
import com.kouros.navigation.car.map.RouteLayer
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Constants.homeLocation
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.data.nominatim.SearchResult
|
||||
import com.kouros.navigation.model.MockLocation
|
||||
import com.kouros.navigation.model.RouteModel
|
||||
import com.kouros.navigation.model.ViewModel
|
||||
import com.kouros.navigation.ui.theme.NavigationTheme
|
||||
import com.kouros.navigation.utils.NavigationUtils
|
||||
import com.kouros.navigation.utils.bearing
|
||||
import com.kouros.navigation.utils.calculateZoom
|
||||
import com.kouros.navigation.utils.location
|
||||
@@ -63,18 +51,12 @@ import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.maplibre.compose.camera.CameraPosition
|
||||
import org.maplibre.compose.camera.rememberCameraState
|
||||
import org.maplibre.compose.location.DesiredAccuracy
|
||||
import org.maplibre.compose.location.LocationTrackingEffect
|
||||
import org.maplibre.compose.location.UserLocationState
|
||||
import org.maplibre.compose.location.Location
|
||||
import org.maplibre.compose.location.rememberDefaultLocationProvider
|
||||
import org.maplibre.compose.location.rememberUserLocationState
|
||||
import org.maplibre.compose.map.MapOptions
|
||||
import org.maplibre.compose.map.MaplibreMap
|
||||
import org.maplibre.compose.map.OrnamentOptions
|
||||
import org.maplibre.compose.sources.getBaseSource
|
||||
import org.maplibre.compose.style.BaseStyle
|
||||
import org.maplibre.spatialk.geojson.Position
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@@ -88,15 +70,19 @@ class MainActivity : ComponentActivity() {
|
||||
var tilt = 50.0
|
||||
|
||||
val useMock = true
|
||||
val instruction: MutableLiveData<StepData> by lazy {
|
||||
val stepData: MutableLiveData<StepData> by lazy {
|
||||
MutableLiveData<StepData>()
|
||||
}
|
||||
|
||||
var lastLocation = location(0.0, 0.0)
|
||||
|
||||
val observer = Observer<String> { newRoute ->
|
||||
routeModel.startNavigation(newRoute)
|
||||
routeData.value = routeModel.route.routeGeoJson
|
||||
if (newRoute.isNotEmpty()) {
|
||||
routeModel.startNavigation(newRoute)
|
||||
routeData.value = routeModel.route.routeGeoJson
|
||||
//mock.setMockLocation(homeLocation.latitude, homeLocation.longitude)
|
||||
simulate()
|
||||
}
|
||||
}
|
||||
val cameraPosition = MutableLiveData(
|
||||
CameraPosition(
|
||||
@@ -129,8 +115,8 @@ class MainActivity : ComponentActivity() {
|
||||
if (useMock) {
|
||||
mock = MockLocation(locationManager)
|
||||
mock.setMockLocation(
|
||||
Constants.homeLocation.latitude,
|
||||
Constants.homeLocation.longitude
|
||||
homeLocation.latitude,
|
||||
homeLocation.longitude
|
||||
)
|
||||
}
|
||||
enableEdgeToEdge()
|
||||
@@ -139,6 +125,21 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Composable
|
||||
fun CheckPermissionScreen() {
|
||||
val permissions = listOf(
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
)
|
||||
PermissionScreen(
|
||||
permissions = permissions,
|
||||
requiredPermissions = listOf(permissions.first()),
|
||||
onGranted = {
|
||||
Content()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("AutoboxingStateCreation")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -146,6 +147,8 @@ class MainActivity : ComponentActivity() {
|
||||
fun Content() {
|
||||
val scaffoldState = rememberBottomSheetScaffoldState()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val locationProvider = rememberDefaultLocationProvider(
|
||||
updateInterval = 0.5.seconds,
|
||||
desiredAccuracy = DesiredAccuracy.Highest
|
||||
@@ -157,7 +160,15 @@ class MainActivity : ComponentActivity() {
|
||||
if (locationState.value != null) {
|
||||
latitude = locationState.value!!.position.latitude
|
||||
}
|
||||
val step: StepData? by instruction.observeAsState()
|
||||
val step: StepData? by stepData.observeAsState()
|
||||
|
||||
fun openSheet() {
|
||||
scope.launch { scaffoldState.bottomSheetState.expand() }
|
||||
}
|
||||
|
||||
fun closeSheet() {
|
||||
scope.launch { scaffoldState.bottomSheetState.partialExpand() }
|
||||
}
|
||||
|
||||
NavigationTheme {
|
||||
BottomSheetScaffold(
|
||||
@@ -167,7 +178,7 @@ class MainActivity : ComponentActivity() {
|
||||
scaffoldState = scaffoldState,
|
||||
sheetPeekHeight = 128.dp,
|
||||
sheetContent = {
|
||||
SheetContent(latitude, step)
|
||||
SheetContent(latitude, step) { closeSheet() }
|
||||
},
|
||||
) { innerPadding ->
|
||||
Box(
|
||||
@@ -176,117 +187,35 @@ class MainActivity : ComponentActivity() {
|
||||
.padding(innerPadding),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Map(userLocationState, step)
|
||||
MapView(applicationContext,userLocationState, step, cameraPosition, routeData, tilt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SheetContent(locationState: Double, step: StepData?) {
|
||||
fun SheetContent(locationState: Double, step: StepData?, closeSheet: () -> Unit) {
|
||||
if (!routeModel.isNavigating()) {
|
||||
SearchSheet(applicationContext, viewModel, lastLocation)
|
||||
SearchSheet(applicationContext, viewModel, lastLocation) { closeSheet() }
|
||||
} else {
|
||||
NavigationSheet( routeModel, step, { simulate() })
|
||||
}
|
||||
// to recomposite SheetContent !
|
||||
Text("State $locationState")
|
||||
}
|
||||
@Composable
|
||||
fun NavigationInfo(step: StepData?) {
|
||||
Card {
|
||||
Column {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_turn_normal_right),
|
||||
contentDescription = stringResource(id = R.string.accept_action_title)
|
||||
)
|
||||
if (step != null) {
|
||||
Text(text = step.instruction, fontSize = 25.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Map(userLocationState: UserLocationState, step: StepData?) {
|
||||
Column {
|
||||
if (step != null) {
|
||||
NavigationInfo(step)
|
||||
}
|
||||
MapView(userLocationState)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MapView(userLocationState: UserLocationState) {
|
||||
|
||||
val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this)
|
||||
val width = metrics.bounds.width()
|
||||
val height = metrics.bounds.height()
|
||||
val paddingValues = PaddingValues(start = 0.dp, top = 350.dp)
|
||||
|
||||
val position: CameraPosition? by cameraPosition.observeAsState()
|
||||
val route: String? by routeData.observeAsState()
|
||||
val cameraState =
|
||||
rememberCameraState(
|
||||
firstPosition =
|
||||
CameraPosition(
|
||||
target = Position(
|
||||
position!!.target.latitude,
|
||||
position!!.target.longitude
|
||||
),
|
||||
zoom = 15.0,
|
||||
)
|
||||
NavigationSheet(
|
||||
routeModel, step!!,
|
||||
{ stopNavigation { closeSheet() } },
|
||||
{ simulateNavigation() }
|
||||
)
|
||||
Box (contentAlignment = Alignment.Center) {
|
||||
MaplibreMap(
|
||||
options = MapOptions(
|
||||
ornamentOptions =
|
||||
OrnamentOptions(isScaleBarEnabled = false)
|
||||
),
|
||||
cameraState = cameraState,
|
||||
baseStyle = BaseStyle.Uri(Constants.STYLE),
|
||||
) {
|
||||
getBaseSource(id = "openmaptiles")?.let { tiles ->
|
||||
if (!NavigationUtils.getBooleanKeyValue(
|
||||
context = applicationContext,
|
||||
Constants.SHOW_THREED_BUILDING
|
||||
)
|
||||
) {
|
||||
BuildingLayer(tiles)
|
||||
}
|
||||
RouteLayer(route, "", position!!.zoom)
|
||||
}
|
||||
if (userLocationState.location != null) {
|
||||
///PuckState(cameraState, userLocationState)
|
||||
}
|
||||
}
|
||||
|
||||
LocationTrackingEffect(
|
||||
locationState = userLocationState,
|
||||
) {
|
||||
cameraState.animateTo(
|
||||
finalPosition = CameraPosition(
|
||||
bearing = position!!.bearing,
|
||||
zoom = position!!.zoom,
|
||||
target = position!!.target,
|
||||
tilt = tilt,
|
||||
padding = paddingValues
|
||||
),
|
||||
duration = 1.seconds
|
||||
)
|
||||
}
|
||||
NavigationImage(paddingValues, width, height /6, "")
|
||||
}
|
||||
// For recomposition!
|
||||
Text("$locationState", fontSize = 12.sp)
|
||||
}
|
||||
|
||||
fun updateLocation(location: org.maplibre.compose.location.Location?) {
|
||||
fun updateLocation(location: Location?) {
|
||||
if (location != null
|
||||
&& lastLocation.latitude != location.position.latitude
|
||||
&& lastLocation.longitude != location.position.longitude) {
|
||||
&& lastLocation.longitude != location.position.longitude
|
||||
) {
|
||||
if (routeModel.isNavigating()) {
|
||||
routeModel.updateLocation(lastLocation)
|
||||
instruction.value = routeModel.currentStep()
|
||||
stepData.value = routeModel.currentStep()
|
||||
}
|
||||
val currentLocation = location(location.position.longitude, location.position.latitude)
|
||||
val bearing = bearing(lastLocation, currentLocation, cameraPosition.value!!.bearing)
|
||||
@@ -306,6 +235,17 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
fun stopNavigation(closeSheet: () -> Unit) {
|
||||
closeSheet()
|
||||
routeModel.stopNavigation()
|
||||
routeData.value = ""
|
||||
stepData.value = StepData("", 0.0, 0, 0, 0, 0.0)
|
||||
}
|
||||
|
||||
fun simulateNavigation() {
|
||||
simulate()
|
||||
}
|
||||
|
||||
private fun checkMockLocationEnabled() {
|
||||
try {
|
||||
// Check if mock location is enabled for this app
|
||||
@@ -330,24 +270,9 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Composable
|
||||
fun CheckPermissionScreen() {
|
||||
val permissions = listOf(
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
)
|
||||
PermissionScreen(
|
||||
permissions = permissions,
|
||||
requiredPermissions = listOf(permissions.first()),
|
||||
onGranted = {
|
||||
Content()
|
||||
},
|
||||
)
|
||||
}
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun simulate() = GlobalScope.async {
|
||||
for ((i, loc) in routeModel.route.waypoints.withIndex()) {
|
||||
for ((_, loc) in routeModel.route.waypoints.withIndex()) {
|
||||
if (routeModel.isNavigating()) {
|
||||
mock.setMockLocation(loc[1], loc[0])
|
||||
delay(1000L) //
|
||||
|
||||
103
app/src/main/java/com/kouros/navigation/ui/MapView.kt
Normal file
103
app/src/main/java/com/kouros/navigation/ui/MapView.kt
Normal file
@@ -0,0 +1,103 @@
|
||||
package com.kouros.navigation.ui
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
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.map.BuildingLayer
|
||||
import com.kouros.navigation.car.map.NavigationImage
|
||||
import com.kouros.navigation.car.map.RouteLayer
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.utils.NavigationUtils
|
||||
import org.maplibre.compose.camera.CameraPosition
|
||||
import org.maplibre.compose.camera.rememberCameraState
|
||||
import org.maplibre.compose.location.LocationTrackingEffect
|
||||
import org.maplibre.compose.location.UserLocationState
|
||||
import org.maplibre.compose.map.MapOptions
|
||||
import org.maplibre.compose.map.MaplibreMap
|
||||
import org.maplibre.compose.map.OrnamentOptions
|
||||
import org.maplibre.compose.sources.getBaseSource
|
||||
import org.maplibre.compose.style.BaseStyle
|
||||
import org.maplibre.spatialk.geojson.Position
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@Composable
|
||||
fun MapView(
|
||||
applicationContext: Context,
|
||||
userLocationState: UserLocationState,
|
||||
step: StepData?,
|
||||
cameraPosition: MutableLiveData<CameraPosition>,
|
||||
routeData: MutableLiveData<String>,
|
||||
tilt: Double
|
||||
) {
|
||||
|
||||
val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(applicationContext)
|
||||
val width = metrics.bounds.width()
|
||||
val height = metrics.bounds.height()
|
||||
val paddingValues = PaddingValues(start = 0.dp, top = 350.dp)
|
||||
|
||||
val position: CameraPosition? by cameraPosition.observeAsState()
|
||||
val route: String? by routeData.observeAsState()
|
||||
val cameraState =
|
||||
rememberCameraState(
|
||||
firstPosition =
|
||||
CameraPosition(
|
||||
target = Position(
|
||||
position!!.target.latitude,
|
||||
position!!.target.longitude
|
||||
),
|
||||
zoom = 15.0,
|
||||
)
|
||||
)
|
||||
Column {
|
||||
NavigationInfo(step)
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
MaplibreMap(
|
||||
options = MapOptions(
|
||||
ornamentOptions =
|
||||
OrnamentOptions(isScaleBarEnabled = false)
|
||||
),
|
||||
cameraState = cameraState,
|
||||
baseStyle = BaseStyle.Uri(Constants.STYLE),
|
||||
) {
|
||||
getBaseSource(id = "openmaptiles")?.let { tiles ->
|
||||
if (!NavigationUtils.getBooleanKeyValue(
|
||||
context = applicationContext,
|
||||
Constants.SHOW_THREED_BUILDING
|
||||
)
|
||||
) {
|
||||
BuildingLayer(tiles)
|
||||
}
|
||||
RouteLayer(route, "", position!!.zoom)
|
||||
}
|
||||
if (userLocationState.location != null) {
|
||||
///PuckState(cameraState, userLocationState)
|
||||
}
|
||||
}
|
||||
|
||||
LocationTrackingEffect(
|
||||
locationState = userLocationState,
|
||||
) {
|
||||
cameraState.animateTo(
|
||||
finalPosition = CameraPosition(
|
||||
bearing = position!!.bearing,
|
||||
zoom = position!!.zoom,
|
||||
target = position!!.target,
|
||||
tilt = tilt,
|
||||
padding = paddingValues
|
||||
),
|
||||
duration = 1.seconds
|
||||
)
|
||||
}
|
||||
NavigationImage(paddingValues, width, height / 6, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.kouros.navigation.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.Icon
|
||||
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.compose.ui.unit.sp
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.utils.round
|
||||
|
||||
@Composable
|
||||
fun NavigationInfo(step: StepData?) {
|
||||
if (step != null && step.instruction.isNotEmpty()) {
|
||||
Card(modifier = Modifier.padding(top = 60.dp)) {
|
||||
Column() {
|
||||
Row {
|
||||
Icon(
|
||||
painter = painterResource(step.icon),
|
||||
contentDescription = stringResource(id = R.string.accept_action_title),
|
||||
modifier = Modifier.size(48.dp, 48.dp),
|
||||
)
|
||||
Column {
|
||||
if (step.leftStepDistance < 1000) {
|
||||
Text(text = "${step.leftStepDistance.toInt()} m", fontSize = 25.sp)
|
||||
} else {
|
||||
Text(
|
||||
text = "${(step.leftStepDistance / 1000).round(1)} km",
|
||||
fontSize = 25.sp
|
||||
)
|
||||
}
|
||||
Text(text = step.instruction, fontSize = 20.sp)
|
||||
}
|
||||
Icon(
|
||||
painter = painterResource(step.icon),
|
||||
contentDescription = stringResource(id = R.string.accept_action_title),
|
||||
modifier = Modifier.size(48.dp, 48.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,45 @@
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.kouros.android.cars.carappservice.R
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.model.RouteModel
|
||||
import kotlinx.coroutines.Deferred
|
||||
import com.kouros.navigation.utils.formatDateTime
|
||||
import com.kouros.navigation.utils.round
|
||||
|
||||
|
||||
@Composable
|
||||
fun NavigationSheet(
|
||||
routeModel: RouteModel,
|
||||
step: StepData?,
|
||||
simulate: () -> Unit
|
||||
step: StepData,
|
||||
stopNavigation: () -> Unit,
|
||||
simulateNavigation: () -> Unit,
|
||||
) {
|
||||
val distance = step.leftDistance.round(1)
|
||||
Column {
|
||||
//Text("${routeModel.travelLeftTime()}")
|
||||
if (step != null)
|
||||
Text("${step.leftDistance / 1000} km")
|
||||
FlowRow(horizontalArrangement= Arrangement.SpaceEvenly) {
|
||||
Text(formatDateTime(step.arrivalTime), fontSize = 22.sp)
|
||||
Spacer(Modifier.size(30.dp))
|
||||
Text("$distance km", fontSize = 22.sp)
|
||||
}
|
||||
HorizontalDivider()
|
||||
Row() {
|
||||
FlowRow(horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
if (routeModel.isNavigating()) {
|
||||
Button(onClick = {
|
||||
routeModel.stopNavigation()
|
||||
stopNavigation()
|
||||
}) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_close_white_24dp),
|
||||
@@ -36,8 +47,9 @@ fun NavigationSheet(
|
||||
modifier = Modifier.size(24.dp, 24.dp),
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.size(30.dp))
|
||||
Button(onClick = {
|
||||
simulate()
|
||||
simulateNavigation()
|
||||
}) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.assistant_navigation_48px),
|
||||
|
||||
@@ -22,8 +22,6 @@ import androidx.compose.material3.SearchBar
|
||||
import androidx.compose.material3.SearchBarDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -38,7 +36,7 @@ import androidx.compose.ui.semantics.isTraversalGroup
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.traversalIndex
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.kouros.android.cars.carappservice.R
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.PlaceColor
|
||||
import com.kouros.navigation.data.nominatim.SearchResult
|
||||
@@ -46,7 +44,12 @@ import com.kouros.navigation.model.ViewModel
|
||||
import com.kouros.navigation.utils.location
|
||||
|
||||
@Composable
|
||||
fun SearchSheet(applicationContext: Context, viewModel: ViewModel, location: Location) {
|
||||
fun SearchSheet(
|
||||
applicationContext: Context,
|
||||
viewModel: ViewModel,
|
||||
location: Location,
|
||||
closeSheet: () -> Unit
|
||||
) {
|
||||
val searchResults = mutableListOf<SearchResult>()
|
||||
val recentPlaces = viewModel.places.observeAsState()
|
||||
val search = viewModel.searchPlaces.observeAsState()
|
||||
@@ -63,7 +66,9 @@ fun SearchSheet(applicationContext: Context, viewModel: ViewModel, location: Loc
|
||||
searchResults = searchResults,
|
||||
viewModel = viewModel,
|
||||
context = applicationContext,
|
||||
location = location
|
||||
location = location,
|
||||
closeSheet = {closeSheet()}
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -77,7 +82,8 @@ fun SearchSheet(applicationContext: Context, viewModel: ViewModel, location: Loc
|
||||
searchResults = searchResults,
|
||||
viewModel = viewModel,
|
||||
context = applicationContext,
|
||||
location = location
|
||||
location = location,
|
||||
closeSheet = {closeSheet()}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -93,6 +99,7 @@ fun SearchBar(
|
||||
viewModel: ViewModel,
|
||||
context: Context,
|
||||
location: Location,
|
||||
closeSheet: () -> Unit
|
||||
) {
|
||||
var expanded by rememberSaveable { mutableStateOf(true) }
|
||||
Box(
|
||||
@@ -121,19 +128,19 @@ fun SearchBar(
|
||||
},
|
||||
expanded = expanded,
|
||||
onExpandedChange = { expanded = it },
|
||||
placeholder = { Text("Suchen") }
|
||||
placeholder = { Text(context.getString(R.string.search_action_title)) }
|
||||
)
|
||||
},
|
||||
expanded = expanded,
|
||||
onExpandedChange = { expanded = it },
|
||||
) {
|
||||
if (searchPlaces.isNotEmpty()) {
|
||||
Text("Recent places")
|
||||
RecentPlaces(searchPlaces, viewModel, context, location)
|
||||
Text(context.getString(R.string.recent_destinations))
|
||||
RecentPlaces(searchPlaces, viewModel, context, location, closeSheet)
|
||||
}
|
||||
if (searchResults.isNotEmpty()) {
|
||||
Text("Search places")
|
||||
SearchPlaces(searchResults, viewModel, context, location)
|
||||
SearchPlaces(searchResults, viewModel, context, location, closeSheet)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,6 +156,7 @@ private fun SearchPlaces(
|
||||
viewModel: ViewModel,
|
||||
context: Context,
|
||||
location: Location,
|
||||
closeSheet: () -> Unit
|
||||
) {
|
||||
val color = remember { PlaceColor }
|
||||
LazyColumn(
|
||||
@@ -171,6 +179,7 @@ private fun SearchPlaces(
|
||||
val toLocation =
|
||||
location(place.lon.toDouble(), place.lat.toDouble())
|
||||
viewModel.loadRoute(context, location, toLocation)
|
||||
closeSheet()
|
||||
}
|
||||
.fillMaxWidth()
|
||||
)
|
||||
@@ -186,7 +195,8 @@ private fun RecentPlaces(
|
||||
recentPlaces: List<Place>,
|
||||
viewModel: ViewModel,
|
||||
context: Context,
|
||||
location: Location
|
||||
location: Location,
|
||||
closeSheet: () -> Unit
|
||||
) {
|
||||
val color = remember { PlaceColor }
|
||||
LazyColumn(
|
||||
@@ -207,6 +217,7 @@ private fun RecentPlaces(
|
||||
.clickable {
|
||||
val toLocation = location(place.longitude, place.latitude)
|
||||
viewModel.loadRoute(context, location, toLocation)
|
||||
closeSheet()
|
||||
}
|
||||
.fillMaxWidth()
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user