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

View file

@ -1,6 +1,6 @@
package com.henryhiles.qweather.domain.weather package com.henryhiles.qweather.domain.weather
data class HourlyWeatherInfo( data class HourlyWeatherInfo(
val weatherDataPerDay: Map<Int, List<HourlyWeatherData>>, val weatherData: List<HourlyWeatherData>,
val currentWeatherData: 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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.henryhiles.qweather.R import com.henryhiles.qweather.R
import com.henryhiles.qweather.presentation.screenmodel.HourlyWeatherState import com.henryhiles.qweather.domain.weather.HourlyWeatherData
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@Composable @Composable
fun WeatherCard(state: HourlyWeatherState, modifier: Modifier = Modifier) { fun WeatherCard(hour: HourlyWeatherData?, modifier: Modifier = Modifier) {
state.hourlyWeatherInfo?.currentWeatherData?.let { hour?.let {
val formattedTime = remember(it) { val formattedTime = remember(it) {
it.time.format(DateTimeFormatter.ofPattern("HH:mm")) 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.layout.*
import androidx.compose.foundation.lazy.LazyRow 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.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -14,8 +14,12 @@ import com.henryhiles.qweather.presentation.screenmodel.HourlyWeatherState
import java.time.LocalDateTime import java.time.LocalDateTime
@Composable @Composable
fun WeatherForecast(state: HourlyWeatherState, modifier: Modifier = Modifier) { fun WeatherForecast(
state.hourlyWeatherInfo?.weatherDataPerDay?.get(0)?.let { state: HourlyWeatherState,
modifier: Modifier = Modifier,
onChangeSelected: (Int) -> Unit
) {
state.hourlyWeatherInfo?.weatherData?.let {
Column( Column(
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
@ -26,12 +30,12 @@ fun WeatherForecast(state: HourlyWeatherState, modifier: Modifier = Modifier) {
val rowState = rememberLazyListState(LocalDateTime.now().hour) val rowState = rememberLazyListState(LocalDateTime.now().hour)
LazyRow(state = rowState) { LazyRow(state = rowState) {
items(it) { itemsIndexed(it) { index, data ->
WeatherHour( WeatherHour(
data = it, data = data,
modifier = Modifier modifier = Modifier
.height(100.dp) .padding(horizontal = 8.dp),
.padding(horizontal = 16.dp) onChangeSelected = { onChangeSelected(index) }
) )
} }
} }

View file

@ -1,13 +1,13 @@
package com.henryhiles.qweather.presentation.components.weather package com.henryhiles.qweather.presentation.components.weather
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.width import androidx.compose.material3.Card
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember 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.Modifier
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -15,25 +15,50 @@ import com.henryhiles.qweather.domain.weather.HourlyWeatherData
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@Composable @Composable
fun WeatherHour(data: HourlyWeatherData, modifier: Modifier = Modifier) { fun WeatherHour(
data: HourlyWeatherData,
modifier: Modifier = Modifier,
onChangeSelected: () -> Unit
) {
data.let { data.let {
val formattedTime = remember(it) { val formattedTime = remember(it) {
it.time.format(DateTimeFormatter.ofPattern("HH:mm")) it.time.format(DateTimeFormatter.ofPattern("HH:mm"))
} }
Card(modifier = modifier.clickable {
onChangeSelected()
}) {
Column( Column(
modifier = modifier, modifier = Modifier
horizontalAlignment = Alignment.CenterHorizontally, .height(128.dp)
verticalArrangement = Arrangement.SpaceBetween .padding(16.dp),
verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = CenterHorizontally
) { ) {
Text(text = formattedTime) Text(text = formattedTime)
Image( Image(
painter = painterResource(id = it.weatherType.iconRes), painter = painterResource(id = it.weatherType.iconRes),
contentDescription = "Image of ${it.weatherType.weatherDesc}", contentDescription = "Image of ${it.weatherType.weatherDesc}",
modifier = Modifier.width(40.dp) modifier = Modifier.width(40.dp)
) )
Text(text = "${it.temperature}°C") 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 hourlyWeatherInfo: HourlyWeatherInfo? = null,
val isLoading: Boolean = false, val isLoading: Boolean = false,
val error: String? = null, val error: String? = null,
val expanded: Int? = null val selected: Int? = null
) )
class HourlyWeatherScreenModel constructor( class HourlyWeatherScreenModel constructor(
@ -30,7 +30,7 @@ class HourlyWeatherScreenModel constructor(
fun loadWeatherInfo(cache: Boolean = true) { fun loadWeatherInfo(cache: Boolean = true) {
coroutineScope.launch { coroutineScope.launch {
state = state.copy(isLoading = true, error = null) state = state.copy(isLoading = true, error = null, selected = null)
val currentLocation = locationTracker.getCurrentLocation() val currentLocation = locationTracker.getCurrentLocation()
currentLocation?.let { location -> currentLocation?.let { location ->
state = when (val result = state = when (val result =
@ -43,7 +43,7 @@ class HourlyWeatherScreenModel constructor(
state.copy( state.copy(
hourlyWeatherInfo = result.data, hourlyWeatherInfo = result.data,
isLoading = false, 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 modifier = Modifier
.fillMaxSize() .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)) Spacer(modifier = Modifier.height(16.dp))
WeatherForecast(state = weatherViewModel.state) WeatherForecast(
state = weatherViewModel.state
) { weatherViewModel.setSelected(it) }
} }
} }
} }