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