ref #5: Set alignment of absolute wind direction field, add preview mode

This commit is contained in:
Tim Kluge 2024-12-13 23:19:20 +01:00
parent 23dc550e5a
commit 223157a3f8
2 changed files with 80 additions and 32 deletions

View File

@ -8,6 +8,7 @@ import androidx.glance.appwidget.ExperimentalGlanceRemoteViewsApi
import androidx.glance.appwidget.GlanceRemoteViews import androidx.glance.appwidget.GlanceRemoteViews
import de.timklge.karooheadwind.KarooHeadwindExtension import de.timklge.karooheadwind.KarooHeadwindExtension
import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse import de.timklge.karooheadwind.OpenMeteoCurrentWeatherResponse
import de.timklge.karooheadwind.OpenMeteoData
import de.timklge.karooheadwind.getRelativeHeadingFlow import de.timklge.karooheadwind.getRelativeHeadingFlow
import de.timklge.karooheadwind.screens.HeadwindSettings import de.timklge.karooheadwind.screens.HeadwindSettings
import de.timklge.karooheadwind.streamCurrentWeatherData import de.timklge.karooheadwind.streamCurrentWeatherData
@ -25,8 +26,11 @@ import io.hammerhead.karooext.models.ViewConfig
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -53,6 +57,21 @@ class HeadwindDirectionDataType(
} }
} }
data class StreamData(val value: Double, val windSpeed: Double, val settings: HeadwindSettings)
private fun previewFlow(): Flow<StreamData> {
return flow {
while (true) {
val bearing = (0..360).random().toDouble()
val windSpeed = (-20..20).random()
emit(StreamData(bearing, windSpeed.toDouble(), HeadwindSettings()))
delay(2_000)
}
}
}
override fun startView(context: Context, config: ViewConfig, emitter: ViewEmitter) { override fun startView(context: Context, config: ViewConfig, emitter: ViewEmitter) {
Log.d(KarooHeadwindExtension.TAG, "Starting headwind direction view with $emitter") Log.d(KarooHeadwindExtension.TAG, "Starting headwind direction view with $emitter")
@ -66,21 +85,26 @@ class HeadwindDirectionDataType(
awaitCancellation() awaitCancellation()
} }
data class StreamData(val value: Double, val data: OpenMeteoCurrentWeatherResponse, val settings: HeadwindSettings) val flow = if (config.preview) {
previewFlow()
val viewJob = CoroutineScope(Dispatchers.IO).launch { } else {
karooSystem.streamDataFlow(dataTypeId) karooSystem.streamDataFlow(dataTypeId)
.mapNotNull { (it as? StreamState.Streaming)?.dataPoint?.singleValue } .mapNotNull { (it as? StreamState.Streaming)?.dataPoint?.singleValue }
.combine(context.streamCurrentWeatherData()) { value, data -> value to data } .combine(context.streamCurrentWeatherData()) { value, data -> value to data }
.combine(context.streamSettings(karooSystem)) { (value, data), settings -> StreamData(value, data, settings) } .combine(context.streamSettings(karooSystem)) { (value, data), settings ->
.onCompletion { StreamData(value, data.current.windSpeed, settings)
}
}
val viewJob = CoroutineScope(Dispatchers.IO).launch {
flow.onCompletion {
// Clear view on completion // Clear view on completion
val result = glance.compose(context, DpSize.Unspecified) { } val result = glance.compose(context, DpSize.Unspecified) { }
emitter.updateView(result.remoteViews) emitter.updateView(result.remoteViews)
} }
.collect { streamData -> .collect { streamData ->
Log.d(KarooHeadwindExtension.TAG, "Updating headwind direction view") Log.d(KarooHeadwindExtension.TAG, "Updating headwind direction view")
val windSpeed = streamData.data.current.windSpeed val windSpeed = streamData.windSpeed
val windDirection = streamData.value val windDirection = streamData.value
val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed
val windSpeedText = headwindSpeed.roundToInt().toString() val windSpeedText = headwindSpeed.roundToInt().toString()

View File

@ -27,6 +27,11 @@ import io.hammerhead.karooext.models.ViewConfig
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -39,6 +44,15 @@ class WindDirectionDataType(val karooSystem: KarooSystemService, context: Contex
return data.current.windDirection return data.current.windDirection
} }
private fun previewFlow(): Flow<Double> {
return flow {
while (true) {
emit((0..360).random().toDouble())
delay(1_000)
}
}
}
@OptIn(ExperimentalGlanceRemoteViewsApi::class) @OptIn(ExperimentalGlanceRemoteViewsApi::class)
override fun startView(context: Context, config: ViewConfig, emitter: ViewEmitter) { override fun startView(context: Context, config: ViewConfig, emitter: ViewEmitter) {
val configJob = CoroutineScope(Dispatchers.IO).launch { val configJob = CoroutineScope(Dispatchers.IO).launch {
@ -47,13 +61,19 @@ class WindDirectionDataType(val karooSystem: KarooSystemService, context: Contex
} }
val viewJob = CoroutineScope(Dispatchers.IO).launch { val viewJob = CoroutineScope(Dispatchers.IO).launch {
val flow = if (config.preview){
previewFlow()
} else {
karooSystem.streamDataFlow(dataTypeId) karooSystem.streamDataFlow(dataTypeId)
.mapNotNull { (it as? StreamState.Streaming)?.dataPoint?.singleValue ?: 0.0 }
}
flow
.onCompletion { .onCompletion {
val result = glance.compose(context, DpSize.Unspecified) { } val result = glance.compose(context, DpSize.Unspecified) { }
emitter.updateView(result.remoteViews) emitter.updateView(result.remoteViews)
} }
.collect { .collect { windBearing ->
val windBearing = (it as? StreamState.Streaming)?.dataPoint?.singleValue?.toInt() ?: 0
val windCardinalDirection = ((windBearing % 360) / 45.0).roundToInt() % 8 val windCardinalDirection = ((windBearing % 360) / 45.0).roundToInt() % 8
val text = when(windCardinalDirection){ val text = when(windCardinalDirection){
0 -> "N" 0 -> "N"
@ -71,10 +91,14 @@ class WindDirectionDataType(val karooSystem: KarooSystemService, context: Contex
Box(modifier = GlanceModifier.fillMaxSize(), Box(modifier = GlanceModifier.fillMaxSize(),
contentAlignment = Alignment( contentAlignment = Alignment(
vertical = Alignment.Vertical.Top, vertical = Alignment.Vertical.Top,
horizontal = Alignment.Horizontal.End, horizontal = when(config.alignment){
ViewConfig.Alignment.LEFT -> Alignment.Horizontal.Start
ViewConfig.Alignment.CENTER -> Alignment.Horizontal.CenterHorizontally
ViewConfig.Alignment.RIGHT -> Alignment.Horizontal.End
},
)) { )) {
Text(text, style = TextStyle(color = ColorProvider(Color.Black, Color.White), fontFamily = FontFamily.Monospace, fontSize = TextUnit( Text(text, style = TextStyle(color = ColorProvider(Color.Black, Color.White), fontFamily = FontFamily.Monospace, fontSize = TextUnit(
config.textSize.toFloat(), TextUnitType.Sp) /* FIXME: Read data field alignment config, karoo-ext #10 */)) config.textSize.toFloat(), TextUnitType.Sp)))
} }
} }
emitter.updateView(result.remoteViews) emitter.updateView(result.remoteViews)