Only refresh graphical data fields on the currently opened data page (#133)

This commit is contained in:
timklge 2025-05-11 19:36:15 +02:00 committed by GitHub
parent f7cd264e0c
commit 9772347a61
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 167 additions and 68 deletions

View File

@ -1,6 +1,7 @@
package de.timklge.karooheadwind package de.timklge.karooheadwind
import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.ActiveRidePage
import io.hammerhead.karooext.models.OnLocationChanged import io.hammerhead.karooext.models.OnLocationChanged
import io.hammerhead.karooext.models.OnNavigationState import io.hammerhead.karooext.models.OnNavigationState
import io.hammerhead.karooext.models.OnStreamState import io.hammerhead.karooext.models.OnStreamState
@ -12,6 +13,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.sample import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.flow.transform import kotlinx.coroutines.flow.transform
@ -65,3 +67,22 @@ fun<T> Flow<T>.throttle(timeout: Long): Flow<T> = this
emit(it) emit(it)
delay(timeout) delay(timeout)
} }
fun KarooSystemService.streamActiveRidePage(): Flow<ActiveRidePage> {
return callbackFlow {
val listenerId = addConsumer { activeRidePage: ActiveRidePage ->
trySendBlocking(activeRidePage)
}
awaitClose {
removeConsumer(listenerId)
}
}
}
fun KarooSystemService.streamDatatypeIsVisible(
datatype: String,
): Flow<Boolean> {
return streamActiveRidePage().map { page ->
page.page.elements.any { it.dataTypeId == datatype }
}
}

View File

@ -31,6 +31,7 @@ import de.timklge.karooheadwind.UpcomingRoute
import de.timklge.karooheadwind.WeatherDataProvider import de.timklge.karooheadwind.WeatherDataProvider
import de.timklge.karooheadwind.getHeadingFlow import de.timklge.karooheadwind.getHeadingFlow
import de.timklge.karooheadwind.streamCurrentForecastWeatherData import de.timklge.karooheadwind.streamCurrentForecastWeatherData
import de.timklge.karooheadwind.streamDatatypeIsVisible
import de.timklge.karooheadwind.streamSettings import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.streamUpcomingRoute import de.timklge.karooheadwind.streamUpcomingRoute
import de.timklge.karooheadwind.streamUserProfile import de.timklge.karooheadwind.streamUserProfile
@ -54,6 +55,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -90,7 +92,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
data class StreamData(val data: WeatherDataResponse?, val settings: SettingsAndProfile, data class StreamData(val data: WeatherDataResponse?, val settings: SettingsAndProfile,
val widgetSettings: HeadwindWidgetSettings? = null, val widgetSettings: HeadwindWidgetSettings? = null,
val headingResponse: HeadingResponse? = null, val upcomingRoute: UpcomingRoute? = null) val headingResponse: HeadingResponse? = null, val upcomingRoute: UpcomingRoute? = null, val isVisible: Boolean)
data class SettingsAndProfile(val settings: HeadwindSettings, val isImperial: Boolean, val isImperialTemperature: Boolean) data class SettingsAndProfile(val settings: HeadwindSettings, val isImperial: Boolean, val isImperialTemperature: Boolean)
@ -164,7 +166,8 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
HeadwindSettings(), HeadwindSettings(),
settingsAndProfile?.isImperial == true, settingsAndProfile?.isImperial == true,
settingsAndProfile?.isImperialTemperature == true settingsAndProfile?.isImperialTemperature == true
) ),
isVisible = true
) )
) )
@ -206,14 +209,23 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
if (oldDistance == null || newDistance == null) return@distinctUntilChanged false if (oldDistance == null || newDistance == null) return@distinctUntilChanged false
abs(oldDistance - newDistance) < 1_000 abs(oldDistance - newDistance) < 1_000
} },
) { weatherData, settings, widgetSettings, heading, upcomingRoute -> karooSystem.streamDatatypeIsVisible(dataTypeId)
) { data ->
val weatherData = data[0] as WeatherDataResponse?
val settings = data[1] as SettingsAndProfile
val widgetSettings = data[2] as HeadwindWidgetSettings?
val heading = data[3] as HeadingResponse?
val upcomingRoute = data[4] as UpcomingRoute?
val isVisible = data[5] as Boolean
StreamData( StreamData(
data = weatherData, data = weatherData,
settings = settings, settings = settings,
widgetSettings = widgetSettings, widgetSettings = widgetSettings,
headingResponse = heading, headingResponse = heading,
upcomingRoute = upcomingRoute upcomingRoute = upcomingRoute,
isVisible = isVisible
) )
} }
} }
@ -221,7 +233,7 @@ abstract class ForecastDataType(private val karooSystem: KarooSystemService, typ
val viewJob = CoroutineScope(Dispatchers.IO).launch { val viewJob = CoroutineScope(Dispatchers.IO).launch {
emitter.onNext(ShowCustomStreamState("", null)) emitter.onNext(ShowCustomStreamState("", null))
dataFlow.collect { (allData, settingsAndProfile, widgetSettings, headingResponse, upcomingRoute) -> dataFlow.filter { it.isVisible }.collect { (allData, settingsAndProfile, widgetSettings, headingResponse, upcomingRoute) ->
Log.d(KarooHeadwindExtension.TAG, "Updating weather forecast view") Log.d(KarooHeadwindExtension.TAG, "Updating weather forecast view")
if (allData?.data.isNullOrEmpty()){ if (allData?.data.isNullOrEmpty()){

View File

@ -12,6 +12,7 @@ import de.timklge.karooheadwind.KarooHeadwindExtension
import de.timklge.karooheadwind.WindDirectionIndicatorSetting import de.timklge.karooheadwind.WindDirectionIndicatorSetting
import de.timklge.karooheadwind.getRelativeHeadingFlow import de.timklge.karooheadwind.getRelativeHeadingFlow
import de.timklge.karooheadwind.streamCurrentWeatherData import de.timklge.karooheadwind.streamCurrentWeatherData
import de.timklge.karooheadwind.streamDatatypeIsVisible
import de.timklge.karooheadwind.streamSettings import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.throttle import de.timklge.karooheadwind.throttle
import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
@ -31,6 +32,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -43,46 +45,54 @@ class HeadwindDirectionDataType(
) : DataTypeImpl("karoo-headwind", "headwind") { ) : DataTypeImpl("karoo-headwind", "headwind") {
private val glance = GlanceRemoteViews() private val glance = GlanceRemoteViews()
data class StreamData(val headingResponse: HeadingResponse, val absoluteWindDirection: Double?, val windSpeed: Double?, val settings: HeadwindSettings)
private fun streamValues(): Flow<Double> = flow { private fun streamValues(): Flow<Double> = flow {
karooSystem.getRelativeHeadingFlow(applicationContext) combine(
.combine(applicationContext.streamCurrentWeatherData(karooSystem)) { headingResponse, data -> karooSystem.getRelativeHeadingFlow(applicationContext),
StreamData(headingResponse, data?.windDirection, data?.windSpeed) applicationContext.streamCurrentWeatherData(karooSystem),
applicationContext.streamSettings(karooSystem),
) { headingResponse, currentWeather, settings ->
StreamData(
headingResponse,
currentWeather?.windDirection,
currentWeather?.windSpeed,
settings,
)
}.collect { streamData ->
val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff
var returnValue = 0.0
if (value == null || streamData.absoluteWindDirection == null || streamData.settings == null || streamData.windSpeed == null){
var errorCode = 1.0
var headingResponse = streamData.headingResponse
if (headingResponse is HeadingResponse.Value && (streamData.absoluteWindDirection == null || streamData.windSpeed == null)){
headingResponse = HeadingResponse.NoWeatherData
} }
.combine(applicationContext.streamSettings(karooSystem)) { data, settings -> data.copy(settings = settings) }
.collect { streamData ->
val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff
var returnValue = 0.0 if (streamData.settings?.welcomeDialogAccepted == false){
if (value == null || streamData.absoluteWindDirection == null || streamData.settings == null || streamData.windSpeed == null){ errorCode = ERROR_APP_NOT_SET_UP.toDouble()
var errorCode = 1.0 } else if (headingResponse is HeadingResponse.NoGps){
var headingResponse = streamData.headingResponse errorCode = ERROR_NO_GPS.toDouble()
if (headingResponse is HeadingResponse.Value && (streamData.absoluteWindDirection == null || streamData.windSpeed == null)){
headingResponse = HeadingResponse.NoWeatherData
}
if (streamData.settings?.welcomeDialogAccepted == false){
errorCode = ERROR_APP_NOT_SET_UP.toDouble()
} else if (headingResponse is HeadingResponse.NoGps){
errorCode = ERROR_NO_GPS.toDouble()
} else {
errorCode = ERROR_NO_WEATHER_DATA.toDouble()
}
returnValue = errorCode
} else { } else {
var windDirection = when (streamData.settings.windDirectionIndicatorSetting){ errorCode = ERROR_NO_WEATHER_DATA.toDouble()
WindDirectionIndicatorSetting.HEADWIND_DIRECTION -> value
WindDirectionIndicatorSetting.WIND_DIRECTION -> streamData.absoluteWindDirection + 180
}
if (windDirection < 0) windDirection += 360
returnValue = windDirection
} }
emit(returnValue) returnValue = errorCode
} else {
var windDirection = when (streamData.settings.windDirectionIndicatorSetting){
WindDirectionIndicatorSetting.HEADWIND_DIRECTION -> value
WindDirectionIndicatorSetting.WIND_DIRECTION -> streamData.absoluteWindDirection + 180
}
if (windDirection < 0) windDirection += 360
returnValue = windDirection
} }
emit(returnValue)
}
} }
override fun startStream(emitter: Emitter<StreamState>) { override fun startStream(emitter: Emitter<StreamState>) {
@ -96,9 +106,7 @@ class HeadwindDirectionDataType(
} }
} }
data class StreamData(val headingResponse: HeadingResponse?, val absoluteWindDirection: Double?, val windSpeed: Double?, val settings: HeadwindSettings? = null) data class DirectionAndSpeed(val bearing: Double, val speed: Double?, val isVisible: Boolean)
data class DirectionAndSpeed(val bearing: Double, val speed: Double?)
private fun previewFlow(): Flow<DirectionAndSpeed> { private fun previewFlow(): Flow<DirectionAndSpeed> {
return flow { return flow {
@ -106,7 +114,7 @@ class HeadwindDirectionDataType(
val bearing = (0..360).random().toDouble() val bearing = (0..360).random().toDouble()
val windSpeed = (0..20).random() val windSpeed = (0..20).random()
emit(DirectionAndSpeed(bearing, windSpeed.toDouble())) emit(DirectionAndSpeed(bearing, windSpeed.toDouble(), true))
delay(2_000) delay(2_000)
} }
@ -136,15 +144,15 @@ class HeadwindDirectionDataType(
emitAll(UserWindSpeedDataType.streamValues(context, karooSystem)) emitAll(UserWindSpeedDataType.streamValues(context, karooSystem))
} }
combine(directionFlow, speedFlow) { direction, speed -> combine(directionFlow, speedFlow, karooSystem.streamDatatypeIsVisible(dataTypeId)) { direction, speed, isVisible ->
DirectionAndSpeed(direction, speed) DirectionAndSpeed(direction, speed, isVisible)
} }
} }
val viewJob = CoroutineScope(Dispatchers.IO).launch { val viewJob = CoroutineScope(Dispatchers.IO).launch {
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context) val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
flow.throttle(refreshRate).collect { streamData -> flow.filter { it.isVisible }.throttle(refreshRate).collect { streamData ->
Log.d(KarooHeadwindExtension.TAG, "Updating headwind direction view") Log.d(KarooHeadwindExtension.TAG, "Updating headwind direction view")
val errorCode = streamData.bearing.let { if(it < 0) it.toInt() else null } val errorCode = streamData.bearing.let { if(it < 0) it.toInt() else null }

View File

@ -21,9 +21,11 @@ import de.timklge.karooheadwind.datatypes.TailwindDataType.StreamData
import de.timklge.karooheadwind.getRelativeHeadingFlow import de.timklge.karooheadwind.getRelativeHeadingFlow
import de.timklge.karooheadwind.streamCurrentWeatherData import de.timklge.karooheadwind.streamCurrentWeatherData
import de.timklge.karooheadwind.streamDataFlow import de.timklge.karooheadwind.streamDataFlow
import de.timklge.karooheadwind.streamDatatypeIsVisible
import de.timklge.karooheadwind.streamSettings import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.streamUserProfile import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.throttle import de.timklge.karooheadwind.throttle
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.extension.DataTypeImpl import io.hammerhead.karooext.extension.DataTypeImpl
import io.hammerhead.karooext.internal.ViewEmitter import io.hammerhead.karooext.internal.ViewEmitter
@ -85,7 +87,7 @@ class TailwindAndRideSpeedDataType(
val gustSpeed = windSpeed * ((10..40).random().toDouble() / 10) val gustSpeed = windSpeed * ((10..40).random().toDouble() / 10)
val isImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL val isImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
emit(StreamData(HeadingResponse.Value(bearing), bearing, windSpeed.toDouble(), HeadwindSettings(), rideSpeed, gustSpeed = gustSpeed, isImperial = isImperial)) emit(StreamData(HeadingResponse.Value(bearing), bearing, windSpeed.toDouble(), HeadwindSettings(), rideSpeed, gustSpeed = gustSpeed, isImperial = isImperial, isVisible = true))
delay(2_000) delay(2_000)
} }
@ -113,7 +115,20 @@ class TailwindAndRideSpeedDataType(
val flow = if (config.preview) { val flow = if (config.preview) {
previewFlow(karooSystem.streamUserProfile()) previewFlow(karooSystem.streamUserProfile())
} else { } else {
combine(karooSystem.getRelativeHeadingFlow(context), context.streamCurrentWeatherData(karooSystem), context.streamSettings(karooSystem), karooSystem.streamUserProfile(), streamSpeedInMs()) { headingResponse, weatherData, settings, userProfile, rideSpeedInMs -> combine(karooSystem.getRelativeHeadingFlow(context),
context.streamCurrentWeatherData(karooSystem),
context.streamSettings(karooSystem),
karooSystem.streamUserProfile(),
streamSpeedInMs(),
karooSystem.streamDatatypeIsVisible(dataTypeId)
) { data ->
val headingResponse = data[0] as HeadingResponse
val weatherData = data[1] as? WeatherData
val settings = data[2] as HeadwindSettings
val userProfile = data[3] as UserProfile
val rideSpeedInMs = data[4] as Double
val isVisible = data[5] as Boolean
val isImperial = userProfile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL val isImperial = userProfile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
val absoluteWindDirection = weatherData?.windDirection val absoluteWindDirection = weatherData?.windDirection
val windSpeed = weatherData?.windSpeed val windSpeed = weatherData?.windSpeed
@ -124,7 +139,7 @@ class TailwindAndRideSpeedDataType(
rideSpeedInMs * 3.6 rideSpeedInMs * 3.6
} }
StreamData(headingResponse, absoluteWindDirection, windSpeed, settings, rideSpeed = rideSpeed, isImperial = isImperial, gustSpeed = gustSpeed) StreamData(headingResponse, absoluteWindDirection, windSpeed, settings, rideSpeed = rideSpeed, isImperial = isImperial, gustSpeed = gustSpeed, isVisible = isVisible)
} }
} }

View File

@ -17,9 +17,11 @@ import de.timklge.karooheadwind.WindDirectionIndicatorTextSetting
import de.timklge.karooheadwind.getRelativeHeadingFlow import de.timklge.karooheadwind.getRelativeHeadingFlow
import de.timklge.karooheadwind.streamCurrentWeatherData import de.timklge.karooheadwind.streamCurrentWeatherData
import de.timklge.karooheadwind.streamDataFlow import de.timklge.karooheadwind.streamDataFlow
import de.timklge.karooheadwind.streamDatatypeIsVisible
import de.timklge.karooheadwind.streamSettings import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.streamUserProfile import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.throttle import de.timklge.karooheadwind.throttle
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.extension.DataTypeImpl import io.hammerhead.karooext.extension.DataTypeImpl
import io.hammerhead.karooext.internal.ViewEmitter import io.hammerhead.karooext.internal.ViewEmitter
@ -35,6 +37,7 @@ import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
@ -56,7 +59,8 @@ class TailwindDataType(
val settings: HeadwindSettings, val settings: HeadwindSettings,
val rideSpeed: Double?, val rideSpeed: Double?,
val gustSpeed: Double?, val gustSpeed: Double?,
val isImperial: Boolean) val isImperial: Boolean,
val isVisible: Boolean)
private fun previewFlow(profileFlow: Flow<UserProfile>): Flow<StreamData> { private fun previewFlow(profileFlow: Flow<UserProfile>): Flow<StreamData> {
return flow { return flow {
@ -69,7 +73,7 @@ class TailwindDataType(
val gustSpeed = windSpeed * ((10..40).random().toDouble() / 10) val gustSpeed = windSpeed * ((10..40).random().toDouble() / 10)
val isImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL val isImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
emit(StreamData(HeadingResponse.Value(bearing), bearing, windSpeed.toDouble(), HeadwindSettings(), rideSpeed, gustSpeed = gustSpeed, isImperial = isImperial)) emit(StreamData(HeadingResponse.Value(bearing), bearing, windSpeed.toDouble(), HeadwindSettings(), rideSpeed, gustSpeed = gustSpeed, isImperial = isImperial, isVisible = true))
delay(2_000) delay(2_000)
} }
@ -98,7 +102,20 @@ class TailwindDataType(
val flow = if (config.preview) { val flow = if (config.preview) {
previewFlow(karooSystem.streamUserProfile()) previewFlow(karooSystem.streamUserProfile())
} else { } else {
combine(karooSystem.getRelativeHeadingFlow(context), context.streamCurrentWeatherData(karooSystem), context.streamSettings(karooSystem), karooSystem.streamUserProfile(), streamSpeedInMs()) { headingResponse, weatherData, settings, userProfile, rideSpeedInMs -> combine(karooSystem.getRelativeHeadingFlow(context),
context.streamCurrentWeatherData(karooSystem),
context.streamSettings(karooSystem),
karooSystem.streamUserProfile(),
streamSpeedInMs(),
karooSystem.streamDatatypeIsVisible(dataTypeId)
) { data ->
val headingResponse = data[0] as HeadingResponse
val weatherData = data[1] as? WeatherData
val settings = data[2] as HeadwindSettings
val userProfile = data[3] as UserProfile
val rideSpeedInMs = data[4] as Double
val isVisible = data[5] as Boolean
val isImperial = userProfile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL val isImperial = userProfile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
val absoluteWindDirection = weatherData?.windDirection val absoluteWindDirection = weatherData?.windDirection
val windSpeed = weatherData?.windSpeed val windSpeed = weatherData?.windSpeed
@ -109,7 +126,7 @@ class TailwindDataType(
rideSpeedInMs * 3.6 rideSpeedInMs * 3.6
} }
StreamData(headingResponse, absoluteWindDirection, windSpeed, settings, rideSpeed = rideSpeed, isImperial = isImperial, gustSpeed = gustSpeed) StreamData(headingResponse, absoluteWindDirection, windSpeed, settings, rideSpeed = rideSpeed, isImperial = isImperial, gustSpeed = gustSpeed, isVisible = isVisible)
} }
} }
@ -117,7 +134,7 @@ class TailwindDataType(
emitter.onNext(ShowCustomStreamState("", null)) emitter.onNext(ShowCustomStreamState("", null))
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context) val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
flow.throttle(refreshRate).collect { streamData -> flow.filter { it.isVisible }.throttle(refreshRate).collect { streamData ->
Log.d(KarooHeadwindExtension.TAG, "Updating tailwind direction view") Log.d(KarooHeadwindExtension.TAG, "Updating tailwind direction view")
val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff val value = (streamData.headingResponse as? HeadingResponse.Value)?.diff

View File

@ -20,6 +20,7 @@ import de.timklge.karooheadwind.R
import de.timklge.karooheadwind.TemperatureUnit import de.timklge.karooheadwind.TemperatureUnit
import de.timklge.karooheadwind.getHeadingFlow import de.timklge.karooheadwind.getHeadingFlow
import de.timklge.karooheadwind.streamCurrentWeatherData import de.timklge.karooheadwind.streamCurrentWeatherData
import de.timklge.karooheadwind.streamDatatypeIsVisible
import de.timklge.karooheadwind.streamSettings import de.timklge.karooheadwind.streamSettings
import de.timklge.karooheadwind.streamUserProfile import de.timklge.karooheadwind.streamUserProfile
import de.timklge.karooheadwind.throttle import de.timklge.karooheadwind.throttle
@ -42,6 +43,7 @@ import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.Instant import java.time.Instant
@ -75,7 +77,8 @@ class WeatherDataType(
} }
data class StreamData(val data: WeatherData?, val settings: HeadwindSettings, data class StreamData(val data: WeatherData?, val settings: HeadwindSettings,
val profile: UserProfile? = null, val headingResponse: HeadingResponse? = null) val profile: UserProfile? = null, val headingResponse: HeadingResponse? = null,
val isVisible: Boolean)
private fun previewFlow(): Flow<StreamData> = flow { private fun previewFlow(): Flow<StreamData> = flow {
while (true){ while (true){
@ -85,7 +88,7 @@ class WeatherDataType(
20.0, 50.0, 3.0, 0.0, 1013.25, 980.0, 15.0, 30.0, 30.0, 20.0, 50.0, 3.0, 0.0, 1013.25, 980.0, 15.0, 30.0, 30.0,
WeatherInterpretation.getKnownWeatherCodes().random(), isForecast = false, WeatherInterpretation.getKnownWeatherCodes().random(), isForecast = false,
isNight = listOf(true, false).random() isNight = listOf(true, false).random()
), HeadwindSettings())) ), HeadwindSettings(), isVisible = true))
delay(5_000) delay(5_000)
} }
@ -106,8 +109,14 @@ class WeatherDataType(
val dataFlow = if (config.preview){ val dataFlow = if (config.preview){
previewFlow() previewFlow()
} else { } else {
combine(context.streamCurrentWeatherData(karooSystem), context.streamSettings(karooSystem), karooSystem.streamUserProfile(), karooSystem.getHeadingFlow(context)) { data, settings, profile, heading -> combine(
StreamData(data, settings, profile, heading) context.streamCurrentWeatherData(karooSystem),
context.streamSettings(karooSystem),
karooSystem.streamUserProfile(),
karooSystem.getHeadingFlow(context),
karooSystem.streamDatatypeIsVisible(dataTypeId)
) { data, settings, profile, heading, isVisible ->
StreamData(data, settings, profile, heading, isVisible)
} }
} }
@ -116,7 +125,7 @@ class WeatherDataType(
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context) val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
dataFlow.throttle(refreshRate).collect { (data, settings, userProfile, headingResponse) -> dataFlow.filter { it.isVisible }.throttle(refreshRate).collect { (data, settings, userProfile, headingResponse) ->
Log.d(KarooHeadwindExtension.TAG, "Updating weather view") Log.d(KarooHeadwindExtension.TAG, "Updating weather view")
if (data == null){ if (data == null){

View File

@ -17,9 +17,10 @@ import androidx.glance.text.FontFamily
import androidx.glance.text.Text import androidx.glance.text.Text
import androidx.glance.text.TextStyle import androidx.glance.text.TextStyle
import de.timklge.karooheadwind.KarooHeadwindExtension import de.timklge.karooheadwind.KarooHeadwindExtension
import de.timklge.karooheadwind.weatherprovider.WeatherData
import de.timklge.karooheadwind.streamDataFlow import de.timklge.karooheadwind.streamDataFlow
import de.timklge.karooheadwind.streamDatatypeIsVisible
import de.timklge.karooheadwind.throttle import de.timklge.karooheadwind.throttle
import de.timklge.karooheadwind.weatherprovider.WeatherData
import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.internal.ViewEmitter import io.hammerhead.karooext.internal.ViewEmitter
import io.hammerhead.karooext.models.ShowCustomStreamState import io.hammerhead.karooext.models.ShowCustomStreamState
@ -31,8 +32,9 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -53,10 +55,18 @@ class WindDirectionDataType(val karooSystem: KarooSystemService, context: Contex
return data.windDirection return data.windDirection
} }
private fun previewFlow(): Flow<Double> { data class StreamData(
val windBearing: Double,
val isVisible: Boolean
)
private fun previewFlow(): Flow<StreamData> {
return flow { return flow {
while (true) { while (true) {
emit((0..360).random().toDouble()) emit(StreamData(
(0..360).random().toDouble(),
true
))
delay(1_000) delay(1_000)
} }
} }
@ -75,17 +85,24 @@ class WindDirectionDataType(val karooSystem: KarooSystemService, context: Contex
val flow = if (config.preview){ val flow = if (config.preview){
previewFlow() previewFlow()
} else { } else {
karooSystem.streamDataFlow(dataTypeId) combine(
.mapNotNull { (it as? StreamState.Streaming)?.dataPoint?.singleValue ?: 0.0 } karooSystem.streamDataFlow(dataTypeId),
karooSystem.streamDatatypeIsVisible(dataTypeId)
) { windBearing, isVisible ->
StreamData(
windBearing = (windBearing as? StreamState.Streaming)?.dataPoint?.singleValue ?: 0.0,
isVisible = isVisible
)
}
} }
val refreshRate = karooSystem.getRefreshRateInMilliseconds(context) val refreshRate = karooSystem.getRefreshRateInMilliseconds(context)
flow.throttle(refreshRate).collect { windBearing -> flow.filter { it.isVisible }.throttle(refreshRate).collect { (windBearing, isVisible) ->
val windCardinalDirectionIndex = ((windBearing % 360) / 22.5).roundToInt() % 16 val windCardinalDirectionIndex = ((windBearing % 360) / 22.5).roundToInt() % 16
val text = windDirections[windCardinalDirectionIndex] val text = windDirections[windCardinalDirectionIndex]
Log.d( KarooHeadwindExtension.TAG,"Updating wind direction view") Log.d(KarooHeadwindExtension.TAG,"Updating wind direction view")
val result = glance.compose(context, DpSize.Unspecified) { val result = glance.compose(context, DpSize.Unspecified) {
Box(modifier = GlanceModifier.fillMaxSize(), Box(modifier = GlanceModifier.fillMaxSize(),
contentAlignment = Alignment( contentAlignment = Alignment(