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.overlay.Marker
|
||||
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.drawable.toDrawable
|
||||
|
||||
@@ -83,6 +86,7 @@ fun MapScreen(
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun MapScreenContent(
|
||||
uiState: State,
|
||||
@@ -90,12 +94,19 @@ private fun MapScreenContent(
|
||||
showMap: Boolean
|
||||
) {
|
||||
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()) {
|
||||
if (showMap) {
|
||||
AirMQMap(
|
||||
items = uiState.items,
|
||||
onMarkerClick = { onEvent(Event.MarkerClicked(it)) }
|
||||
onMarkerClick = { onEvent(Event.MarkerClicked(it)) },
|
||||
centerOnMarker = centerOnMarker,
|
||||
sheetHeightFraction = sheetHeightFraction,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
} else {
|
||||
Box(
|
||||
@@ -143,16 +154,20 @@ private fun MapScreenContent(
|
||||
}
|
||||
|
||||
uiState.devicePanelState?.let { panelData ->
|
||||
MapDevicePanel(
|
||||
data = panelData,
|
||||
onClose = { onEvent(Event.DevicePanelClosed) },
|
||||
onOpenDevice = { onEvent(Event.DeviceOpenClicked) },
|
||||
onRangeSelected = { onEvent(Event.TimeRangeSelected(it)) },
|
||||
onDateBack = { onEvent(Event.DateBackClicked) },
|
||||
onDateForward = { onEvent(Event.DateForwardClicked) },
|
||||
onSensorSelected = { onEvent(Event.DeviceSensorSelected(it)) },
|
||||
modifier = Modifier.align(Alignment.BottomCenter)
|
||||
)
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = { onEvent(Event.DevicePanelClosed) },
|
||||
sheetState = sheetState
|
||||
) {
|
||||
MapDevicePanelContent(
|
||||
data = panelData,
|
||||
onOpenDevice = { onEvent(Event.DeviceOpenClicked) },
|
||||
onRangeSelected = { onEvent(Event.TimeRangeSelected(it)) },
|
||||
onDateBack = { onEvent(Event.DateBackClicked) },
|
||||
onDateForward = { onEvent(Event.DateForwardClicked) },
|
||||
onSensorSelected = { onEvent(Event.DeviceSensorSelected(it)) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.isLoading) {
|
||||
@@ -172,7 +187,10 @@ private fun MapScreenContent(
|
||||
@Composable
|
||||
private fun AirMQMap(
|
||||
items: List<MapMarker>,
|
||||
onMarkerClick: (String) -> Unit
|
||||
onMarkerClick: (String) -> Unit,
|
||||
centerOnMarker: MapMarker? = null,
|
||||
sheetHeightFraction: Float = 0f,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val context = LocalContext.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(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
modifier = modifier.fillMaxSize(),
|
||||
factory = { mapView },
|
||||
update = { map ->
|
||||
map.overlays.removeAll { it is Marker }
|
||||
@@ -226,8 +267,14 @@ private fun AirMQMap(
|
||||
map.overlays.add(marker)
|
||||
}
|
||||
|
||||
items.firstOrNull()?.let { first ->
|
||||
map.controller.animateTo(GeoPoint(first.latitude, first.longitude))
|
||||
if (centerOnMarker == null) {
|
||||
items.firstOrNull()?.let { first ->
|
||||
map.controller.animateTo(
|
||||
GeoPoint(first.latitude, first.longitude),
|
||||
map.zoomLevelDouble,
|
||||
200L
|
||||
)
|
||||
}
|
||||
}
|
||||
map.invalidate()
|
||||
}
|
||||
|
||||
@@ -71,7 +71,9 @@ fun AirMQNavGraph(modifier: Modifier = Modifier) {
|
||||
val view = LocalView.current
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user