Refactoring
This commit is contained in:
@@ -14,8 +14,8 @@ android {
|
||||
applicationId = "com.kouros.navigation"
|
||||
minSdk = 33
|
||||
targetSdk = 36
|
||||
versionCode = 7
|
||||
versionName = "0.1.3.7"
|
||||
versionCode = 8
|
||||
versionName = "0.1.3.8"
|
||||
base.archivesName = "navi-$versionName"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
@@ -15,28 +15,36 @@ import androidx.annotation.RequiresPermission
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.BottomSheetScaffold
|
||||
import androidx.compose.material3.BottomSheetScaffoldState
|
||||
import androidx.compose.material3.Button
|
||||
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
|
||||
import androidx.compose.material3.rememberBottomSheetScaffoldState
|
||||
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.mutableDoubleStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
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.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import com.google.android.gms.location.FusedLocationProviderClient
|
||||
import com.google.android.gms.location.LocationServices
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.data.Constants.homeLocation
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.StepData
|
||||
@@ -74,6 +82,10 @@ class MainActivity : ComponentActivity() {
|
||||
MutableLiveData<StepData>()
|
||||
}
|
||||
|
||||
val nextStepData: MutableLiveData<StepData> by lazy {
|
||||
MutableLiveData<StepData>()
|
||||
}
|
||||
|
||||
var lastLocation = location(0.0, 0.0)
|
||||
|
||||
val observer = Observer<String> { newRoute ->
|
||||
@@ -147,8 +159,9 @@ class MainActivity : ComponentActivity() {
|
||||
fun Content() {
|
||||
val scaffoldState = rememberBottomSheetScaffoldState()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val sheetPeekHeightState = remember { mutableStateOf(256.dp) }
|
||||
|
||||
val locationProvider = rememberDefaultLocationProvider(
|
||||
updateInterval = 0.5.seconds,
|
||||
desiredAccuracy = DesiredAccuracy.Highest
|
||||
@@ -161,24 +174,27 @@ class MainActivity : ComponentActivity() {
|
||||
latitude = locationState.value!!.position.latitude
|
||||
}
|
||||
val step: StepData? by stepData.observeAsState()
|
||||
val nextStep: StepData? by nextStepData.observeAsState()
|
||||
|
||||
fun openSheet() {
|
||||
scope.launch { scaffoldState.bottomSheetState.expand() }
|
||||
}
|
||||
|
||||
fun closeSheet() {
|
||||
scope.launch { scaffoldState.bottomSheetState.partialExpand() }
|
||||
scope.launch {
|
||||
scaffoldState.bottomSheetState.partialExpand()
|
||||
sheetPeekHeightState.value = 128.dp
|
||||
}
|
||||
}
|
||||
|
||||
NavigationTheme {
|
||||
NavigationTheme() {
|
||||
BottomSheetScaffold(
|
||||
snackbarHost = {
|
||||
SnackbarHost(hostState = snackbarHostState)
|
||||
},
|
||||
scaffoldState = scaffoldState,
|
||||
sheetPeekHeight = 128.dp,
|
||||
sheetPeekHeight = sheetPeekHeightState.value,
|
||||
sheetContent = {
|
||||
SheetContent(latitude, step) { closeSheet() }
|
||||
SheetContent(latitude, step, nextStep) { closeSheet() }
|
||||
},
|
||||
) { innerPadding ->
|
||||
Box(
|
||||
@@ -187,19 +203,31 @@ class MainActivity : ComponentActivity() {
|
||||
.padding(innerPadding),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
MapView(applicationContext,userLocationState, step, cameraPosition, routeData, tilt)
|
||||
MapView(
|
||||
applicationContext,
|
||||
userLocationState,
|
||||
step,
|
||||
cameraPosition,
|
||||
routeData,
|
||||
tilt
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SheetContent(locationState: Double, step: StepData?, closeSheet: () -> Unit) {
|
||||
fun SheetContent(
|
||||
locationState: Double,
|
||||
step: StepData?,
|
||||
nextStep: StepData?,
|
||||
closeSheet: () -> Unit
|
||||
) {
|
||||
if (!routeModel.isNavigating()) {
|
||||
SearchSheet(applicationContext, viewModel, lastLocation) { closeSheet() }
|
||||
} else {
|
||||
NavigationSheet(
|
||||
routeModel, step!!,
|
||||
routeModel, step!!, nextStep!!,
|
||||
{ stopNavigation { closeSheet() } },
|
||||
{ simulateNavigation() }
|
||||
)
|
||||
@@ -213,11 +241,16 @@ class MainActivity : ComponentActivity() {
|
||||
&& lastLocation.latitude != location.position.latitude
|
||||
&& lastLocation.longitude != location.position.longitude
|
||||
) {
|
||||
if (routeModel.isNavigating()) {
|
||||
routeModel.updateLocation(lastLocation)
|
||||
stepData.value = routeModel.currentStep()
|
||||
}
|
||||
val currentLocation = location(location.position.longitude, location.position.latitude)
|
||||
with(routeModel) {
|
||||
if (isNavigating()) {
|
||||
updateLocation(currentLocation)
|
||||
stepData.value = currentStep()
|
||||
if (route.currentManeuverIndex + 1 <= route.maneuvers.size) {
|
||||
nextStepData.value = nextStep()
|
||||
}
|
||||
}
|
||||
}
|
||||
val bearing = bearing(lastLocation, currentLocation, cameraPosition.value!!.bearing)
|
||||
val zoom = calculateZoom(location.speed)
|
||||
cameraPosition.postValue(
|
||||
@@ -252,7 +285,7 @@ class MainActivity : ComponentActivity() {
|
||||
val appOpsManager =
|
||||
getSystemService(APP_OPS_SERVICE) as AppOpsManager
|
||||
val mode =
|
||||
appOpsManager.unsafeCheckOp(
|
||||
appOpsManager.checkOp(
|
||||
AppOpsManager.OPSTR_MOCK_LOCATION,
|
||||
Process.myUid(),
|
||||
packageName
|
||||
@@ -275,7 +308,7 @@ class MainActivity : ComponentActivity() {
|
||||
for ((_, loc) in routeModel.route.waypoints.withIndex()) {
|
||||
if (routeModel.isNavigating()) {
|
||||
mock.setMockLocation(loc[1], loc[0])
|
||||
delay(1000L) //
|
||||
delay(500L) //
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,43 @@
|
||||
package com.kouros.navigation.ui
|
||||
|
||||
import android.R.attr.x
|
||||
import android.R.attr.y
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.absoluteOffset
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
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.DarkMode
|
||||
import com.kouros.navigation.car.map.MapLibre
|
||||
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.CameraState
|
||||
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
|
||||
@@ -57,32 +70,14 @@ fun MapView(
|
||||
zoom = 15.0,
|
||||
)
|
||||
)
|
||||
val baseStyle = remember {
|
||||
mutableStateOf(BaseStyle.Uri(Constants.STYLE))
|
||||
}
|
||||
DarkMode(applicationContext, baseStyle)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
MapLibre(applicationContext, cameraState, baseStyle, route, "", position)
|
||||
LocationTrackingEffect(
|
||||
locationState = userLocationState,
|
||||
) {
|
||||
@@ -97,7 +92,8 @@ fun MapView(
|
||||
duration = 1.seconds
|
||||
)
|
||||
}
|
||||
NavigationImage(paddingValues, width, height / 6, "")
|
||||
NavigationImage(paddingValues, width, height / 6)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,13 @@ import com.kouros.navigation.utils.round
|
||||
fun NavigationSheet(
|
||||
routeModel: RouteModel,
|
||||
step: StepData,
|
||||
nextStep: StepData,
|
||||
stopNavigation: () -> Unit,
|
||||
simulateNavigation: () -> Unit,
|
||||
) {
|
||||
val distance = step.leftDistance.round(1)
|
||||
Column {
|
||||
FlowRow(horizontalArrangement= Arrangement.SpaceEvenly) {
|
||||
FlowRow(horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
Text(formatDateTime(step.arrivalTime), fontSize = 22.sp)
|
||||
Spacer(Modifier.size(30.dp))
|
||||
Text("$distance km", fontSize = 22.sp)
|
||||
@@ -47,7 +48,9 @@ fun NavigationSheet(
|
||||
modifier = Modifier.size(24.dp, 24.dp),
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.size(30.dp))
|
||||
}
|
||||
Spacer(Modifier.size(30.dp))
|
||||
if (!routeModel.isNavigating()) {
|
||||
Button(onClick = {
|
||||
simulateNavigation()
|
||||
}) {
|
||||
|
||||
@@ -57,7 +57,7 @@ fun PermissionScreen(
|
||||
errorText = if (rejectedPermissions.none { it in requiredPermissions }) {
|
||||
""
|
||||
} else {
|
||||
"${rejectedPermissions.joinToString()} required for the sample"
|
||||
"${rejectedPermissions.joinToString()} required for the app"
|
||||
}
|
||||
}
|
||||
val allRequiredPermissionsGranted =
|
||||
@@ -128,7 +128,7 @@ private fun PermissionScreen(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
text = "Sample requires permission/s:",
|
||||
text = "Navigation requires permission/s:",
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
modifier = Modifier.padding(16.dp),
|
||||
)
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.text.input.TextFieldState
|
||||
import androidx.compose.foundation.text.input.rememberTextFieldState
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -56,23 +57,25 @@ fun SearchSheet(
|
||||
if (search.value != null) {
|
||||
searchResults.addAll(search.value!!)
|
||||
}
|
||||
Home(applicationContext, viewModel, location, closeSheet = { closeSheet() })
|
||||
if (searchResults.isNotEmpty()) {
|
||||
val textFieldState = rememberTextFieldState()
|
||||
val items = listOf(searchResults)
|
||||
if (items.isNotEmpty()) {
|
||||
SearchBar(
|
||||
textFieldState = textFieldState,
|
||||
searchPlaces = recentPlaces.value!!,
|
||||
searchPlaces = recentPlaces.value!!,
|
||||
searchResults = searchResults,
|
||||
viewModel = viewModel,
|
||||
context = applicationContext,
|
||||
location = location,
|
||||
closeSheet = {closeSheet()}
|
||||
closeSheet = { closeSheet() }
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
if (recentPlaces.value != null) {
|
||||
println("Recent Places ${recentPlaces.value}")
|
||||
val textFieldState = rememberTextFieldState()
|
||||
val items = listOf(recentPlaces)
|
||||
if (items.isNotEmpty()) {
|
||||
@@ -83,10 +86,44 @@ fun SearchSheet(
|
||||
viewModel = viewModel,
|
||||
context = applicationContext,
|
||||
location = location,
|
||||
closeSheet = {closeSheet()}
|
||||
closeSheet = { closeSheet() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Home(
|
||||
applicationContext: Context,
|
||||
viewModel: ViewModel,
|
||||
location: Location,
|
||||
closeSheet: () -> Unit
|
||||
) {
|
||||
Row(horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Button(onClick = {
|
||||
val places = viewModel.loadRecentPlace()
|
||||
val toLocation = location(places.first()!!.longitude, places.first()!!.latitude)
|
||||
viewModel.loadRoute(applicationContext, location, toLocation)
|
||||
closeSheet()
|
||||
}) {
|
||||
Icon(
|
||||
painter = painterResource(id = com.google.android.gms.base.R.drawable.common_full_open_on_phone),
|
||||
"Home",
|
||||
modifier = Modifier.size(24.dp, 24.dp),
|
||||
)
|
||||
Text("Home")
|
||||
}
|
||||
Button(onClick = {
|
||||
}) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_favorite_white_24dp),
|
||||
"Work",
|
||||
modifier = Modifier.size(24.dp, 24.dp),
|
||||
)
|
||||
Text("Arbeit")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -176,6 +213,16 @@ private fun SearchPlaces(
|
||||
headlineContent = { Text("${place.address.road} ${place.address.postcode}") },
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
val pl = Place(
|
||||
name = place.name,
|
||||
longitude = place.lon.toDouble(),
|
||||
latitude = place.lat.toDouble(),
|
||||
postalCode = place.address.postcode,
|
||||
city = place.address.city,
|
||||
street = place.address.road
|
||||
)
|
||||
viewModel.saveRecent(pl)
|
||||
println("Save $pl")
|
||||
val toLocation =
|
||||
location(place.lon.toDouble(), place.lat.toDouble())
|
||||
viewModel.loadRoute(context, location, toLocation)
|
||||
@@ -212,7 +259,7 @@ private fun RecentPlaces(
|
||||
modifier = Modifier.size(24.dp, 24.dp),
|
||||
)
|
||||
ListItem(
|
||||
headlineContent = { Text("${place.street!!} ${place.postalCode}") },
|
||||
headlineContent = { Text("${place.name} ${place.postalCode}") },
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
val toLocation = location(place.longitude, place.latitude)
|
||||
|
||||
Reference in New Issue
Block a user