build: S04 day detail
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
package app.wetter.ui.screens
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
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.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.wetter.R
|
||||
import app.wetter.data.Fmt
|
||||
import app.wetter.data.Graph
|
||||
import app.wetter.data.Settings
|
||||
import app.wetter.data.Units
|
||||
import app.wetter.data.conditionOf
|
||||
import app.wetter.ui.components.DailyCapsules
|
||||
import app.wetter.ui.components.HourlyStrip
|
||||
import app.wetter.ui.components.conditionLabel
|
||||
import app.wetter.ui.scene.WeatherIcon
|
||||
import app.wetter.ui.theme.WSpace
|
||||
import app.wetter.ui.theme.WType
|
||||
import java.time.LocalDate
|
||||
|
||||
/** S04: one day, picked from the capsule row. */
|
||||
@Composable
|
||||
fun DayScreen(locationId: Long, initialDate: LocalDate, settings: Settings, onBack: () -> Unit) {
|
||||
val forecast by remember(locationId) { Graph.repo.forecast(locationId) }.collectAsState(initial = null)
|
||||
val location by produceState<app.wetter.data.LocationEntity?>(null, locationId) { value = Graph.repo.location(locationId) }
|
||||
val f = forecast ?: return
|
||||
DayContent(f, location?.name?.ifBlank { null }, initialDate, settings, onBack)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DayContent(f: app.wetter.data.Forecast, placeName: String?, initialDate: LocalDate, settings: Settings, onBack: () -> Unit) {
|
||||
var date by rememberSaveable { mutableStateOf(initialDate.toEpochDay()) }
|
||||
val units = remember(settings) { Units(settings) }
|
||||
val day = f.daily.firstOrNull { it.date.toEpochDay() == date } ?: f.daily.first()
|
||||
val cond = conditionOf(day.code)
|
||||
val onBg = MaterialTheme.colorScheme.onBackground
|
||||
|
||||
Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) {
|
||||
LazyColumn(
|
||||
Modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(bottom = WSpace.s32),
|
||||
verticalArrangement = Arrangement.spacedBy(WSpace.s16),
|
||||
) {
|
||||
item {
|
||||
Row(Modifier.statusBarsPadding().height(64.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
IconButton(onClick = onBack) { Icon(Icons.AutoMirrored.Rounded.ArrowBack, stringResource(R.string.back), tint = onBg) }
|
||||
Text(stringResource(R.string.daily), style = WType.headline, color = onBg)
|
||||
}
|
||||
}
|
||||
item { DailyCapsules(f.daily, units, selected = day.date, asSection = false) { date = it.date.toEpochDay() } }
|
||||
item {
|
||||
Column(Modifier.padding(horizontal = WSpace.s24)) {
|
||||
Text(Fmt.longDate(day.date), style = WType.bodySm, color = onBg)
|
||||
Text(placeName ?: stringResource(R.string.current_location), style = WType.headline, color = onBg)
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("${units.temp(day.tMax)}/${units.temp(day.tMin)}", style = WType.dayRange, color = onBg)
|
||||
Spacer(Modifier.width(WSpace.s8))
|
||||
WeatherIcon(cond, true, 56.dp)
|
||||
}
|
||||
Text(stringResource(conditionLabel(cond, true)), style = WType.body, color = onBg)
|
||||
}
|
||||
}
|
||||
item {
|
||||
val hours = if (day.date == f.now.toLocalDate()) f.upcomingHours(24).filter { it.time.toLocalDate() == day.date } else f.hoursOf(day.date)
|
||||
HourlyStrip(hours, units, Modifier.padding(horizontal = WSpace.s16).widthIn(max = 720.dp), markNow = day.date == f.now.toLocalDate())
|
||||
}
|
||||
item {
|
||||
// the day's own values for the tiles that make sense per day
|
||||
val dayHours = f.hoursOf(day.date)
|
||||
val noon = dayHours.getOrNull(12)
|
||||
val cur = if (day.date == f.now.toLocalDate() || noon == null) f.current else f.current.copy(
|
||||
temp = noon.temp, code = noon.code, isDay = true, humidity = noon.humidity, windSpeed = noon.windSpeed, uv = day.uvMax,
|
||||
)
|
||||
app.wetter.ui.components.DetailGrid(
|
||||
cur, day, if (day.date == f.now.toLocalDate()) f.air else null, units,
|
||||
if (day.date == f.now.toLocalDate()) f.now else day.date.atTime(12, 0),
|
||||
Modifier.padding(horizontal = WSpace.s16).navigationBarsPadding().widthIn(max = 720.dp).fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user