feat(map): dark status bar on map screen, white on dashboard/manage; faster map animations
Made-with: Cursor
This commit is contained in:
@@ -49,6 +49,9 @@ import org.osmdroid.util.GeoPoint
|
|||||||
import org.osmdroid.views.MapView
|
import org.osmdroid.views.MapView
|
||||||
import org.osmdroid.views.overlay.Marker
|
import org.osmdroid.views.overlay.Marker
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.core.graphics.createBitmap
|
import androidx.core.graphics.createBitmap
|
||||||
import androidx.core.graphics.drawable.toDrawable
|
import androidx.core.graphics.drawable.toDrawable
|
||||||
|
|
||||||
@@ -83,6 +86,7 @@ fun MapScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun MapScreenContent(
|
private fun MapScreenContent(
|
||||||
uiState: State,
|
uiState: State,
|
||||||
@@ -90,12 +94,19 @@ private fun MapScreenContent(
|
|||||||
showMap: Boolean
|
showMap: Boolean
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val centerOnMarker = uiState.selectedMarkerId?.let { id ->
|
||||||
|
uiState.items.find { it.id == id }
|
||||||
|
}
|
||||||
|
val sheetHeightFraction = if (uiState.devicePanelState != null) 0.5f else 0f
|
||||||
|
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
if (showMap) {
|
if (showMap) {
|
||||||
AirMQMap(
|
AirMQMap(
|
||||||
items = uiState.items,
|
items = uiState.items,
|
||||||
onMarkerClick = { onEvent(Event.MarkerClicked(it)) }
|
onMarkerClick = { onEvent(Event.MarkerClicked(it)) },
|
||||||
|
centerOnMarker = centerOnMarker,
|
||||||
|
sheetHeightFraction = sheetHeightFraction,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Box(
|
Box(
|
||||||
@@ -143,17 +154,21 @@ private fun MapScreenContent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
uiState.devicePanelState?.let { panelData ->
|
uiState.devicePanelState?.let { panelData ->
|
||||||
MapDevicePanel(
|
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||||
|
ModalBottomSheet(
|
||||||
|
onDismissRequest = { onEvent(Event.DevicePanelClosed) },
|
||||||
|
sheetState = sheetState
|
||||||
|
) {
|
||||||
|
MapDevicePanelContent(
|
||||||
data = panelData,
|
data = panelData,
|
||||||
onClose = { onEvent(Event.DevicePanelClosed) },
|
|
||||||
onOpenDevice = { onEvent(Event.DeviceOpenClicked) },
|
onOpenDevice = { onEvent(Event.DeviceOpenClicked) },
|
||||||
onRangeSelected = { onEvent(Event.TimeRangeSelected(it)) },
|
onRangeSelected = { onEvent(Event.TimeRangeSelected(it)) },
|
||||||
onDateBack = { onEvent(Event.DateBackClicked) },
|
onDateBack = { onEvent(Event.DateBackClicked) },
|
||||||
onDateForward = { onEvent(Event.DateForwardClicked) },
|
onDateForward = { onEvent(Event.DateForwardClicked) },
|
||||||
onSensorSelected = { onEvent(Event.DeviceSensorSelected(it)) },
|
onSensorSelected = { onEvent(Event.DeviceSensorSelected(it)) }
|
||||||
modifier = Modifier.align(Alignment.BottomCenter)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (uiState.isLoading) {
|
if (uiState.isLoading) {
|
||||||
Box(
|
Box(
|
||||||
@@ -172,7 +187,10 @@ private fun MapScreenContent(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun AirMQMap(
|
private fun AirMQMap(
|
||||||
items: List<MapMarker>,
|
items: List<MapMarker>,
|
||||||
onMarkerClick: (String) -> Unit
|
onMarkerClick: (String) -> Unit,
|
||||||
|
centerOnMarker: MapMarker? = null,
|
||||||
|
sheetHeightFraction: Float = 0f,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val lifecycleOwner = LocalLifecycleOwner.current
|
val lifecycleOwner = LocalLifecycleOwner.current
|
||||||
@@ -202,8 +220,31 @@ private fun AirMQMap(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val mapAnimationSpeedMs = 200L
|
||||||
|
LaunchedEffect(centerOnMarker, sheetHeightFraction) {
|
||||||
|
centerOnMarker?.let { marker ->
|
||||||
|
val markerGeo = GeoPoint(marker.latitude, marker.longitude)
|
||||||
|
val zoomLevel = 15.5
|
||||||
|
if (sheetHeightFraction > 0f) {
|
||||||
|
mapView.post {
|
||||||
|
val height = mapView.height
|
||||||
|
val width = mapView.width
|
||||||
|
if (height > 0 && width > 0) {
|
||||||
|
val sheetHeightPx = (height * sheetHeightFraction).toInt()
|
||||||
|
val offsetCenterY = height / 2 + sheetHeightPx / 2
|
||||||
|
val projection = mapView.projection
|
||||||
|
val offsetGeo = projection.fromPixels(width / 2, offsetCenterY)
|
||||||
|
mapView.controller.animateTo(offsetGeo, zoomLevel, mapAnimationSpeedMs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mapView.controller.animateTo(markerGeo, zoomLevel, mapAnimationSpeedMs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AndroidView(
|
AndroidView(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
factory = { mapView },
|
factory = { mapView },
|
||||||
update = { map ->
|
update = { map ->
|
||||||
map.overlays.removeAll { it is Marker }
|
map.overlays.removeAll { it is Marker }
|
||||||
@@ -226,8 +267,14 @@ private fun AirMQMap(
|
|||||||
map.overlays.add(marker)
|
map.overlays.add(marker)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (centerOnMarker == null) {
|
||||||
items.firstOrNull()?.let { first ->
|
items.firstOrNull()?.let { first ->
|
||||||
map.controller.animateTo(GeoPoint(first.latitude, first.longitude))
|
map.controller.animateTo(
|
||||||
|
GeoPoint(first.latitude, first.longitude),
|
||||||
|
map.zoomLevelDouble,
|
||||||
|
200L
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
map.invalidate()
|
map.invalidate()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,9 @@ fun AirMQNavGraph(modifier: Modifier = Modifier) {
|
|||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
SideEffect {
|
SideEffect {
|
||||||
val window = (view.context as? Activity)?.window ?: return@SideEffect
|
val window = (view.context as? Activity)?.window ?: return@SideEffect
|
||||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !showBottomBar
|
// Map: dark icons (light map background); Dashboard/Manage: white icons (dark nav bar)
|
||||||
|
val lightStatusBars = currentRoute == AirMqRoutes.MAP || !showBottomBar
|
||||||
|
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = lightStatusBars
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
|||||||
Reference in New Issue
Block a user