LocationPuck
This commit is contained in:
@@ -18,7 +18,6 @@ package com.kouros.navigation
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.PackageManager
|
||||
import android.location.Location
|
||||
import android.location.LocationManager
|
||||
import android.os.Bundle
|
||||
@@ -34,23 +33,37 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalDrawerSheet
|
||||
import androidx.compose.material3.ModalNavigationDrawer
|
||||
import androidx.compose.material3.NavigationDrawerItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SegmentedButtonDefaults.Icon
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.location.LocationListenerCompat
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import com.example.places.ui.theme.PlacesTheme
|
||||
@@ -59,10 +72,12 @@ import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
import com.kouros.navigation.data.Category
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Constants.TAG
|
||||
import com.kouros.navigation.data.Constants.homeLocation
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.model.RouteModel
|
||||
import com.kouros.navigation.model.ViewModel
|
||||
import com.kouros.navigation.utils.NavigationUtils
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
import org.maplibre.compose.camera.CameraPosition
|
||||
import org.maplibre.compose.camera.rememberCameraState
|
||||
@@ -85,18 +100,24 @@ import org.maplibre.spatialk.geojson.Position
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
|
||||
val geojson = MutableLiveData("")
|
||||
val routeData = MutableLiveData("")
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
val vieModel = ViewModel(NavigationRepository())
|
||||
val routeModel = RouteModel()
|
||||
|
||||
var tilt = 0.0
|
||||
|
||||
val curLocation = Location(LocationManager.GPS_PROVIDER)
|
||||
|
||||
val instruction: MutableLiveData<StepData> by lazy {
|
||||
MutableLiveData<StepData>()
|
||||
}
|
||||
|
||||
val observer = Observer<String> { newRoute ->
|
||||
routeModel.createNavigationRoute(newRoute)
|
||||
geojson.value = routeModel.geoJson
|
||||
homeLocation.latitude = 48.155782
|
||||
homeLocation.longitude = 11.607921
|
||||
routeModel.startNavigation(newRoute)
|
||||
routeData.value = routeModel.route
|
||||
}
|
||||
|
||||
val cameraPosition = MutableLiveData(
|
||||
@@ -108,38 +129,19 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
init {
|
||||
vieModel.route.observe(this, observer)
|
||||
vieModel.loadRoute(
|
||||
homeLocation,
|
||||
Constants.home2Location
|
||||
)
|
||||
}
|
||||
|
||||
var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? ->
|
||||
updateLocation(location)
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
fun requestLocationUpdates() {
|
||||
val locationManager =
|
||||
getSystemService(LOCATION_SERVICE) as LocationManager
|
||||
val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
|
||||
updateLocation(location)
|
||||
locationManager.requestLocationUpdates(
|
||||
LocationManager.GPS_PROVIDER,
|
||||
/* minTimeMs= */ 100,
|
||||
/* minDistanceM= */ 0f,
|
||||
mLocationListener
|
||||
)
|
||||
}
|
||||
|
||||
fun updateLocation(location: Location?) {
|
||||
fun updateLocation(location: org.maplibre.compose.location.Location?) {
|
||||
if (location != null) {
|
||||
if (routeModel.isNavigating()) {
|
||||
instruction.value = routeModel.currentStep()
|
||||
}
|
||||
val zoom = NavigationUtils().calculateZoom(location.speed)
|
||||
cameraPosition.postValue(
|
||||
cameraPosition.value!!.copy(
|
||||
zoom = 15.0,
|
||||
target = Position(location.longitude, location.latitude),
|
||||
)
|
||||
zoom = zoom,
|
||||
target = location.position
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -164,23 +166,64 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
val scope = rememberCoroutineScope()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
PlacesTheme {
|
||||
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
||||
Column(modifier = Modifier.padding(innerPadding)) {
|
||||
CheckPermission()
|
||||
ModalNavigationDrawer(
|
||||
drawerContent = {
|
||||
ModalDrawerSheet {
|
||||
Text("Drawer title", modifier = Modifier.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
NavigationDrawerItem(
|
||||
label = { Text(text = "Drawer Item") },
|
||||
selected = false,
|
||||
onClick = { /*TODO*/ }
|
||||
)
|
||||
}
|
||||
},
|
||||
gesturesEnabled = false
|
||||
) {
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
snackbarHost = {
|
||||
SnackbarHost(hostState = snackbarHostState)
|
||||
},
|
||||
floatingActionButton = {
|
||||
ExtendedFloatingActionButton(
|
||||
text = {
|
||||
Text("Navigate")
|
||||
},
|
||||
icon = { Icon(true) },
|
||||
onClick = {
|
||||
scope.launch {
|
||||
snackbarHostState.showSnackbar("Starte Navigation")
|
||||
}
|
||||
if (!routeModel.isNavigating()) {
|
||||
tilt = 60.0
|
||||
vieModel.loadRoute(
|
||||
curLocation,
|
||||
Constants.home2Location
|
||||
)
|
||||
} else {
|
||||
tilt = 0.0
|
||||
routeModel.stopNavigation()
|
||||
routeData.value = ""
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
) { innerPadding ->
|
||||
Column(modifier = Modifier.padding(innerPadding)) {
|
||||
CheckPermission()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
val locationManager =
|
||||
getSystemService(LOCATION_SERVICE) as LocationManager
|
||||
locationManager.removeUpdates(mLocationListener)
|
||||
}
|
||||
|
||||
@SuppressLint("PermissionLaunchedDuringComposition")
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
@@ -224,11 +267,40 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NavigationInfo(step: StepData?) {
|
||||
Card {
|
||||
Column {
|
||||
Icon(
|
||||
painter = painterResource(com.kouros.android.cars.carappservice.R.drawable.ic_turn_normal_right),
|
||||
contentDescription = stringResource(id = com.kouros.android.cars.carappservice.R.string.accept_action_title)
|
||||
)
|
||||
if (step != null) {
|
||||
Text(text = step.bearing.toString(), fontSize = 25.sp)
|
||||
Text(text = step.instruction, fontSize = 25.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Map() {
|
||||
requestLocationUpdates()
|
||||
val step: StepData? by instruction.observeAsState()
|
||||
Column {
|
||||
if (step != null) {
|
||||
NavigationInfo(step)
|
||||
}
|
||||
MapView()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MapView() {
|
||||
val locationProvider = rememberDefaultLocationProvider()
|
||||
val locationState = rememberUserLocationState(locationProvider)
|
||||
updateLocation(locationState.location)
|
||||
val position: CameraPosition? by cameraPosition.observeAsState()
|
||||
val geoJsonData: String? by geojson.observeAsState()
|
||||
val route: String? by routeData.observeAsState()
|
||||
val cameraState =
|
||||
rememberCameraState(
|
||||
firstPosition =
|
||||
@@ -241,9 +313,10 @@ class MainActivity : ComponentActivity() {
|
||||
)
|
||||
)
|
||||
|
||||
val locationProvider = rememberDefaultLocationProvider()
|
||||
val locationState = rememberUserLocationState(locationProvider)
|
||||
|
||||
if (locationState.location != null) {
|
||||
curLocation.latitude = locationState.location?.position!!.latitude
|
||||
curLocation.longitude = locationState.location?.position!!.longitude
|
||||
}
|
||||
MaplibreMap(
|
||||
cameraState = cameraState,
|
||||
//baseStyle = BaseStyle.Uri("https://tiles.openfreemap.org/styles/liberty"),
|
||||
@@ -270,7 +343,7 @@ class MainActivity : ComponentActivity() {
|
||||
)
|
||||
getBaseSource(id = "openmaptiles")?.let { tiles ->
|
||||
FillLayer(id = "example", visible = false, source = tiles, sourceLayer = "building")
|
||||
RouteLayer(geoJsonData)
|
||||
RouteLayer(route)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,6 +353,7 @@ class MainActivity : ComponentActivity() {
|
||||
bearing = position!!.bearing,
|
||||
zoom = position!!.zoom,
|
||||
target = position!!.target,
|
||||
tilt = tilt
|
||||
),
|
||||
duration = 3.seconds
|
||||
)
|
||||
@@ -287,21 +361,23 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RouteLayer(geoJsonData: String?) {
|
||||
val routes =
|
||||
rememberGeoJsonSource(GeoJsonData.JsonString(geoJsonData!!))
|
||||
LineLayer(
|
||||
id = "routes-casing",
|
||||
source = routes,
|
||||
color = const(Color.White),
|
||||
width = const(6.dp),
|
||||
)
|
||||
LineLayer(
|
||||
id = "routes",
|
||||
source = routes,
|
||||
color = const(Color.Blue),
|
||||
width = const(4.dp),
|
||||
)
|
||||
fun RouteLayer(routeData: String?) {
|
||||
if (routeData!!.isNotEmpty()) {
|
||||
val routes =
|
||||
rememberGeoJsonSource(GeoJsonData.JsonString(routeData!!))
|
||||
LineLayer(
|
||||
id = "routes-casing",
|
||||
source = routes,
|
||||
color = const(Color.White),
|
||||
width = const(6.dp),
|
||||
)
|
||||
LineLayer(
|
||||
id = "routes",
|
||||
source = routes,
|
||||
color = const(Color.Blue),
|
||||
width = const(4.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
Reference in New Issue
Block a user