feat: add AQI/RAD help dialog on map screen

This commit is contained in:
2026-03-16 16:45:48 +01:00
parent 3c41b0d487
commit fee67c35af
5 changed files with 98 additions and 8 deletions

View File

@@ -119,19 +119,17 @@ private fun MapScreenContent(
MapTopControls( MapTopControls(
selectedSensor = uiState.selectedTopSensor, selectedSensor = uiState.selectedTopSensor,
onSensorSelected = { onEvent(Event.TopSensorSelected(it)) }, onSensorSelected = { onEvent(Event.TopSensorSelected(it)) },
onHelpClick = { onHelpClick = { onEvent(Event.HelpClicked) },
Toast.makeText(
context,
context.getString(R.string.text_what_does_it_mean_title),
Toast.LENGTH_SHORT
).show()
},
modifier = Modifier modifier = Modifier
.align(Alignment.TopEnd) .align(Alignment.TopEnd)
.statusBarsPadding() .statusBarsPadding()
.padding(top = 20.dp, end = 16.dp) .padding(top = 20.dp, end = 16.dp)
) )
if (uiState.showHelpDialog) {
WhatDoesThisMeanDialog(onDismiss = { onEvent(Event.HelpDialogDismissed) })
}
if (uiState.searchPanelState == null && uiState.devicePanelState == null) { if (uiState.searchPanelState == null && uiState.devicePanelState == null) {
MapFloatingActions( MapFloatingActions(
onSearchClick = { onEvent(Event.SearchButtonClicked) }, onSearchClick = { onEvent(Event.SearchButtonClicked) },

View File

@@ -51,7 +51,8 @@ object MapScreenContract {
val selectedTopSensor: SensorType = SensorType.DUST, val selectedTopSensor: SensorType = SensorType.DUST,
val searchPanelState: SearchPanelState? = null, val searchPanelState: SearchPanelState? = null,
val devicePanelState: DevicePanelState? = null, val devicePanelState: DevicePanelState? = null,
val selectedMarkerId: String? = null val selectedMarkerId: String? = null,
val showHelpDialog: Boolean = false
) )
sealed interface Action { sealed interface Action {
@@ -67,6 +68,8 @@ object MapScreenContract {
data class SearchResultClicked(val resultId: String) : Event data class SearchResultClicked(val resultId: String) : Event
data object MyLocationClicked : Event data object MyLocationClicked : Event
data class TopSensorSelected(val sensor: SensorType) : Event data class TopSensorSelected(val sensor: SensorType) : Event
data object HelpClicked : Event
data object HelpDialogDismissed : Event
data class MarkerClicked(val itemId: String) : Event data class MarkerClicked(val itemId: String) : Event
data object DevicePanelClosed : Event data object DevicePanelClosed : Event
data object DeviceOpenClicked : Event data object DeviceOpenClicked : Event

View File

@@ -1,5 +1,6 @@
package org.db3.airmq.features.map package org.db3.airmq.features.map
import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@@ -12,10 +13,13 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
@@ -27,6 +31,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.expandVertically import androidx.compose.animation.expandVertically
@@ -38,6 +43,10 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
@@ -220,6 +229,78 @@ fun MapTopControls(
} }
} }
@Composable
fun WhatDoesThisMeanDialog(
onDismiss: () -> Unit
) {
Dialog(onDismissRequest = onDismiss) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 32.dp, vertical = 128.dp),
shape = RoundedCornerShape(24.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)
) {
Column(
modifier = Modifier.padding(24.dp)
) {
Text(
text = stringResource(id = R.string.text_what_does_it_mean_title),
style = MaterialTheme.typography.titleMedium,
fontSize = 16.sp,
fontWeight = FontWeight.Medium,
modifier = Modifier.padding(bottom = 22.dp)
)
Column(
modifier = Modifier
.heightIn(max = 400.dp)
.verticalScroll(rememberScrollState())
.padding(horizontal = 0.dp)
) {
Text(
text = stringResource(id = R.string.text_aqi_title),
style = MaterialTheme.typography.bodyLarge,
fontSize = 16.sp,
fontWeight = FontWeight.Medium
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = stringResource(id = R.string.text_aqi),
style = MaterialTheme.typography.bodyMedium
)
Spacer(modifier = Modifier.height(8.dp))
Image(
painter = painterResource(id = R.drawable.aqi_table),
contentDescription = null,
contentScale = ContentScale.Fit,
modifier = Modifier
.width(300.dp)
.height(150.dp)
)
Spacer(modifier = Modifier.height(20.dp))
Text(
text = stringResource(id = R.string.text_rad_title),
style = MaterialTheme.typography.bodyLarge,
fontSize = 16.sp,
fontWeight = FontWeight.Medium
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = stringResource(id = R.string.text_rad),
style = MaterialTheme.typography.bodyMedium
)
}
TextButton(
onClick = onDismiss,
modifier = Modifier.align(Alignment.End)
) {
Text(stringResource(id = R.string.button_ok))
}
}
}
}
}
@Composable @Composable
private fun SensorTypeItem( private fun SensorTypeItem(
iconRes: Int, iconRes: Int,

View File

@@ -96,6 +96,14 @@ class MapViewModel @Inject constructor(
remapMarkers() remapMarkers()
} }
Event.HelpClicked -> {
_uiState.value = _uiState.value.copy(showHelpDialog = true)
}
Event.HelpDialogDismissed -> {
_uiState.value = _uiState.value.copy(showHelpDialog = false)
}
is Event.MarkerClicked -> { is Event.MarkerClicked -> {
val selectedItem = _uiState.value.items.firstOrNull { it.id == event.itemId } ?: return val selectedItem = _uiState.value.items.firstOrNull { it.id == event.itemId } ?: return
_uiState.value = _uiState.value.copy( _uiState.value = _uiState.value.copy(

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB