Update route progress datasource to show ridden distance, add route remaining datasource (#41)
All checks were successful
Build / build (push) Successful in 9m54s
All checks were successful
Build / build (push) Successful in 9m54s
This commit is contained in:
parent
b8c3356674
commit
1afeaae9e6
@ -25,6 +25,8 @@ to be displayed at the bottom or at the top of the screen:
|
|||||||
- Average power over the last 10 seconds
|
- Average power over the last 10 seconds
|
||||||
- Speed
|
- Speed
|
||||||
- Cadence
|
- Cadence
|
||||||
|
- Route Progress (shows currently ridden distance)
|
||||||
|
- Remaining Route (shows remaining distance to the end of the route)
|
||||||
|
|
||||||
Subsequently, the bar(s) will be shown when riding. Bars are filled and colored according
|
Subsequently, the bar(s) will be shown when riding. Bars are filled and colored according
|
||||||
to your current power output / heart rate zone as setup in your Karoo settings. Optionally, the actual data value can be displayed on top of the bar.
|
to your current power output / heart rate zone as setup in your Karoo settings. Optionally, the actual data value can be displayed on top of the bar.
|
||||||
|
|||||||
@ -34,7 +34,6 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.flowOf
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -152,7 +151,8 @@ class Window(
|
|||||||
SelectedSource.SPEED_3S -> streamSpeed(true)
|
SelectedSource.SPEED_3S -> streamSpeed(true)
|
||||||
SelectedSource.CADENCE -> streamCadence(false)
|
SelectedSource.CADENCE -> streamCadence(false)
|
||||||
SelectedSource.CADENCE_3S -> streamCadence(true)
|
SelectedSource.CADENCE_3S -> streamCadence(true)
|
||||||
SelectedSource.ROUTE_PROGRESS -> streamRouteProgress()
|
SelectedSource.ROUTE_PROGRESS -> streamRouteProgress(::getRouteProgress)
|
||||||
|
SelectedSource.REMAINING_ROUTE -> streamRouteProgress(::getRemainingRouteProgress)
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,19 +168,50 @@ class Window(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun streamRouteProgress() {
|
data class BarProgress(
|
||||||
|
val progress: Double?,
|
||||||
|
val label: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun getRouteProgress(userProfile: UserProfile, riddenDistance: Double?, routeEndAt: Double?, distanceToDestination: Double?): BarProgress {
|
||||||
|
val routeProgress = if (routeEndAt != null && riddenDistance != null) remap(riddenDistance, 0.0, routeEndAt, 0.0, 1.0) else null
|
||||||
|
val routeProgressInUserUnit = when (userProfile.preferredUnit.distance) {
|
||||||
|
UserProfile.PreferredUnit.UnitType.IMPERIAL -> riddenDistance?.times(0.000621371)?.roundToInt() // Miles
|
||||||
|
else -> riddenDistance?.times(0.001)?.roundToInt() // Kilometers
|
||||||
|
}
|
||||||
|
|
||||||
|
return BarProgress(routeProgress, "$routeProgressInUserUnit")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getRemainingRouteProgress(userProfile: UserProfile, riddenDistance: Double?, routeEndAt: Double?, distanceToDestination: Double?): BarProgress {
|
||||||
|
val routeProgress = if (routeEndAt != null && riddenDistance != null) remap(riddenDistance, 0.0, routeEndAt, 0.0, 1.0) else null
|
||||||
|
val distanceToDestinationInUserUnit = when (userProfile.preferredUnit.distance) {
|
||||||
|
UserProfile.PreferredUnit.UnitType.IMPERIAL -> distanceToDestination?.times(0.000621371)?.roundToInt() // Miles
|
||||||
|
else -> distanceToDestination?.times(0.001)?.roundToInt() // Kilometers
|
||||||
|
}
|
||||||
|
|
||||||
|
return BarProgress(routeProgress, "$distanceToDestinationInUserUnit")
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun streamRouteProgress(routeProgressProvider: (UserProfile, Double?, Double?, Double?) -> BarProgress) {
|
||||||
data class StreamData(
|
data class StreamData(
|
||||||
val userProfile: UserProfile,
|
val userProfile: UserProfile,
|
||||||
val distanceToDestination: Double?,
|
val distanceToDestination: Double?,
|
||||||
val navigationState: OnNavigationState
|
val navigationState: OnNavigationState,
|
||||||
|
val riddenDistance: Double?
|
||||||
)
|
)
|
||||||
|
|
||||||
var lastKnownRoutePolyline: String? = null
|
var lastKnownRoutePolyline: String? = null
|
||||||
var lastKnownRouteLength: Double? = null
|
var lastKnownRouteLength: Double? = null
|
||||||
|
|
||||||
combine(karooSystem.streamUserProfile(), karooSystem.streamDataFlow(DataType.Type.DISTANCE_TO_DESTINATION), karooSystem.streamNavigationState()) { userProfile, distanceToDestination, navigationState ->
|
combine(karooSystem.streamUserProfile(), karooSystem.streamDataFlow(DataType.Type.DISTANCE_TO_DESTINATION), karooSystem.streamNavigationState(), karooSystem.streamDataFlow(DataType.Type.DISTANCE)) { userProfile, distanceToDestination, navigationState, riddenDistance ->
|
||||||
StreamData(userProfile, (distanceToDestination as? StreamState.Streaming)?.dataPoint?.values[DataType.Field.DISTANCE_TO_DESTINATION], navigationState)
|
StreamData(
|
||||||
}.distinctUntilChanged().throttle(5_000).collect { (userProfile, distanceToDestination, navigationState) ->
|
userProfile,
|
||||||
|
(distanceToDestination as? StreamState.Streaming)?.dataPoint?.values?.get(DataType.Field.DISTANCE_TO_DESTINATION),
|
||||||
|
navigationState,
|
||||||
|
(riddenDistance as? StreamState.Streaming)?.dataPoint?.values?.get(DataType.Field.DISTANCE)
|
||||||
|
)
|
||||||
|
}.distinctUntilChanged().throttle(5_000).collect { (userProfile, distanceToDestination, navigationState, riddenDistance) ->
|
||||||
val state = navigationState.state
|
val state = navigationState.state
|
||||||
val routePolyline = when (state) {
|
val routePolyline = when (state) {
|
||||||
is OnNavigationState.NavigationState.NavigatingRoute -> state.routePolyline
|
is OnNavigationState.NavigationState.NavigatingRoute -> state.routePolyline
|
||||||
@ -202,17 +233,12 @@ class Window(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val routeLength = lastKnownRouteLength
|
val routeEndAt = lastKnownRouteLength?.plus((distanceToDestination ?: 0.0))
|
||||||
val routeProgressMeters = routeLength?.let { routeLength - (distanceToDestination ?: 0.0) }?.coerceAtLeast(0.0)
|
val barProgress = routeProgressProvider(userProfile, riddenDistance, routeEndAt, distanceToDestination)
|
||||||
val routeProgress = if (routeLength != null && routeProgressMeters != null) remap(routeProgressMeters, 0.0, routeLength, 0.0, 1.0) else null
|
|
||||||
val routeProgressInUserUnit = when (userProfile.preferredUnit.distance) {
|
|
||||||
UserProfile.PreferredUnit.UnitType.IMPERIAL -> routeProgressMeters?.times(0.000621371)?.roundToInt() // Miles
|
|
||||||
else -> routeProgressMeters?.times(0.001)?.roundToInt() // Kilometers
|
|
||||||
}
|
|
||||||
|
|
||||||
powerbar.progressColor = context.getColor(R.color.zone0)
|
powerbar.progressColor = context.getColor(R.color.zone0)
|
||||||
powerbar.progress = routeProgress
|
powerbar.progress = barProgress.progress
|
||||||
powerbar.label = "$routeProgressInUserUnit"
|
powerbar.label = barProgress.label
|
||||||
powerbar.invalidate()
|
powerbar.invalidate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,9 +310,9 @@ class Window(
|
|||||||
val maxCadence = streamData.settings?.maxCadence ?: PowerbarSettings.defaultMaxCadence
|
val maxCadence = streamData.settings?.maxCadence ?: PowerbarSettings.defaultMaxCadence
|
||||||
val progress = remap(value.toDouble(), minCadence.toDouble(), maxCadence.toDouble(), 0.0, 1.0) ?: 0.0
|
val progress = remap(value.toDouble(), minCadence.toDouble(), maxCadence.toDouble(), 0.0, 1.0) ?: 0.0
|
||||||
|
|
||||||
powerbar.minTarget = remap(streamData.cadenceTarget?.values[FIELD_TARGET_MIN_ID]?.toDouble(), minCadence.toDouble(), maxCadence.toDouble(), 0.0, 1.0)
|
powerbar.minTarget = remap(streamData.cadenceTarget?.values?.get(FIELD_TARGET_MIN_ID)?.toDouble(), minCadence.toDouble(), maxCadence.toDouble(), 0.0, 1.0)
|
||||||
powerbar.maxTarget = remap(streamData.cadenceTarget?.values[FIELD_TARGET_MAX_ID]?.toDouble(), minCadence.toDouble(), maxCadence.toDouble(), 0.0, 1.0)
|
powerbar.maxTarget = remap(streamData.cadenceTarget?.values?.get(FIELD_TARGET_MAX_ID)?.toDouble(), minCadence.toDouble(), maxCadence.toDouble(), 0.0, 1.0)
|
||||||
powerbar.target = remap(streamData.cadenceTarget?.values[FIELD_TARGET_VALUE_ID]?.toDouble(), minCadence.toDouble(), maxCadence.toDouble(), 0.0, 1.0)
|
powerbar.target = remap(streamData.cadenceTarget?.values?.get(FIELD_TARGET_VALUE_ID)?.toDouble(), minCadence.toDouble(), maxCadence.toDouble(), 0.0, 1.0)
|
||||||
|
|
||||||
@ColorRes val zoneColorRes = Zone.entries[(progress * Zone.entries.size).roundToInt().coerceIn(0..<Zone.entries.size)].colorResource
|
@ColorRes val zoneColorRes = Zone.entries[(progress * Zone.entries.size).roundToInt().coerceIn(0..<Zone.entries.size)].colorResource
|
||||||
|
|
||||||
@ -334,9 +360,9 @@ class Window(
|
|||||||
val maxHr = customMaxHr ?: streamData.userProfile.maxHr
|
val maxHr = customMaxHr ?: streamData.userProfile.maxHr
|
||||||
val progress = remap(value.toDouble(), minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
val progress = remap(value.toDouble(), minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
||||||
|
|
||||||
powerbar.minTarget = remap(streamData.heartrateTarget?.values[FIELD_TARGET_MIN_ID]?.toDouble(), minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
powerbar.minTarget = remap(streamData.heartrateTarget?.values?.get(FIELD_TARGET_MIN_ID), minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
||||||
powerbar.maxTarget = remap(streamData.heartrateTarget?.values[FIELD_TARGET_MAX_ID]?.toDouble(), minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
powerbar.maxTarget = remap(streamData.heartrateTarget?.values?.get(FIELD_TARGET_MAX_ID), minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
||||||
powerbar.target = remap(streamData.heartrateTarget?.values[FIELD_TARGET_VALUE_ID]?.toDouble(), minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
powerbar.target = remap(streamData.heartrateTarget?.values?.get(FIELD_TARGET_VALUE_ID), minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
||||||
|
|
||||||
powerbar.progressColor = if (streamData.settings?.useZoneColors == true) {
|
powerbar.progressColor = if (streamData.settings?.useZoneColors == true) {
|
||||||
context.getColor(getZone(streamData.userProfile.heartRateZones, value)?.colorResource ?: R.color.zone7)
|
context.getColor(getZone(streamData.userProfile.heartRateZones, value)?.colorResource ?: R.color.zone7)
|
||||||
@ -389,9 +415,9 @@ class Window(
|
|||||||
val maxPower = customMaxPower ?: (streamData.userProfile.powerZones.last().min + 30)
|
val maxPower = customMaxPower ?: (streamData.userProfile.powerZones.last().min + 30)
|
||||||
val progress = remap(value.toDouble(), minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
val progress = remap(value.toDouble(), minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
||||||
|
|
||||||
powerbar.minTarget = remap(streamData.powerTarget?.values[FIELD_TARGET_MIN_ID]?.toDouble(), minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
powerbar.minTarget = remap(streamData.powerTarget?.values?.get(FIELD_TARGET_MIN_ID), minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
||||||
powerbar.maxTarget = remap(streamData.powerTarget?.values[FIELD_TARGET_MAX_ID]?.toDouble(), minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
powerbar.maxTarget = remap(streamData.powerTarget?.values?.get(FIELD_TARGET_MAX_ID), minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
||||||
powerbar.target = remap(streamData.powerTarget?.values[FIELD_TARGET_VALUE_ID]?.toDouble(), minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
powerbar.target = remap(streamData.powerTarget?.values?.get(FIELD_TARGET_VALUE_ID), minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
||||||
|
|
||||||
powerbar.progressColor = if (streamData.settings?.useZoneColors == true) {
|
powerbar.progressColor = if (streamData.settings?.useZoneColors == true) {
|
||||||
context.getColor(getZone(streamData.userProfile.powerZones, value)?.colorResource ?: R.color.zone7)
|
context.getColor(getZone(streamData.userProfile.powerZones, value)?.colorResource ?: R.color.zone7)
|
||||||
|
|||||||
@ -59,7 +59,6 @@ import androidx.datastore.preferences.core.edit
|
|||||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||||
import de.timklge.karoopowerbar.CustomProgressBarBarSize
|
import de.timklge.karoopowerbar.CustomProgressBarBarSize
|
||||||
import de.timklge.karoopowerbar.CustomProgressBarFontSize
|
import de.timklge.karoopowerbar.CustomProgressBarFontSize
|
||||||
import de.timklge.karoopowerbar.CustomProgressBarSize
|
|
||||||
import de.timklge.karoopowerbar.KarooPowerbarExtension
|
import de.timklge.karoopowerbar.KarooPowerbarExtension
|
||||||
import de.timklge.karoopowerbar.PowerbarSettings
|
import de.timklge.karoopowerbar.PowerbarSettings
|
||||||
import de.timklge.karoopowerbar.R
|
import de.timklge.karoopowerbar.R
|
||||||
@ -88,7 +87,8 @@ enum class SelectedSource(val id: String, val label: String) {
|
|||||||
SPEED_3S("speed_3s", "Speed (3 sec avg"),
|
SPEED_3S("speed_3s", "Speed (3 sec avg"),
|
||||||
CADENCE("cadence", "Cadence"),
|
CADENCE("cadence", "Cadence"),
|
||||||
CADENCE_3S("cadence_3s", "Cadence (3 sec avg)"),
|
CADENCE_3S("cadence_3s", "Cadence (3 sec avg)"),
|
||||||
ROUTE_PROGRESS("route_progress", "Route Progress");
|
ROUTE_PROGRESS("route_progress", "Route Progress"),
|
||||||
|
REMAINING_ROUTE("route_progress_remaining", "Route Remaining");
|
||||||
|
|
||||||
fun isPower() = this == POWER || this == POWER_3S || this == POWER_10S
|
fun isPower() = this == POWER || this == POWER_3S || this == POWER_10S
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user