SheetContent Simulation
This commit is contained in:
@@ -98,4 +98,5 @@ class MockLocation (private var locationManager: LocationManager) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
132
app/src/main/java/com/kouros/navigation/model/Simulation.kt
Normal file
132
app/src/main/java/com/kouros/navigation/model/Simulation.kt
Normal file
@@ -0,0 +1,132 @@
|
||||
package com.kouros.navigation.model
|
||||
|
||||
import android.content.Context
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.MainApplication.Companion.navigationViewModel
|
||||
import com.kouros.navigation.utils.location
|
||||
import io.ticofab.androidgpxparser.parser.GPXParser
|
||||
import io.ticofab.androidgpxparser.parser.domain.Gpx
|
||||
import io.ticofab.androidgpxparser.parser.domain.TrackSegment
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.joda.time.DateTime
|
||||
import kotlin.collections.forEach
|
||||
|
||||
fun simulate(routeModel: RouteModel, mock: MockLocation) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
var lastLocation = location(0.0, 0.0)
|
||||
for ((index, waypoint) in routeModel.curRoute.waypoints.withIndex()) {
|
||||
val curLocation = location(waypoint[0], waypoint[1])
|
||||
if (routeModel.isNavigating()) {
|
||||
val deviation = 0.0
|
||||
if (index in 0..routeModel.curRoute.waypoints.size) {
|
||||
val bearing = lastLocation.bearingTo(curLocation)
|
||||
mock.setMockLocation(waypoint[1], waypoint[0], bearing)
|
||||
Thread.sleep(1000)
|
||||
}
|
||||
}
|
||||
lastLocation = curLocation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test(applicationContext: Context, routeModel: RouteModel) {
|
||||
for ((index, step) in routeModel.curLeg.steps.withIndex()) {
|
||||
for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) {
|
||||
routeModel.updateLocation(
|
||||
applicationContext,
|
||||
location(waypoint[0], waypoint[1]), navigationViewModel
|
||||
)
|
||||
val step = routeModel.currentStep()
|
||||
val nextStep = routeModel.nextStep()
|
||||
println("Step: ${step.instruction} ${step.leftStepDistance} ${nextStep.currentManeuverType}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun testSingle(applicationContext: Context, routeModel: RouteModel, mock: MockLocation) {
|
||||
testSingleUpdate(
|
||||
applicationContext,
|
||||
48.185976,
|
||||
11.578463,
|
||||
routeModel,
|
||||
mock
|
||||
) // Silcherstr. 23-13
|
||||
testSingleUpdate(
|
||||
applicationContext,
|
||||
48.186712,
|
||||
11.578574,
|
||||
routeModel,
|
||||
mock
|
||||
) // Silcherstr. 27-33
|
||||
testSingleUpdate(
|
||||
applicationContext,
|
||||
48.186899,
|
||||
11.580480,
|
||||
routeModel,
|
||||
mock
|
||||
) // Schmalkadenerstr. 24-28
|
||||
}
|
||||
|
||||
fun testSingleUpdate(
|
||||
applicationContext: Context,
|
||||
latitude: Double,
|
||||
longitude: Double,
|
||||
routeModel: RouteModel,
|
||||
mock: MockLocation
|
||||
) {
|
||||
if (1 == 1) {
|
||||
mock.setMockLocation(latitude, longitude, 0F)
|
||||
} else {
|
||||
routeModel.updateLocation(
|
||||
applicationContext,
|
||||
location(longitude, latitude), navigationViewModel
|
||||
)
|
||||
}
|
||||
val step = routeModel.currentStep()
|
||||
val nextStep = routeModel.nextStep()
|
||||
Thread.sleep(1_000)
|
||||
}
|
||||
|
||||
fun gpx(context: Context, mock: MockLocation) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
var lastLocation = location(0.0, 0.0)
|
||||
val parser = GPXParser()
|
||||
val input = context.resources.openRawResource(R.raw.vh)
|
||||
val parsedGpx: Gpx? = parser.parse(input) // consider using a background thread
|
||||
parsedGpx?.let {
|
||||
val tracks = parsedGpx.tracks
|
||||
tracks.forEach { tr ->
|
||||
val segments: MutableList<TrackSegment?>? = tr.trackSegments
|
||||
segments!!.forEach { seg ->
|
||||
var lastTime = DateTime.now()
|
||||
seg!!.trackPoints.forEach { p ->
|
||||
val curLocation = location(p.longitude, p.latitude)
|
||||
val ext = p.extensions
|
||||
val speed: Double?
|
||||
if (ext != null) {
|
||||
speed = ext.speed
|
||||
mock.curSpeed = speed.toFloat()
|
||||
}
|
||||
|
||||
val duration = p.time.millis - lastTime.millis
|
||||
val bearing = lastLocation.bearingTo(curLocation)
|
||||
println("Bearing $bearing")
|
||||
mock.setMockLocation(p.latitude, p.longitude, bearing)
|
||||
if (duration > 0) {
|
||||
delay(duration / 5)
|
||||
}
|
||||
lastTime = p.time
|
||||
lastLocation = curLocation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class SimulationType {
|
||||
SIMULATE, TEST, GPX, TEST_SINGLE
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.kouros.navigation.ui
|
||||
|
||||
import NavigationSheet
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AppOpsManager
|
||||
import android.content.Context
|
||||
import android.location.LocationManager
|
||||
import android.os.Bundle
|
||||
import android.os.Process
|
||||
@@ -18,6 +16,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.BottomSheetScaffold
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
@@ -56,6 +55,11 @@ import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.model.BaseStyleModel
|
||||
import com.kouros.navigation.model.MockLocation
|
||||
import com.kouros.navigation.model.RouteModel
|
||||
import com.kouros.navigation.model.SimulationType
|
||||
import com.kouros.navigation.model.gpx
|
||||
import com.kouros.navigation.model.simulate
|
||||
import com.kouros.navigation.model.test
|
||||
import com.kouros.navigation.model.testSingle
|
||||
import com.kouros.navigation.ui.app.AppViewModel
|
||||
import com.kouros.navigation.ui.app.appViewModel
|
||||
import com.kouros.navigation.ui.navigation.AppNavGraph
|
||||
@@ -64,14 +68,7 @@ import com.kouros.navigation.utils.GeoUtils.snapLocation
|
||||
import com.kouros.navigation.utils.bearing
|
||||
import com.kouros.navigation.utils.getSettingsViewModel
|
||||
import com.kouros.navigation.utils.location
|
||||
import io.ticofab.androidgpxparser.parser.GPXParser
|
||||
import io.ticofab.androidgpxparser.parser.domain.Gpx
|
||||
import io.ticofab.androidgpxparser.parser.domain.TrackSegment
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.joda.time.DateTime
|
||||
import org.maplibre.compose.camera.CameraPosition
|
||||
import org.maplibre.compose.location.DesiredAccuracy
|
||||
import org.maplibre.compose.location.Location
|
||||
@@ -86,7 +83,7 @@ class MainActivity : ComponentActivity() {
|
||||
val routeModel = RouteModel()
|
||||
var tilt = 50.0
|
||||
val useMock = false
|
||||
val type = 3 // 1 simulate 2 test 3 gpx 4 testSingle
|
||||
val type = SimulationType.GPX
|
||||
|
||||
val stepData: MutableLiveData<StepData> by lazy {
|
||||
MutableLiveData()
|
||||
@@ -94,6 +91,7 @@ class MainActivity : ComponentActivity() {
|
||||
val nextStepData: MutableLiveData<StepData> by lazy {
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
var lastLocation = location(0.0, 0.0)
|
||||
val observer = Observer<String> { newRoute ->
|
||||
if (newRoute.isNotEmpty()) {
|
||||
@@ -101,13 +99,12 @@ class MainActivity : ComponentActivity() {
|
||||
routeData.value = routeModel.curRoute.routeGeoJson
|
||||
if (useMock) {
|
||||
when (type) {
|
||||
1 -> simulate()
|
||||
2 -> test()
|
||||
3 -> gpx(
|
||||
context = applicationContext
|
||||
SimulationType.SIMULATE -> simulate(routeModel, mock)
|
||||
SimulationType.TEST -> test(applicationContext, routeModel)
|
||||
SimulationType.GPX -> gpx(
|
||||
context = applicationContext, mock
|
||||
)
|
||||
|
||||
4 -> testSingle()
|
||||
SimulationType.TEST_SINGLE -> testSingle(applicationContext, routeModel, mock)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,11 +184,12 @@ class MainActivity : ComponentActivity() {
|
||||
val appViewModel: AppViewModel = appViewModel()
|
||||
val darkMode by appViewModel.darkMode.collectAsState()
|
||||
|
||||
val sheetPeekHeight = 250.dp
|
||||
|
||||
val baseStyle = BaseStyleModel().readStyle(applicationContext, darkMode, darkMode == 1)
|
||||
val scaffoldState = rememberBottomSheetScaffoldState()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val scope = rememberCoroutineScope()
|
||||
val sheetPeekHeight = 250.dp
|
||||
val sheetPeekHeightState = remember { mutableStateOf(sheetPeekHeight) }
|
||||
|
||||
val locationProvider = rememberDefaultLocationProvider(
|
||||
@@ -209,7 +207,7 @@ class MainActivity : ComponentActivity() {
|
||||
fun closeSheet() {
|
||||
scope.launch {
|
||||
scaffoldState.bottomSheetState.partialExpand()
|
||||
sheetPeekHeightState.value = sheetPeekHeight
|
||||
sheetPeekHeightState.value = 50.dp
|
||||
}
|
||||
}
|
||||
NavigationTheme(useDarkTheme = darkMode == 1) {
|
||||
@@ -217,7 +215,7 @@ class MainActivity : ComponentActivity() {
|
||||
snackbarHost = {
|
||||
SnackbarHost(hostState = snackbarHostState)
|
||||
},
|
||||
scaffoldState = scaffoldState,
|
||||
scaffoldState = scaffoldState,
|
||||
sheetPeekHeight = sheetPeekHeightState.value,
|
||||
sheetContent = {
|
||||
SheetContent(latitude, step, nextStep) { closeSheet() }
|
||||
@@ -363,7 +361,10 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
fun simulateNavigation() {
|
||||
simulate()
|
||||
simulate(
|
||||
routeModel = routeModel,
|
||||
mock = mock
|
||||
)
|
||||
}
|
||||
|
||||
private fun checkMockLocationEnabled() {
|
||||
@@ -385,95 +386,5 @@ class MainActivity : ComponentActivity() {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun simulate() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
var lastLocation = location(0.0, 0.0)
|
||||
for ((index, waypoint) in routeModel.curRoute.waypoints.withIndex()) {
|
||||
val curLocation = location(waypoint[0], waypoint[1])
|
||||
if (routeModel.isNavigating()) {
|
||||
val deviation = 0.0
|
||||
if (index in 0..routeModel.curRoute.waypoints.size) {
|
||||
val bearing = lastLocation.bearingTo(curLocation)
|
||||
mock.setMockLocation(waypoint[1], waypoint[0], bearing)
|
||||
Thread.sleep(1000)
|
||||
}
|
||||
}
|
||||
lastLocation = curLocation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
for ((index, step) in routeModel.curLeg.steps.withIndex()) {
|
||||
//if (index in 3..3) {
|
||||
for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) {
|
||||
routeModel.updateLocation(
|
||||
applicationContext,
|
||||
location(waypoint[0], waypoint[1]), navigationViewModel
|
||||
)
|
||||
val step = routeModel.currentStep()
|
||||
val nextStep = routeModel.nextStep()
|
||||
println("Step: ${step.instruction} ${step.leftStepDistance} ${nextStep.currentManeuverType}")
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
fun testSingle() {
|
||||
testSingleUpdate(48.185976, 11.578463) // Silcherstr. 23-13
|
||||
testSingleUpdate(48.186712, 11.578574) // Silcherstr. 27-33
|
||||
testSingleUpdate(48.186899, 11.580480) // Schmalkadenerstr. 24-28
|
||||
}
|
||||
|
||||
fun testSingleUpdate(latitude: Double, longitude: Double) {
|
||||
if (1 == 1) {
|
||||
mock.setMockLocation(latitude, longitude, 0F)
|
||||
} else {
|
||||
routeModel.updateLocation(
|
||||
applicationContext,
|
||||
location(longitude, latitude), navigationViewModel
|
||||
)
|
||||
}
|
||||
val step = routeModel.currentStep()
|
||||
val nextStep = routeModel.nextStep()
|
||||
Thread.sleep(1_000)
|
||||
}
|
||||
|
||||
fun gpx(context: Context) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
var lastLocation = location(0.0, 0.0)
|
||||
val parser = GPXParser()
|
||||
val input = context.resources.openRawResource(R.raw.vh)
|
||||
val parsedGpx: Gpx? = parser.parse(input) // consider using a background thread
|
||||
parsedGpx?.let {
|
||||
val tracks = parsedGpx.tracks
|
||||
tracks.forEach { tr ->
|
||||
val segments: MutableList<TrackSegment?>? = tr.trackSegments
|
||||
segments!!.forEach { seg ->
|
||||
var lastTime = DateTime.now()
|
||||
seg!!.trackPoints.forEach { p ->
|
||||
val curLocation = location(p.longitude, p.latitude)
|
||||
val ext = p.extensions
|
||||
val speed: Double?
|
||||
if (ext != null) {
|
||||
speed = ext.speed
|
||||
mock.curSpeed = speed.toFloat()
|
||||
}
|
||||
|
||||
val duration = p.time.millis - lastTime.millis
|
||||
val bearing = lastLocation.bearingTo(curLocation)
|
||||
println("Bearing $bearing")
|
||||
mock.setMockLocation(p.latitude, p.longitude, bearing)
|
||||
if (duration > 0) {
|
||||
delay(duration / 5)
|
||||
}
|
||||
lastTime = p.time
|
||||
lastLocation = curLocation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
package com.kouros.navigation.ui
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -13,9 +15,7 @@ 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.core.graphics.drawable.IconCompat
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.model.RouteModel
|
||||
import com.kouros.navigation.utils.formatDateTime
|
||||
|
||||
@@ -61,6 +61,7 @@ fun SearchSheet(
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
) {
|
||||
// Home(applicationContext, viewModel, location, closeSheet = { closeSheet() })
|
||||
SearchBar(
|
||||
textFieldState = textFieldState,
|
||||
searchPlaces = emptyList(),
|
||||
@@ -71,7 +72,7 @@ fun SearchSheet(
|
||||
closeSheet = { closeSheet() }
|
||||
|
||||
)
|
||||
//Home(applicationContext, viewModel, location, closeSheet = { closeSheet() })
|
||||
|
||||
if (recentPlaces.value != null) {
|
||||
val items = listOf(recentPlaces)
|
||||
if (items.isNotEmpty()) {
|
||||
@@ -142,7 +143,7 @@ fun SearchBar(
|
||||
SearchBarDefaults.InputField(
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.search_48px),
|
||||
painter = painterResource(id = R.drawable.speed_camera_24px),
|
||||
"Search",
|
||||
modifier = Modifier.size(24.dp, 24.dp),
|
||||
)
|
||||
@@ -166,8 +167,8 @@ fun SearchBar(
|
||||
RecentPlaces(searchPlaces, viewModel, context, location, closeSheet)
|
||||
}
|
||||
if (searchResults.isNotEmpty()) {
|
||||
Text("Search places")
|
||||
SearchPlaces(searchResults, viewModel, context, location, closeSheet)
|
||||
Text("Search places")
|
||||
SearchPlaces(searchResults, viewModel, context, location, closeSheet)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,7 +187,7 @@ private fun SearchPlaces(
|
||||
) {
|
||||
val color = remember { PlaceColor }
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 24.dp),
|
||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 10.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
if (searchResults.isNotEmpty()) {
|
||||
@@ -199,7 +200,7 @@ private fun SearchPlaces(
|
||||
modifier = Modifier.size(24.dp, 24.dp),
|
||||
)
|
||||
ListItem(
|
||||
headlineContent = { Text("${place.address.road} ${place.address.postcode}") },
|
||||
headlineContent = { Text(place.displayName) },
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
val pl = Place(
|
||||
@@ -235,7 +236,7 @@ private fun RecentPlaces(
|
||||
) {
|
||||
val color = remember { PlaceColor }
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 24.dp),
|
||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 10.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
items(recentPlaces, key = { it.id }) { place ->
|
||||
|
||||
Reference in New Issue
Block a user