fix(ui): status bar layout and icons for Map, Dashboard, Manage
- Dashboard: apply background before statusBarsPadding so gradient extends under status bar - Map: add statusBarsPadding to layer selector so it no longer overlaps status bar - NavGraph: set white status bar icons (isAppearanceLightStatusBars=false) on main tab screens Made-with: Cursor
This commit is contained in:
@@ -7,27 +7,28 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import org.db3.airmq.R
|
||||
import org.db3.airmq.features.common.MockScreenScaffold
|
||||
import org.db3.airmq.features.common.metric.MetricGaugeRow
|
||||
import org.db3.airmq.features.common.metric.SensorType
|
||||
import org.db3.airmq.features.common.ScreenAction
|
||||
import org.db3.airmq.features.common.chart.AirMQChart
|
||||
import org.db3.airmq.features.common.chart.ChartConfig
|
||||
import org.db3.airmq.features.common.chart.ChartDataset
|
||||
import org.db3.airmq.features.common.chart.generateSineWaveData
|
||||
import org.db3.airmq.ui.theme.ChartBackground
|
||||
import org.db3.airmq.ui.theme.ChartFill
|
||||
import org.db3.airmq.features.common.metric.MetricGaugePager
|
||||
import org.db3.airmq.features.common.metric.SensorType
|
||||
import org.db3.airmq.ui.theme.AirMQTheme
|
||||
import org.db3.airmq.ui.theme.LegacyNavGradientEnd
|
||||
import org.db3.airmq.ui.theme.LegacyNavGradientStart
|
||||
|
||||
@@ -38,57 +39,105 @@ fun DashboardScreen(
|
||||
onOpenCity: () -> Unit,
|
||||
onOpenDevice: () -> Unit,
|
||||
onOpenNews: () -> Unit,
|
||||
onOpenWidgetConstructor: () -> Unit
|
||||
onOpenWidgetConstructor: () -> Unit,
|
||||
viewModel: DashboardViewModel = hiltViewModel()
|
||||
) {
|
||||
MockScreenScaffold(
|
||||
title = stringResource(id = R.string.title_dashboard),
|
||||
subtitle = stringResource(id = R.string.dashboard_subtitle),
|
||||
content = {
|
||||
var selectedSensor by remember { mutableStateOf<SensorType?>(SensorType.DUST) }
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
colors = listOf(LegacyNavGradientStart, LegacyNavGradientEnd)
|
||||
)
|
||||
)
|
||||
) {
|
||||
MetricGaugeRow(
|
||||
selectedSensor = selectedSensor,
|
||||
values = mapOf(
|
||||
SensorType.DUST to 6f,
|
||||
SensorType.RADIOACTIVITY to 0f,
|
||||
SensorType.TEMPERATURE to 3f
|
||||
),
|
||||
onGaugeSelected = { selectedSensor = it },
|
||||
modifier = Modifier.padding(vertical = 8.dp)
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(144.dp)
|
||||
) {
|
||||
AirMQChart(
|
||||
data = ChartDataset.Single(generateSineWaveData()),
|
||||
config = ChartConfig(
|
||||
lineColor = Color.White,
|
||||
fillColor = ChartFill,
|
||||
backgroundColor = ChartBackground,
|
||||
labelColor = Color.White,
|
||||
leftTimeLabel = stringResource(R.string.text_yesterday),
|
||||
rightTimeLabel = stringResource(R.string.text_now),
|
||||
unit = "°C"
|
||||
),
|
||||
sensorType = "sensor_temperature",
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
actions = listOf(
|
||||
ScreenAction(stringResource(id = R.string.dashboard_open_news), onOpenNews),
|
||||
ScreenAction(stringResource(id = R.string.manage_open_widget_constructor), onOpenWidgetConstructor)
|
||||
)
|
||||
val state by viewModel.uiState.collectAsState()
|
||||
DashboardContent(
|
||||
state = state,
|
||||
onEvent = viewModel::onEvent
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun DashboardContent(
|
||||
state: DashboardScreenContract.State,
|
||||
onEvent: (DashboardScreenContract.Event) -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
colors = listOf(LegacyNavGradientStart, LegacyNavGradientEnd)
|
||||
)
|
||||
)
|
||||
.statusBarsPadding()
|
||||
) {
|
||||
CitySelector(city = state.city, modifier = Modifier.padding(top = 12.dp))
|
||||
MetricGaugePager(
|
||||
selectedSensor = state.selectedSensor,
|
||||
values = state.gaugeValues,
|
||||
currentPage = state.currentPage,
|
||||
onGaugeSelected = { onEvent(DashboardScreenContract.Event.GaugeSelected(it)) },
|
||||
onPageChanged = { onEvent(DashboardScreenContract.Event.PageChanged(it)) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(144.dp)
|
||||
) {
|
||||
AirMQChart(
|
||||
data = state.chartData,
|
||||
config = state.chartConfig.copy(
|
||||
leftTimeLabel = stringResource(R.string.text_yesterday),
|
||||
rightTimeLabel = stringResource(R.string.text_now)
|
||||
),
|
||||
sensorType = state.selectedSensor.legacyKey,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CitySelector(
|
||||
city: String,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(44.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = city,
|
||||
color = Color.White,
|
||||
fontSize = 22.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, name = "Dashboard – dust selected")
|
||||
@Composable
|
||||
private fun PreviewDashboardDust() {
|
||||
AirMQTheme {
|
||||
DashboardContent(
|
||||
state = DashboardScreenContract.previewState(selectedSensor = SensorType.DUST),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, name = "Dashboard – page 2 humidity")
|
||||
@Composable
|
||||
private fun PreviewDashboardPage2() {
|
||||
AirMQTheme {
|
||||
DashboardContent(
|
||||
state = DashboardScreenContract.previewState(
|
||||
selectedSensor = SensorType.HUMIDITY,
|
||||
currentPage = 1
|
||||
),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
@@ -116,6 +117,7 @@ private fun MapScreenContent(
|
||||
},
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.statusBarsPadding()
|
||||
.padding(top = 20.dp, end = 16.dp)
|
||||
)
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package org.db3.airmq.features.navigation
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
@@ -13,6 +15,7 @@ import androidx.compose.material3.NavigationBarItemDefaults
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
@@ -25,6 +28,7 @@ import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import androidx.core.view.WindowCompat
|
||||
import org.db3.airmq.R
|
||||
import org.db3.airmq.features.city.CityScreen
|
||||
import org.db3.airmq.features.constructor.ChartConstructorScreen
|
||||
@@ -64,6 +68,12 @@ fun AirMQNavGraph(modifier: Modifier = Modifier) {
|
||||
val currentRoute = navBackStackEntry?.destination?.route
|
||||
val showBottomBar = currentRoute in tabRoutes
|
||||
|
||||
val view = LocalView.current
|
||||
SideEffect {
|
||||
val window = (view.context as? Activity)?.window ?: return@SideEffect
|
||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !showBottomBar
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
contentWindowInsets = WindowInsets(0, 0, 0, 0),
|
||||
|
||||
Reference in New Issue
Block a user