Enlarge font in single date weather display (#55)

* Shorter date format

* Enlarge font size in single date weather widget and make clickable

* Fix off by one in route forecast

* Fix indentation lint
This commit is contained in:
timklge 2025-03-02 23:56:34 +01:00 committed by GitHub
parent e95e0c03f6
commit 7c28251b02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 150 additions and 140 deletions

View File

@ -163,7 +163,8 @@ class KarooHeadwindExtension : KarooExtension("karoo-headwind", "1.3") {
add(gps)
var currentPosition = positionOnRoute + calculatedDistanceToNextFullHour
var lastRequestedPosition = currentPosition
var lastRequestedPosition = positionOnRoute
while (currentPosition < upcomingRoute.routeLength && size < 10) {
val point = TurfMeasurement.along(
upcomingRoute.routePolyline,
@ -182,7 +183,7 @@ class KarooHeadwindExtension : KarooExtension("karoo-headwind", "1.3") {
currentPosition += distancePerHour
}
if (upcomingRoute.routeLength > lastRequestedPosition + 5_000) {
if (upcomingRoute.routeLength > lastRequestedPosition + 1_000) {
val point = TurfMeasurement.along(
upcomingRoute.routePolyline,
upcomingRoute.routeLength,

View File

@ -5,6 +5,8 @@ import android.graphics.BitmapFactory
import android.util.Log
import androidx.compose.ui.unit.DpSize
import androidx.glance.GlanceModifier
import androidx.glance.action.actionStartActivity
import androidx.glance.action.clickable
import androidx.glance.appwidget.ExperimentalGlanceRemoteViewsApi
import androidx.glance.appwidget.GlanceRemoteViews
import androidx.glance.layout.Alignment
@ -13,6 +15,7 @@ import androidx.glance.layout.fillMaxSize
import de.timklge.karooheadwind.HeadingResponse
import de.timklge.karooheadwind.HeadwindSettings
import de.timklge.karooheadwind.KarooHeadwindExtension
import de.timklge.karooheadwind.MainActivity
import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse
import de.timklge.karooheadwind.OpenMeteoData
import de.timklge.karooheadwind.TemperatureUnit
@ -43,7 +46,6 @@ 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)
@ -124,11 +126,13 @@ 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 formattedDate = getShortDateFormatter().format(Instant.ofEpochSecond(data.current.time))
val result = glance.compose(context, DpSize.Unspecified) {
Box(modifier = GlanceModifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) {
var modifier = GlanceModifier.fillMaxSize()
if (!config.preview) modifier = modifier.clickable(onClick = actionStartActivity<MainActivity>())
Box(modifier = modifier, contentAlignment = Alignment.CenterEnd) {
Weather(
baseBitmap,
current = interpretation,

View File

@ -165,7 +165,7 @@ class WeatherForecastDataType(
var previousDate: String? = let {
val unixTime = allData.getOrNull(positionOffset)?.data?.forecastData?.time?.getOrNull(hourOffset)
val formattedDate = unixTime?.let { Instant.ofEpochSecond(unixTime).atZone(ZoneId.systemDefault()).toLocalDate().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)) }
val formattedDate = unixTime?.let { getShortDateFormatter().format(Instant.ofEpochSecond(unixTime)) }
formattedDate
}
@ -182,8 +182,6 @@ class WeatherForecastDataType(
val distanceAlongRoute = allData.getOrNull(positionIndex)?.requestedPosition?.distanceAlongRoute
val position = allData.getOrNull(positionIndex)?.requestedPosition?.let { "${(it.distanceAlongRoute?.div(1000.0))?.toInt()} at ${it.lat}, ${it.lon}" }
Log.d(KarooHeadwindExtension.TAG, "Distance along route ${positionIndex}: $position")
if (baseIndex > hourOffset) {
Spacer(
modifier = GlanceModifier.fillMaxHeight().background(
@ -192,6 +190,8 @@ class WeatherForecastDataType(
)
}
Log.d(KarooHeadwindExtension.TAG, "Distance along route ${positionIndex}: $position")
val distanceFromCurrent = upcomingRoute?.distanceAlongRoute?.let { currentDistanceAlongRoute ->
distanceAlongRoute?.minus(currentDistanceAlongRoute)
}
@ -202,7 +202,7 @@ class WeatherForecastDataType(
val interpretation = WeatherInterpretation.fromWeatherCode(data.current.weatherCode)
val unixTime = data.current.time
val formattedTime = timeFormatter.format(Instant.ofEpochSecond(unixTime))
val formattedDate = Instant.ofEpochSecond(unixTime).atZone(ZoneId.systemDefault()).toLocalDate().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT))
val formattedDate = getShortDateFormatter().format(Instant.ofEpochSecond(unixTime))
val hasNewDate = formattedDate != previousDate || baseIndex == 0
Weather(
@ -225,7 +225,7 @@ class WeatherForecastDataType(
val interpretation = WeatherInterpretation.fromWeatherCode(data?.forecastData?.weatherCode?.get(baseIndex) ?: 0)
val unixTime = data?.forecastData?.time?.get(baseIndex) ?: 0
val formattedTime = timeFormatter.format(Instant.ofEpochSecond(unixTime))
val formattedDate = Instant.ofEpochSecond(unixTime).atZone(ZoneId.systemDefault()).toLocalDate().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT))
val formattedDate = getShortDateFormatter().format(Instant.ofEpochSecond(unixTime))
val hasNewDate = formattedDate != previousDate || baseIndex == 0
Weather(

View File

@ -24,7 +24,6 @@ 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
import androidx.glance.text.FontWeight
import androidx.glance.text.Text
@ -33,9 +32,19 @@ import androidx.glance.text.TextStyle
import de.timklge.karooheadwind.R
import de.timklge.karooheadwind.TemperatureUnit
import de.timklge.karooheadwind.WeatherInterpretation
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.Locale
import kotlin.math.absoluteValue
import kotlin.math.ceil
fun getShortDateFormatter(): DateTimeFormatter = DateTimeFormatter.ofPattern(
when (Locale.getDefault().country) {
"US" -> "MM/dd"
else -> "dd.MM"
}
).withZone(ZoneId.systemDefault())
fun getWeatherIcon(interpretation: WeatherInterpretation): Int {
return when (interpretation){
WeatherInterpretation.CLEAR -> R.drawable.bx_clear
@ -49,7 +58,6 @@ fun getWeatherIcon(interpretation: WeatherInterpretation): Int {
}
@OptIn(ExperimentalGlancePreviewApi::class)
@Preview(widthDp = 200, heightDp = 150)
@Composable
fun Weather(
baseBitmap: Bitmap,
@ -69,7 +77,7 @@ fun Weather(
isImperial: Boolean?
) {
val fontSize = 14f
val fontSize = if (singleDisplay) 19f else 14f
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) {
@ -130,7 +138,7 @@ fun Weather(
}
Image(
modifier = GlanceModifier.height(16.dp).width(12.dp).padding(1.dp),
modifier = if (singleDisplay) GlanceModifier.height(20.dp).width(16.dp) else GlanceModifier.height(16.dp).width(12.dp).padding(1.dp),
provider = ImageProvider(R.drawable.thermometer),
contentDescription = "Temperature",
contentScale = ContentScale.Fit,
@ -163,14 +171,13 @@ fun Weather(
Spacer(modifier = GlanceModifier.width(5.dp))
Image(
modifier = GlanceModifier.height(16.dp).width(12.dp).padding(1.dp),
modifier = if (singleDisplay) GlanceModifier.height(20.dp).width(16.dp) else GlanceModifier.height(16.dp).width(12.dp).padding(1.dp),
provider = ImageProvider(getArrowBitmapByBearing(baseBitmap, windBearing + 180)),
contentDescription = "Current wind direction",
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White))
)
Text(
text = "$windSpeed,${windGusts}",
style = TextStyle(color = ColorProvider(Color.Black, Color.White), fontFamily = FontFamily.Monospace, fontSize = TextUnit(fontSize, TextUnitType.Sp))

View File

@ -26,12 +26,12 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import de.timklge.karooheadwind.HeadwindStats
import de.timklge.karooheadwind.KarooHeadwindExtension
import de.timklge.karooheadwind.PrecipitationUnit
import de.timklge.karooheadwind.R
import de.timklge.karooheadwind.TemperatureUnit
import de.timklge.karooheadwind.WeatherInterpretation
import de.timklge.karooheadwind.datatypes.WeatherDataType.Companion.timeFormatter
import de.timklge.karooheadwind.datatypes.WeatherForecastDataType
import de.timklge.karooheadwind.datatypes.getShortDateFormatter
import de.timklge.karooheadwind.getGpsCoordinateFlow
import de.timklge.karooheadwind.streamCurrentWeatherData
import de.timklge.karooheadwind.streamStats
@ -41,10 +41,7 @@ import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.UserProfile
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.time.temporal.ChronoUnit
import kotlin.math.roundToInt
@ -91,15 +88,10 @@ fun WeatherScreen(onFinish: () -> Unit) {
val requestedWeatherPosition = weatherData.firstOrNull()?.requestedPosition
val formattedTime = currentWeatherData?.let { timeFormatter.format(Instant.ofEpochSecond(currentWeatherData.current.time)) }
val formattedDate = currentWeatherData?.let { Instant.ofEpochSecond(currentWeatherData.current.time).atZone(ZoneId.systemDefault()).toLocalDate().format(
DateTimeFormatter.ofLocalizedDate(
FormatStyle.SHORT))
}
val formattedDate = currentWeatherData?.let { getShortDateFormatter().format(Instant.ofEpochSecond(currentWeatherData.current.time)) }
if (karooConnected == true && currentWeatherData != null) {
WeatherWidget(
dateLabel = formattedDate,
timeLabel = formattedTime,
baseBitmap = baseBitmap,
current = WeatherInterpretation.fromWeatherCode(currentWeatherData.current.weatherCode),
windBearing = currentWeatherData.current.windDirection.roundToInt(),
@ -108,10 +100,11 @@ fun WeatherScreen(onFinish: () -> Unit) {
precipitation = currentWeatherData.current.precipitation,
temperature = currentWeatherData.current.temperature.toInt(),
temperatureUnit = if(profile?.preferredUnit?.temperature == UserProfile.PreferredUnit.UnitType.METRIC) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL,
precipitationUnit = if (profile?.preferredUnit?.distance != UserProfile.PreferredUnit.UnitType.IMPERIAL) PrecipitationUnit.MILLIMETERS else PrecipitationUnit.INCH,
timeLabel = formattedTime,
dateLabel = formattedDate,
distance = requestedWeatherPosition?.let { l -> location?.distanceTo(l)?.times(1000) },
includeDistanceLabel = false,
isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL,
)
}
@ -208,7 +201,7 @@ fun WeatherScreen(onFinish: () -> Unit) {
val interpretation = WeatherInterpretation.fromWeatherCode(data?.forecastData?.weatherCode?.get(index) ?: 0)
val unixTime = data?.forecastData?.time?.get(index) ?: 0
val formattedForecastTime = WeatherForecastDataType.timeFormatter.format(Instant.ofEpochSecond(unixTime))
val formattedForecastDate = Instant.ofEpochSecond(unixTime).atZone(ZoneId.systemDefault()).toLocalDate().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT))
val formattedForecastDate = getShortDateFormatter().format(Instant.ofEpochSecond(unixTime))
WeatherWidget(
baseBitmap,
@ -217,15 +210,14 @@ fun WeatherScreen(onFinish: () -> Unit) {
windSpeed = data?.forecastData?.windSpeed?.get(index)?.roundToInt() ?: 0,
windGusts = data?.forecastData?.windGusts?.get(index)?.roundToInt() ?: 0,
precipitation = data?.forecastData?.precipitation?.get(index) ?: 0.0,
precipitationProbability = data?.forecastData?.precipitationProbability?.get(index) ?: 0,
temperature = data?.forecastData?.temperature?.get(index)?.roundToInt() ?: 0,
temperatureUnit = if (profile?.preferredUnit?.temperature != UserProfile.PreferredUnit.UnitType.IMPERIAL) TemperatureUnit.CELSIUS else TemperatureUnit.FAHRENHEIT,
timeLabel = formattedForecastTime,
dateLabel = formattedForecastDate,
distance = distanceFromCurrent,
isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL,
precipitationUnit = if (profile?.preferredUnit?.distance != UserProfile.PreferredUnit.UnitType.IMPERIAL) PrecipitationUnit.MILLIMETERS else PrecipitationUnit.INCH,
includeDistanceLabel = true
includeDistanceLabel = true,
precipitationProbability = data?.forecastData?.precipitationProbability?.get(index) ?: 0,
isImperial = profile?.preferredUnit?.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
)
}

View File

@ -23,7 +23,6 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import de.timklge.karooheadwind.PrecipitationUnit
import de.timklge.karooheadwind.R
import de.timklge.karooheadwind.TemperatureUnit
import de.timklge.karooheadwind.WeatherInterpretation
@ -47,9 +46,10 @@ fun WeatherWidget(
distance: Double? = null,
includeDistanceLabel: Boolean = false,
precipitationProbability: Int? = null,
precipitationUnit: PrecipitationUnit,
isImperial: Boolean
) {
val fontSize = 20.sp
Row(
modifier = Modifier.fillMaxWidth().padding(5.dp),
verticalAlignment = Alignment.CenterVertically,
@ -60,7 +60,7 @@ fun WeatherWidget(
Text(
text = dateLabel,
style = TextStyle(
fontSize = 14.sp
fontSize = fontSize
)
)
}
@ -81,7 +81,7 @@ fun WeatherWidget(
Text(
text = text,
style = TextStyle(
fontSize = 14.sp
fontSize = fontSize
)
)
}
@ -91,7 +91,7 @@ fun WeatherWidget(
text = timeLabel,
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 14.sp
fontSize = fontSize
)
)
}
@ -104,7 +104,7 @@ fun WeatherWidget(
modifier = Modifier.size(72.dp)
)
Column {
Column(horizontalAlignment = Alignment.End) {
// Temperature (larger)
Row(
verticalAlignment = Alignment.CenterVertically
@ -134,10 +134,16 @@ fun WeatherWidget(
val precipitationProbabilityLabel =
if (precipitationProbability != null) "${precipitationProbability}% " else ""
Icon(
painter = painterResource(id = R.drawable.droplet_regular),
contentDescription = "Precipitation",
modifier = Modifier.size(18.dp)
)
Text(
text = "${precipitationProbabilityLabel}${ceil(precipitation).toInt()}${precipitationUnit.unitDisplay}",
text = "${precipitationProbabilityLabel}${ceil(precipitation).toInt()}",
style = TextStyle(
fontSize = 14.sp
fontSize = fontSize
)
)
}
@ -151,7 +157,7 @@ fun WeatherWidget(
bitmap = getArrowBitmapByBearing(baseBitmap, windBearing).asImageBitmap(),
colorFilter = ColorFilter.tint(Color.Black),
contentDescription = "Wind direction",
modifier = Modifier.size(16.dp)
modifier = Modifier.size(20.dp)
)
Spacer(modifier = Modifier.width(4.dp))
@ -159,7 +165,7 @@ fun WeatherWidget(
Text(
text = "$windSpeed,$windGusts",
style = TextStyle(
fontSize = 14.sp
fontSize = fontSize
)
)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB