implement WindScreen, add click navigation to WindBlock closes #878

This commit is contained in:
PranshulGG committed 2026-06-03 22:33:50 +05:30
1 parent d8b7d6b351
commit 798fa10171
3 files changed
+201 -4

No files matched your search

@@ -0,0 +1,195 @@
package com.pranshulgg.weather_master_app.feature.blocks.screens
import android.content.Context
import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.navigation.NavController
import com.pranshulgg.weather_master_app.R
import com.pranshulgg.weather_master_app.core.model.weather.WindSpeedUnit
import com.pranshulgg.weather_master_app.core.model.weather.toName
import com.pranshulgg.weather_master_app.core.model.weather.wind.WindDirection
import com.pranshulgg.weather_master_app.core.prefs.LocalAppPrefs
import com.pranshulgg.weather_master_app.core.ui.components.Gap
import com.pranshulgg.weather_master_app.core.ui.components.LargeTopBarScaffold
import com.pranshulgg.weather_master_app.core.ui.components.NavigateUpBtn
import com.pranshulgg.weather_master_app.core.utils.formatters.to12HourTimeString
import com.pranshulgg.weather_master_app.core.utils.formatters.to24HourTimeString
import com.pranshulgg.weather_master_app.core.utils.formatters.toDateString
import com.pranshulgg.weather_master_app.core.utils.weather.forecast.findMatchingHourly
import com.pranshulgg.weather_master_app.feature.blocks.BlocksScreenViewModel
import com.pranshulgg.weather_master_app.feature.blocks.components.AboutCard
import com.pranshulgg.weather_master_app.feature.blocks.components.AboutCardText
import com.pranshulgg.weather_master_app.feature.blocks.components.MatBarChart
import kotlin.math.max
import kotlin.math.roundToInt
@Composable
fun WindScreen(navController: NavController, index: Int = 0, locationId: String) {
val viewModel: BlocksScreenViewModel = hiltViewModel()
LaunchedEffect(Unit) {
viewModel.getUnitsOnce()
viewModel.getWeather(locationId)
}
val uiState = viewModel.uiState.value
val weather = uiState.weather
val hourly = weather?.hourly ?: return
val units = uiState.units
val context = LocalContext.current
val fullDayHourly =
findMatchingHourly(hourly, weather.daily[index].time, weather.location.source)
val date = toDateString(weather.daily[index].time, weather.location.timezone)
val maxWind = weather.daily[index].windSpeed
val minWind = fullDayHourly.minOf { it.windSpeed ?: 0.0 }
val dayDirection = weather.daily[index].windDirection
LargeTopBarScaffold(
title = stringResource(R.string.weather_wind),
navigationIcon = { NavigateUpBtn(navController) },
actions = {
Text(
date,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(end = 16.dp)
)
}
) { paddingValues ->
Column(
modifier =
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(paddingValues)
) {
WindBarChart(
max = maxWind!!,
min = minWind,
times = fullDayHourly.map { it.time },
values = fullDayHourly.map { it.windSpeed ?: 0.0 },
directions = fullDayHourly.map { it.windDirection },
zoneId = weather.location.timezone,
unit = units.windUnit,
context = context,
dayDirection = dayDirection
)
Gap(14.dp)
AboutCard {
AboutCardText(stringResource(R.string.weather_about_windspeed))
}
}
}
}
@Composable
private fun WindBarChart(
max: Double,
min: Double,
times: List<Long>,
values: List<Double>,
directions: List<WindDirection?>,
dayDirection: WindDirection?,
zoneId: String,
unit: WindSpeedUnit,
context: Context
) {
val timeStartIndex = if (times.size == 12) 0 else 6
val is24hr = LocalAppPrefs.current.is24HrTimeFormat
val bottomValues = times.slice(timeStartIndex..times.lastIndex step 6)
val barHeights = values.map {
val percentage = ((it.minus(min)).div((max - min))).times(100)
max((percentage.div(100)).times(170).roundToInt(), 5)
}
val sideValues =
(min.roundToInt() until max.roundToInt()).sortedByDescending { it }
.map { "${WindSpeedUnit.KPH.convert(it.toDouble(), unit)?.roundToInt()}" }
val directions = directions.map {
WindDirection.toDegrees(it ?: WindDirection.N)
}
val steps = 7
val topValues = (0 until steps).map { i ->
val index = ((directions.size - 1) * i.toDouble() / (steps - 1)).toInt()
directions[index]
}
val barColor = values.map {
when {
it < 10 -> Color(0xFF42A5F5)
it < 20 -> Color(0xFF66BB6A)
it < 40 -> Color(0xFFFDD835)
it < 60 -> Color(0xFFFB8C00)
else -> Color(0xFFC62828)
}
}
MatBarChart(
topValues = topValues.map {
{
Image(
painter = painterResource(id = R.drawable.weather_wind_arrow_dominant),
contentDescription = "",
modifier = Modifier
.size(18.dp)
.rotate(it.toFloat()),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.primary)
)
}
},
bottomValues = bottomValues.map {
{
val time = if (is24hr) to24HourTimeString(
it,
zoneId
) else to12HourTimeString(it, zoneId)
Text(time, style = MaterialTheme.typography.labelMedium)
}
},
sideValues = sideValues,
values = values,
barHeights = barHeights,
barColor = barColor,
headerValue = "${WindSpeedUnit.KPH.convert(max, unit)?.roundToInt()}",
headerSuffix = "${unit.toName(context, true)} • $dayDirection",
headerTitle = stringResource(R.string.weather_max_for_the_day),
chartHeight = 250.dp
)
}
@@ -231,8 +231,8 @@ fun WeatherBlocks(
context,
isDaily,
dailyIndex,
units
)
units,
onClickBlock = { onClickBlock(NavRoutes.WIND) })
}
}
@@ -41,7 +41,8 @@ fun WindBlock(
context: Context,
isDaily: Boolean,
dailyIndex: Int,
units: WeatherUnits
units: WeatherUnits,
onClickBlock: () -> Unit
) {
val windDirection = if (isDaily) {
@@ -57,7 +58,8 @@ fun WindBlock(
Surface(
color = MaterialTheme.colorScheme.surface,
shape = RoundedCornerShape(ShapeRadius.Full),
shadowElevation = ShadowElevation.level2
shadowElevation = ShadowElevation.level2,
onClick = onClickBlock
) {
Box(
Modifier