fix #23: Show date of weather data in weather forecast, main menu (#24)

* fix #23: Show date of weather data in weather forecast, main menu

* Use localized date format
This commit is contained in:
timklge 2025-01-17 18:01:02 +01:00 committed by GitHub
parent a948ed4561
commit 69626dce67
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 59 additions and 19 deletions

View File

@ -39,6 +39,7 @@ import kotlinx.coroutines.launch
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import kotlin.math.roundToInt
@OptIn(ExperimentalGlanceRemoteViewsApi::class)
@ -99,6 +100,8 @@ class WeatherDataType(
val interpretation = WeatherInterpretation.fromWeatherCode(data.current.weatherCode)
val formattedTime = timeFormatter.format(Instant.ofEpochSecond(data.current.time))
val formattedDate = Instant.ofEpochSecond(data.current.time).atZone(ZoneId.systemDefault()).toLocalDate().format(DateTimeFormatter.ofLocalizedDate(
FormatStyle.SHORT))
val result = glance.compose(context, DpSize.Unspecified) {
Box(modifier = GlanceModifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) {
@ -114,11 +117,13 @@ class WeatherDataType(
temperature = data.current.temperature.roundToInt(),
temperatureUnit = if (userProfile?.preferredUnit?.temperature != UserProfile.PreferredUnit.UnitType.IMPERIAL) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
timeLabel = formattedTime,
dateLabel = formattedDate,
rowAlignment = when (config.alignment){
ViewConfig.Alignment.LEFT -> Alignment.Horizontal.Start
ViewConfig.Alignment.CENTER -> Alignment.Horizontal.CenterHorizontally
ViewConfig.Alignment.RIGHT -> Alignment.Horizontal.End
}
},
singleDisplay = true
)
}
}

View File

@ -55,6 +55,7 @@ import kotlinx.coroutines.launch
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import kotlin.math.roundToInt
class CycleHoursAction : ActionCallback {
@ -139,6 +140,13 @@ class WeatherForecastDataType(
Row(modifier = GlanceModifier.fillMaxSize().clickable(onClick = actionRunCallback<CycleHoursAction>()), horizontalAlignment = Alignment.Horizontal.CenterHorizontally) {
val hourOffset = widgetSettings?.currentForecastHourOffset ?: 0
var previousDate: String? = let {
val unixTime = data.forecastData.time.firstOrNull()
val formattedDate = unixTime?.let { Instant.ofEpochSecond(it).atZone(ZoneId.systemDefault()).toLocalDate().toString() }
formattedDate
}
for (index in hourOffset..hourOffset + 2){
if (index >= data.forecastData.weatherCode.size) {
break
@ -155,6 +163,8 @@ class WeatherForecastDataType(
val interpretation = WeatherInterpretation.fromWeatherCode(data.forecastData.weatherCode[index])
val unixTime = data.forecastData.time[index]
val formattedTime = timeFormatter.format(Instant.ofEpochSecond(unixTime))
val formattedDate = Instant.ofEpochSecond(unixTime).atZone(ZoneId.systemDefault()).toLocalDate().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT))
val hasNewDate = formattedDate != previousDate || index == 0
Weather(baseBitmap,
current = interpretation,
@ -167,8 +177,11 @@ class WeatherForecastDataType(
precipitationUnit = if (userProfile?.preferredUnit?.distance != UserProfile.PreferredUnit.UnitType.IMPERIAL) PrecipitationUnit.MILLIMETERS else PrecipitationUnit.INCH,
temperature = data.forecastData.temperature[index].roundToInt(),
temperatureUnit = if (userProfile?.preferredUnit?.temperature != UserProfile.PreferredUnit.UnitType.IMPERIAL) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
timeLabel = formattedTime
timeLabel = formattedTime,
dateLabel = if (hasNewDate) formattedDate else null
)
previousDate = formattedDate
}
}
}

View File

@ -17,9 +17,12 @@ import androidx.glance.layout.ContentScale
import androidx.glance.layout.Row
import androidx.glance.layout.Spacer
import androidx.glance.layout.fillMaxHeight
import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.height
import androidx.glance.layout.padding
import androidx.glance.layout.width
import androidx.glance.layout.wrapContentWidth
import androidx.glance.preview.ExperimentalGlancePreviewApi
import androidx.glance.preview.Preview
import androidx.glance.text.FontFamily
@ -51,14 +54,15 @@ fun getWeatherIcon(interpretation: WeatherInterpretation): Int {
@Composable
fun Weather(baseBitmap: Bitmap, current: WeatherInterpretation, windBearing: Int, windSpeed: Int, windGusts: Int, windSpeedUnit: WindUnit,
precipitation: Double, precipitationProbability: Int?, precipitationUnit: PrecipitationUnit,
temperature: Int, temperatureUnit: TemperatureUnit, timeLabel: String? = null, rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally) {
temperature: Int, temperatureUnit: TemperatureUnit, timeLabel: String? = null, rowAlignment: Alignment.Horizontal = Alignment.Horizontal.CenterHorizontally,
dateLabel: String? = null, singleDisplay: Boolean = false) {
val fontSize = 14f
Column(modifier = GlanceModifier.fillMaxHeight().padding(2.dp).width(85.dp), horizontalAlignment = rowAlignment) {
Row(modifier = GlanceModifier.defaultWeight(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) {
Column(modifier = if (singleDisplay) GlanceModifier.fillMaxSize().padding(1.dp) else GlanceModifier.fillMaxHeight().padding(1.dp).width(86.dp), horizontalAlignment = rowAlignment) {
Row(modifier = GlanceModifier.defaultWeight().wrapContentWidth(), horizontalAlignment = rowAlignment, verticalAlignment = Alignment.CenterVertically) {
Image(
modifier = GlanceModifier.defaultWeight(),
modifier = GlanceModifier.defaultWeight().wrapContentWidth().padding(1.dp),
provider = ImageProvider(getWeatherIcon(current)),
contentDescription = "Current weather information",
contentScale = ContentScale.Fit,
@ -66,6 +70,19 @@ fun Weather(baseBitmap: Bitmap, current: WeatherInterpretation, windBearing: Int
)
}
if (dateLabel != null && !singleDisplay){
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = dateLabel,
style = TextStyle(
color = ColorProvider(Color.Black, Color.White),
fontFamily = FontFamily.Monospace,
fontSize = TextUnit(fontSize, TextUnitType.Sp)
)
)
}
}
Row(verticalAlignment = Alignment.CenterVertically, horizontalAlignment = rowAlignment) {
if (timeLabel != null){
Text(
@ -78,7 +95,7 @@ fun Weather(baseBitmap: Bitmap, current: WeatherInterpretation, windBearing: Int
}
Image(
modifier = GlanceModifier.height(20.dp).width(12.dp),
modifier = GlanceModifier.height(16.dp).width(12.dp).padding(1.dp),
provider = ImageProvider(R.drawable.thermometer),
contentDescription = "Temperature",
contentScale = ContentScale.Fit,
@ -91,14 +108,16 @@ fun Weather(baseBitmap: Bitmap, current: WeatherInterpretation, windBearing: Int
)
}
Row(verticalAlignment = Alignment.CenterVertically, horizontalAlignment = rowAlignment) {
/* Image(
modifier = GlanceModifier.height(20.dp).width(12.dp),
provider = ImageProvider(R.drawable.water_regular),
contentDescription = "Rain",
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White))
) */
Row(verticalAlignment = Alignment.CenterVertically, horizontalAlignment = rowAlignment, modifier = GlanceModifier.fillMaxWidth()) {
if (dateLabel != null && singleDisplay){
Text(
text = "$dateLabel",
style = TextStyle(color = ColorProvider(Color.Black, Color.White),
fontFamily = FontFamily.Monospace, fontSize = TextUnit(fontSize, TextUnitType.Sp))
)
Spacer(modifier = GlanceModifier.width(5.dp))
}
val precipitationProbabilityLabel = if (precipitationProbability != null) "${precipitationProbability}%," else ""
Text(
@ -109,7 +128,7 @@ fun Weather(baseBitmap: Bitmap, current: WeatherInterpretation, windBearing: Int
Spacer(modifier = GlanceModifier.width(5.dp))
Image(
modifier = GlanceModifier.height(20.dp).width(12.dp),
modifier = GlanceModifier.height(16.dp).width(12.dp).padding(1.dp),
provider = ImageProvider(getArrowBitmapByBearing(baseBitmap, windBearing + 180)),
contentDescription = "Current wind direction",
contentScale = ContentScale.Fit,

View File

@ -222,16 +222,19 @@ fun MainScreen() {
if (stats.failedWeatherRequest != null && (stats.lastSuccessfulWeatherRequest == null || stats.failedWeatherRequest!! > stats.lastSuccessfulWeatherRequest!!)){
val successfulTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(stats.lastSuccessfulWeatherRequest ?: 0), ZoneOffset.systemDefault()).toLocalTime().truncatedTo(
ChronoUnit.SECONDS)
val successfulDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(stats.lastSuccessfulWeatherRequest ?: 0), ZoneOffset.systemDefault()).toLocalDate()
val lastTryTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(stats.failedWeatherRequest ?: 0), ZoneOffset.systemDefault()).toLocalTime().truncatedTo(
ChronoUnit.SECONDS)
val lastTryDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(stats.failedWeatherRequest ?: 0), ZoneOffset.systemDefault()).toLocalDate()
val successStr = if(lastPosition != null) " Last data received at ${successfulTime}${lastPositionDistanceStr}." else ""
Text(modifier = Modifier.padding(5.dp), text = "Failed to update weather data; last try at ${lastTryTime}.${successStr}")
val successStr = if(lastPosition != null) " Last data received at $successfulDate ${successfulTime}${lastPositionDistanceStr}." else ""
Text(modifier = Modifier.padding(5.dp), text = "Failed to update weather data; last try at $lastTryDate ${lastTryTime}.${successStr}")
} else if(stats.lastSuccessfulWeatherRequest != null){
val localDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(stats.lastSuccessfulWeatherRequest ?: 0), ZoneOffset.systemDefault()).toLocalDate()
val localTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(stats.lastSuccessfulWeatherRequest ?: 0), ZoneOffset.systemDefault()).toLocalTime().truncatedTo(
ChronoUnit.SECONDS)
Text(modifier = Modifier.padding(5.dp), text = "Last weather data received at ${localTime}${lastPositionDistanceStr}")
Text(modifier = Modifier.padding(5.dp), text = "Last weather data received at $localDate ${localTime}${lastPositionDistanceStr}")
} else {
Text(modifier = Modifier.padding(5.dp), text = "No weather data received yet, waiting for GPS fix...")
}