fix #3: Fix handling of manually configured power and hr zones
This commit is contained in:
parent
d9b8fac445
commit
bc782e7f90
@ -13,8 +13,8 @@ android {
|
|||||||
applicationId = "de.timklge.karoopowerbar"
|
applicationId = "de.timklge.karoopowerbar"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 33
|
targetSdk = 33
|
||||||
versionCode = 3
|
versionCode = 4
|
||||||
versionName = "1.1.0"
|
versionName = "1.1.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@ -3,9 +3,9 @@
|
|||||||
"packageName": "de.timklge.karoopowerbar",
|
"packageName": "de.timklge.karoopowerbar",
|
||||||
"iconUrl": "https://github.com/timklge/karoo-powerbar/releases/latest/download/karoo-powerbar.png",
|
"iconUrl": "https://github.com/timklge/karoo-powerbar/releases/latest/download/karoo-powerbar.png",
|
||||||
"latestApkUrl": "https://github.com/timklge/karoo-powerbar/releases/latest/download/app-release.apk",
|
"latestApkUrl": "https://github.com/timklge/karoo-powerbar/releases/latest/download/app-release.apk",
|
||||||
"latestVersion": "1.1.0",
|
"latestVersion": "1.1.1",
|
||||||
"latestVersionCode": 3,
|
"latestVersionCode": 4,
|
||||||
"developer": "timklge",
|
"developer": "timklge",
|
||||||
"description": "Adds a colored power bar to the bottom of the screen",
|
"description": "Adds a colored power bar to the bottom of the screen",
|
||||||
"releaseNotes": "Add options to add secondary power bar and to hide bar when not riding"
|
"releaseNotes": "Add options to add secondary power bar and to hide bar when not riding. Fix manually set up power/hr zones."
|
||||||
}
|
}
|
||||||
@ -10,7 +10,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class KarooPowerbarExtension : KarooExtension("karoo-powerbar", "1.1.0") {
|
class KarooPowerbarExtension : KarooExtension("karoo-powerbar", "1.1.1") {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "karoo-powerbar"
|
const val TAG = "karoo-powerbar"
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.mapNotNull
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
fun remap(value: Double, fromMin: Double, fromMax: Double, toMin: Double, toMax: Double): Double {
|
fun remap(value: Double, fromMin: Double, fromMax: Double, toMin: Double, toMax: Double): Double {
|
||||||
return (value - fromMin) * (toMax - toMin) / (fromMax - fromMin) + toMin
|
return (value - fromMin) * (toMax - toMin) / (fromMax - fromMin) + toMin
|
||||||
@ -102,11 +103,11 @@ class Window(
|
|||||||
Log.i(TAG, "Karoo system service connected: $connected")
|
Log.i(TAG, "Karoo system service connected: $connected")
|
||||||
}
|
}
|
||||||
|
|
||||||
powerbar.progressColor = context.resources.getColor(R.color.zoneAerobic)
|
powerbar.progressColor = context.resources.getColor(R.color.zone7)
|
||||||
powerbar.progress = 0.0
|
powerbar.progress = 0.0
|
||||||
powerbar.invalidate()
|
powerbar.invalidate()
|
||||||
|
|
||||||
Log.i(KarooPowerbarExtension.TAG, "Streaming $selectedSource")
|
Log.i(TAG, "Streaming $selectedSource")
|
||||||
|
|
||||||
when (selectedSource){
|
when (selectedSource){
|
||||||
SelectedSource.POWER -> streamPower(PowerStreamSmoothing.RAW)
|
SelectedSource.POWER -> streamPower(PowerStreamSmoothing.RAW)
|
||||||
@ -124,7 +125,7 @@ class Window(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(KarooPowerbarExtension.TAG, e.toString())
|
Log.e(TAG, e.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,20 +140,21 @@ class Window(
|
|||||||
.map { (userProfile, hr) -> StreamData(userProfile, hr) }
|
.map { (userProfile, hr) -> StreamData(userProfile, hr) }
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.collect { streamData ->
|
.collect { streamData ->
|
||||||
|
val value = streamData.value.roundToInt()
|
||||||
val color = context.getColor(
|
val color = context.getColor(
|
||||||
streamData.userProfile.getUserHrZone(streamData.value.toInt())?.colorResource
|
streamData.userProfile.getZone(streamData.userProfile.heartRateZones, value)?.colorResource
|
||||||
?: R.color.zoneAerobic
|
?: R.color.zone7
|
||||||
)
|
)
|
||||||
val minHr = streamData.userProfile.restingHr
|
val minHr = streamData.userProfile.restingHr
|
||||||
val maxHr = streamData.userProfile.maxHr
|
val maxHr = streamData.userProfile.maxHr
|
||||||
val progress =
|
val progress =
|
||||||
remap(streamData.value, minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
remap(value.toDouble(), minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
||||||
|
|
||||||
powerbar.progressColor = color
|
powerbar.progressColor = color
|
||||||
powerbar.progress = progress
|
powerbar.progress = progress
|
||||||
powerbar.invalidate()
|
powerbar.invalidate()
|
||||||
|
|
||||||
Log.d(KarooPowerbarExtension.TAG, "Hr: ${streamData.value} min: $minHr max: $maxHr")
|
Log.d(TAG, "Hr: $value min: $minHr max: $maxHr")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,20 +175,21 @@ class Window(
|
|||||||
.map { (userProfile, power) -> StreamData(userProfile, power) }
|
.map { (userProfile, power) -> StreamData(userProfile, power) }
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.collect { streamData ->
|
.collect { streamData ->
|
||||||
|
val value = streamData.value.roundToInt()
|
||||||
val color = context.getColor(
|
val color = context.getColor(
|
||||||
streamData.userProfile.getUserPowerZone(streamData.value.toInt())?.colorResource
|
streamData.userProfile.getZone(streamData.userProfile.powerZones, value)?.colorResource
|
||||||
?: R.color.zoneAerobic
|
?: R.color.zone7
|
||||||
)
|
)
|
||||||
val minPower = streamData.userProfile.powerZones.first().min
|
val minPower = streamData.userProfile.powerZones.first().min
|
||||||
val maxPower = streamData.userProfile.powerZones.last().min + 50
|
val maxPower = streamData.userProfile.powerZones.last().min + 50
|
||||||
val progress =
|
val progress =
|
||||||
remap(streamData.value, minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
remap(value.toDouble(), minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
||||||
|
|
||||||
powerbar.progressColor = color
|
powerbar.progressColor = color
|
||||||
powerbar.progress = progress
|
powerbar.progress = progress
|
||||||
powerbar.invalidate()
|
powerbar.invalidate()
|
||||||
|
|
||||||
Log.d(KarooPowerbarExtension.TAG, "Power: ${streamData.value} min: $minPower max: $maxPower")
|
Log.d(TAG, "Power: ${value} min: $minPower max: $maxPower")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,7 +200,7 @@ class Window(
|
|||||||
rootView.invalidate()
|
rootView.invalidate()
|
||||||
(rootView.parent as ViewGroup).removeAllViews()
|
(rootView.parent as ViewGroup).removeAllViews()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.d(KarooPowerbarExtension.TAG, e.toString())
|
Log.d(TAG, e.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,38 +2,36 @@ package de.timklge.karoopowerbar
|
|||||||
|
|
||||||
import io.hammerhead.karooext.models.UserProfile
|
import io.hammerhead.karooext.models.UserProfile
|
||||||
|
|
||||||
enum class PowerZone(val colorResource: Int) {
|
enum class Zone(val colorResource: Int){
|
||||||
ACTIVE_RECOVERY(R.color.zoneActiveRecovery),
|
Zone0(R.color.zone0),
|
||||||
ENDURANCE(R.color.zoneEndurance),
|
Zone1(R.color.zone1),
|
||||||
TEMPO(R.color.zoneTempo),
|
Zone2(R.color.zone2),
|
||||||
THRESHOLD(R.color.zoneThreshold),
|
Zone3(R.color.zone3),
|
||||||
VO2_MAX(R.color.zoneVO2Max),
|
Zone4(R.color.zone4),
|
||||||
AEROBIC_CAPACITY(R.color.zoneAerobic),
|
Zone5(R.color.zone5),
|
||||||
ANAEROBIC_CAPACITY(R.color.zoneAnaerobic),
|
Zone6(R.color.zone6),
|
||||||
|
Zone7(R.color.zone7),
|
||||||
|
Zone8(R.color.zone8),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class HrZone(val colorResource: Int) {
|
val zones = mapOf(
|
||||||
ACTIVE_RECOVERY(R.color.zoneActiveRecovery),
|
1 to listOf(Zone.Zone7),
|
||||||
ENDURANCE(R.color.zoneEndurance),
|
2 to listOf(Zone.Zone1, Zone.Zone7),
|
||||||
TEMPO(R.color.zoneTempo),
|
3 to listOf(Zone.Zone1, Zone.Zone3, Zone.Zone7),
|
||||||
THRESHOLD(R.color.zoneThreshold),
|
4 to listOf(Zone.Zone1, Zone.Zone3, Zone.Zone5, Zone.Zone7),
|
||||||
VO2_MAX(R.color.zoneAerobic),
|
5 to listOf(Zone.Zone1, Zone.Zone2, Zone.Zone3, Zone.Zone5, Zone.Zone7),
|
||||||
}
|
6 to listOf(Zone.Zone1, Zone.Zone2, Zone.Zone3, Zone.Zone5, Zone.Zone7, Zone.Zone8),
|
||||||
|
7 to listOf(Zone.Zone1, Zone.Zone2, Zone.Zone3, Zone.Zone5, Zone.Zone6, Zone.Zone7, Zone.Zone8),
|
||||||
|
8 to listOf(Zone.Zone0, Zone.Zone1, Zone.Zone2, Zone.Zone3, Zone.Zone5, Zone.Zone6, Zone.Zone7, Zone.Zone8),
|
||||||
|
9 to listOf(Zone.Zone0, Zone.Zone1, Zone.Zone2, Zone.Zone3, Zone.Zone4, Zone.Zone5, Zone.Zone6, Zone.Zone7, Zone.Zone8)
|
||||||
|
)
|
||||||
|
|
||||||
fun UserProfile.getUserPowerZone(power: Int): PowerZone? {
|
fun UserProfile.getZone(userZones: List<UserProfile.Zone>, value: Int): Zone? {
|
||||||
powerZones.forEachIndexed { index, zone ->
|
val zoneList = zones[userZones.size] ?: return null
|
||||||
if (power in zone.min..zone.max) {
|
|
||||||
return PowerZone.entries[index]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
userZones.forEachIndexed { index, zone ->
|
||||||
}
|
if (value in zone.min..zone.max) {
|
||||||
|
return zoneList.getOrNull(index) ?: Zone.Zone7
|
||||||
fun UserProfile.getUserHrZone(hr: Int): HrZone? {
|
|
||||||
heartRateZones.forEachIndexed { index, zone ->
|
|
||||||
if (hr in zone.min..zone.max) {
|
|
||||||
return HrZone.entries[index]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,11 +3,13 @@
|
|||||||
<color name="colorPrimary">#6200EE</color>
|
<color name="colorPrimary">#6200EE</color>
|
||||||
<color name="colorPrimaryDark">#2600B3</color>
|
<color name="colorPrimaryDark">#2600B3</color>
|
||||||
|
|
||||||
<color name="zoneActiveRecovery">#00B988</color>
|
<color name="zone0">#2386D9</color>
|
||||||
<color name="zoneEndurance">#60EEB2</color>
|
<color name="zone1">#00B988</color>
|
||||||
<color name="zoneTempo">#FFF500</color>
|
<color name="zone2">#60EEB2</color>
|
||||||
<color name="zoneThreshold">#FB8C65</color>
|
<color name="zone3">#FFF500</color>
|
||||||
<color name="zoneVO2Max">#FE581F</color>
|
<color name="zone4">#FDC84C</color>
|
||||||
<color name="zoneAerobic">#D60404</color>
|
<color name="zone5">#FB8C65</color>
|
||||||
<color name="zoneAnaerobic">#B700A2</color>
|
<color name="zone6">#FE581F</color>
|
||||||
|
<color name="zone7">#D60404</color>
|
||||||
|
<color name="zone8">#B700A2</color>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
x
Reference in New Issue
Block a user