expandable cards

This commit is contained in:
Henry Hiles 2023-04-12 10:43:32 -04:00
parent dc1d3328cb
commit a13db7aa7d
7 changed files with 84 additions and 50 deletions

View file

@ -12,22 +12,17 @@ import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import kotlin.math.roundToInt
private data class IndexedHourlyWeatherData(val index: Int, val data: HourlyWeatherData)
fun HourlyWeatherDataDto.toHourlyWeatherDataMap(): Map<Int, List<HourlyWeatherData>> {
return time.mapIndexed { index, time ->
IndexedHourlyWeatherData(
index = index,
data = HourlyWeatherData(
time = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME),
temperature = temperature[index].roundToInt(),
apparentTemperature = apparentTemperature[index].roundToInt(),
windSpeed = windSpeed[index].roundToInt(),
precipitationProbability = precipitationProbability.getOrNull(index),
weatherType = WeatherType.fromWMO(weatherCode[index])
)
fun HourlyWeatherDataDto.toHourlyWeatherDataMap(): List<HourlyWeatherData> {
return time.subList(0, 24).mapIndexed { index, time ->
HourlyWeatherData(
time = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME),
temperature = temperature[index].roundToInt(),
apparentTemperature = apparentTemperature[index].roundToInt(),
windSpeed = windSpeed[index].roundToInt(),
precipitationProbability = precipitationProbability.getOrNull(index),
weatherType = WeatherType.fromWMO(weatherCode[index])
)
}.groupBy { it.index / 24 }.mapValues { entry -> entry.value.map { it.data } }
}
}
fun DailyWeatherDataDto.toDailyWeatherDataMap(): List<DailyWeatherData> {
@ -48,11 +43,11 @@ fun DailyWeatherDataDto.toDailyWeatherDataMap(): List<DailyWeatherData> {
fun WeatherDto.toHourlyWeatherInfo(): HourlyWeatherInfo {
val weatherDataMap = hourlyWeatherData.toHourlyWeatherDataMap()
val now = LocalDateTime.now()
val currentWeatherData = weatherDataMap[0]?.find {
val currentWeatherData = weatherDataMap.find {
it.time.hour == now.hour
}
return HourlyWeatherInfo(
weatherDataPerDay = weatherDataMap,
weatherData = weatherDataMap,
currentWeatherData = currentWeatherData
)
}

View file

@ -1,6 +1,6 @@
package com.henryhiles.qweather.domain.weather
data class HourlyWeatherInfo(
val weatherDataPerDay: Map<Int, List<HourlyWeatherData>>,
val weatherData: List<HourlyWeatherData>,
val currentWeatherData: HourlyWeatherData?
)

View file

@ -18,12 +18,12 @@ import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.henryhiles.qweather.R
import com.henryhiles.qweather.presentation.screenmodel.HourlyWeatherState
import com.henryhiles.qweather.domain.weather.HourlyWeatherData
import java.time.format.DateTimeFormatter
@Composable
fun WeatherCard(state: HourlyWeatherState, modifier: Modifier = Modifier) {
state.hourlyWeatherInfo?.currentWeatherData?.let {
fun WeatherCard(hour: HourlyWeatherData?, modifier: Modifier = Modifier) {
hour?.let {
val formattedTime = remember(it) {
it.time.format(DateTimeFormatter.ofPattern("HH:mm"))
}

View file

@ -2,7 +2,7 @@ package com.henryhiles.qweather.presentation.components.weather
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -14,8 +14,12 @@ import com.henryhiles.qweather.presentation.screenmodel.HourlyWeatherState
import java.time.LocalDateTime
@Composable
fun WeatherForecast(state: HourlyWeatherState, modifier: Modifier = Modifier) {
state.hourlyWeatherInfo?.weatherDataPerDay?.get(0)?.let {
fun WeatherForecast(
state: HourlyWeatherState,
modifier: Modifier = Modifier,
onChangeSelected: (Int) -> Unit
) {
state.hourlyWeatherInfo?.weatherData?.let {
Column(
modifier = modifier
.fillMaxWidth()
@ -26,12 +30,12 @@ fun WeatherForecast(state: HourlyWeatherState, modifier: Modifier = Modifier) {
val rowState = rememberLazyListState(LocalDateTime.now().hour)
LazyRow(state = rowState) {
items(it) {
itemsIndexed(it) { index, data ->
WeatherHour(
data = it,
data = data,
modifier = Modifier
.height(100.dp)
.padding(horizontal = 16.dp)
.padding(horizontal = 8.dp),
onChangeSelected = { onChangeSelected(index) }
)
}
}

View file

@ -1,13 +1,13 @@
package com.henryhiles.qweather.presentation.components.weather
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
@ -15,25 +15,50 @@ import com.henryhiles.qweather.domain.weather.HourlyWeatherData
import java.time.format.DateTimeFormatter
@Composable
fun WeatherHour(data: HourlyWeatherData, modifier: Modifier = Modifier) {
fun WeatherHour(
data: HourlyWeatherData,
modifier: Modifier = Modifier,
onChangeSelected: () -> Unit
) {
data.let {
val formattedTime = remember(it) {
it.time.format(DateTimeFormatter.ofPattern("HH:mm"))
}
Card(modifier = modifier.clickable {
onChangeSelected()
}) {
Column(
modifier = Modifier
.height(128.dp)
.padding(16.dp),
verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = CenterHorizontally
) {
Text(text = formattedTime)
Image(
painter = painterResource(id = it.weatherType.iconRes),
contentDescription = "Image of ${it.weatherType.weatherDesc}",
modifier = Modifier.width(40.dp)
)
Text(text = "${it.temperature}°C")
}
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceBetween
) {
Text(text = formattedTime)
Image(
painter = painterResource(id = it.weatherType.iconRes),
contentDescription = "Image of ${it.weatherType.weatherDesc}",
modifier = Modifier.width(40.dp)
)
Text(text = "${it.temperature}°C")
}
// Column(
// horizontalAlignment = Alignment.CenterHorizontally,
// verticalArrangement = Arrangement.SpaceBetween,
// modifier = modifier
// ) {
// Text(text = formattedTime)
// Image(
// painter = painterResource(id = it.weatherType.iconRes),
// contentDescription = "Image of ${it.weatherType.weatherDesc}",
// modifier = Modifier.width(40.dp)
// )
// Text(text = "${it.temperature}°C")
// }
}
}

View file

@ -17,7 +17,7 @@ data class HourlyWeatherState(
val hourlyWeatherInfo: HourlyWeatherInfo? = null,
val isLoading: Boolean = false,
val error: String? = null,
val expanded: Int? = null
val selected: Int? = null
)
class HourlyWeatherScreenModel constructor(
@ -30,7 +30,7 @@ class HourlyWeatherScreenModel constructor(
fun loadWeatherInfo(cache: Boolean = true) {
coroutineScope.launch {
state = state.copy(isLoading = true, error = null)
state = state.copy(isLoading = true, error = null, selected = null)
val currentLocation = locationTracker.getCurrentLocation()
currentLocation?.let { location ->
state = when (val result =
@ -43,7 +43,7 @@ class HourlyWeatherScreenModel constructor(
state.copy(
hourlyWeatherInfo = result.data,
isLoading = false,
error = null
error = null,
)
}
@ -63,4 +63,8 @@ class HourlyWeatherScreenModel constructor(
}
}
}
fun setSelected(index: Int) {
state = state.copy(selected = index)
}
}

View file

@ -87,9 +87,15 @@ object TodayTab : NavigationTab {
modifier = Modifier
.fillMaxSize()
) {
WeatherCard(state = weatherViewModel.state)
WeatherCard(
hour = weatherViewModel.state.selected?.let {
weatherViewModel.state.hourlyWeatherInfo?.weatherData?.get(it)
} ?: weatherViewModel.state.hourlyWeatherInfo?.currentWeatherData
)
Spacer(modifier = Modifier.height(16.dp))
WeatherForecast(state = weatherViewModel.state)
WeatherForecast(
state = weatherViewModel.state
) { weatherViewModel.setSelected(it) }
}
}
}