Compare commits

..

14 Commits

Author SHA1 Message Date
b48138f196 Fix base url quotation
All checks were successful
Build / build (push) Successful in 4m42s
2025-05-29 15:17:06 +02:00
2bb9c59bff Only replace base url in manifest as part of ci build
All checks were successful
Build / build (push) Successful in 4m34s
2025-05-28 17:37:58 +02:00
6db3097e66 Fix gradle task order
All checks were successful
Build / build (push) Successful in 8m21s
2025-05-28 17:33:37 +02:00
da448b7407 Replace BASE_URL on build
All checks were successful
Build / build (push) Successful in 8m14s
2025-05-28 17:14:51 +02:00
76def03651 Fix BASE_URL
All checks were successful
Build / build (push) Successful in 6m55s
2025-05-28 16:50:58 +02:00
cdafc7cedd Test BASE_URL parameter
All checks were successful
Build / build (push) Successful in 7m10s
2025-05-28 16:35:37 +02:00
f020cc4e2f Update release parameters 2025-05-28 16:31:07 +02:00
bc1d03f053 Test release action
All checks were successful
Build / build (push) Successful in 4m36s
2025-05-28 16:08:38 +02:00
a54abf2667 Change to v3 release action
All checks were successful
Build / build (push) Successful in 7m16s
2025-05-28 15:23:07 +02:00
7ffb6867b7 Merge branch 'master' into feat/workout-range-distance 2025-05-28 15:15:43 +02:00
dfedd1afe5 Update changelog 2025-05-28 15:15:33 +02:00
65e7ea4d14 Fix powerbar is not redrawn in route progress mode 2025-05-27 22:35:38 +02:00
3e1fa2169b Update target range drawing 2025-05-27 22:29:42 +02:00
72b9a0f57e Add route distance data source, workout target indication 2025-05-26 22:56:37 +02:00
7 changed files with 249 additions and 217 deletions

View File

@ -72,7 +72,7 @@ tasks.register("generateManifest") {
"latestVersionCode" to android.defaultConfig.versionCode, "latestVersionCode" to android.defaultConfig.versionCode,
"developer" to "github.com/timklge", "developer" to "github.com/timklge",
"description" to "Open-source extension that adds colored power or heart rate progress bars to the edges of the screen, similar to the LEDs on Wahoo computers", "description" to "Open-source extension that adds colored power or heart rate progress bars to the edges of the screen, similar to the LEDs on Wahoo computers",
"releaseNotes" to "* Add route progress data source\n* Add workout target range indicator\n* Make bars transparent by default\n* Split size setting", "releaseNotes" to "* Add route progress data source\n* Add workout target range indicator\n* Replace dropdown popup with fullscreen dialog",
"screenshotUrls" to listOf( "screenshotUrls" to listOf(
"$baseUrl/powerbar_min.gif", "$baseUrl/powerbar_min.gif",
"$baseUrl/powerbar0.png", "$baseUrl/powerbar0.png",

View File

@ -11,6 +11,14 @@ import android.util.AttributeSet
import android.view.View import android.view.View
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import kotlinx.serialization.Serializable
@Serializable
enum class CustomProgressBarSize(val id: String, val label: String, val fontSize: Float, val barHeight: Float) {
SMALL("small", "Small", 35f, 10f),
MEDIUM("medium", "Medium", 40f, 15f),
LARGE("large", "Large", 60f, 25f),
}
class CustomProgressBar @JvmOverloads constructor( class CustomProgressBar @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null context: Context, attrs: AttributeSet? = null
@ -22,30 +30,22 @@ class CustomProgressBar @JvmOverloads constructor(
var maxTarget: Double? = null var maxTarget: Double? = null
var target: Double? = null var target: Double? = null
var showLabel: Boolean = true var showLabel: Boolean = true
var barBackground: Boolean = false
@ColorInt var progressColor: Int = 0xFF2b86e6.toInt() @ColorInt var progressColor: Int = 0xFF2b86e6.toInt()
var fontSize = CustomProgressBarFontSize.MEDIUM var size = CustomProgressBarSize.MEDIUM
set(value) { set(value) {
field = value field = value
textPaint.textSize = value.fontSize textPaint.textSize = value.fontSize
invalidate() // Redraw to apply new font size
}
var barSize = CustomProgressBarBarSize.MEDIUM
set(value) {
field = value
targetZoneStrokePaint.strokeWidth = when(value){ targetZoneStrokePaint.strokeWidth = when(value){
CustomProgressBarBarSize.NONE, CustomProgressBarBarSize.SMALL -> 3f CustomProgressBarSize.SMALL -> 3f
CustomProgressBarBarSize.MEDIUM -> 6f CustomProgressBarSize.MEDIUM -> 6f
CustomProgressBarBarSize.LARGE -> 8f CustomProgressBarSize.LARGE -> 8f
} }
targetIndicatorPaint.strokeWidth = when(value){ targetIndicatorPaint.strokeWidth = when(value){
CustomProgressBarBarSize.NONE, CustomProgressBarBarSize.SMALL -> 6f CustomProgressBarSize.SMALL -> 6f
CustomProgressBarBarSize.MEDIUM -> 8f CustomProgressBarSize.MEDIUM -> 8f
CustomProgressBarBarSize.LARGE -> 10f CustomProgressBarSize.LARGE -> 10f
} }
invalidate() // Redraw to apply new bar size
} }
private val targetColor = 0xFF9933FF.toInt() private val targetColor = 0xFF9933FF.toInt()
@ -80,7 +80,7 @@ class CustomProgressBar @JvmOverloads constructor(
private val blurPaint = Paint().apply { private val blurPaint = Paint().apply {
isAntiAlias = true isAntiAlias = true
strokeWidth = 6f strokeWidth = 4f
style = Paint.Style.STROKE style = Paint.Style.STROKE
color = progressColor color = progressColor
maskFilter = BlurMaskFilter(3f, BlurMaskFilter.Blur.NORMAL) maskFilter = BlurMaskFilter(3f, BlurMaskFilter.Blur.NORMAL)
@ -88,7 +88,7 @@ class CustomProgressBar @JvmOverloads constructor(
private val blurPaintHighlight = Paint().apply { private val blurPaintHighlight = Paint().apply {
isAntiAlias = true isAntiAlias = true
strokeWidth = 10f strokeWidth = 8f
style = Paint.Style.FILL_AND_STROKE style = Paint.Style.FILL_AND_STROKE
color = ColorUtils.blendARGB(progressColor, 0xFFFFFF, 0.5f) color = ColorUtils.blendARGB(progressColor, 0xFFFFFF, 0.5f)
maskFilter = BlurMaskFilter(6f, BlurMaskFilter.Blur.NORMAL) maskFilter = BlurMaskFilter(6f, BlurMaskFilter.Blur.NORMAL)
@ -109,7 +109,7 @@ class CustomProgressBar @JvmOverloads constructor(
private val textPaint = Paint().apply { private val textPaint = Paint().apply {
color = Color.WHITE color = Color.WHITE
strokeWidth = 3f strokeWidth = 3f
textSize = fontSize.fontSize textSize = size.fontSize
typeface = Typeface.create(Typeface.MONOSPACE, Typeface.BOLD) typeface = Typeface.create(Typeface.MONOSPACE, Typeface.BOLD)
textAlign = Paint.Align.CENTER textAlign = Paint.Align.CENTER
} }
@ -134,18 +134,19 @@ class CustomProgressBar @JvmOverloads constructor(
when (location) { when (location) {
PowerbarLocation.TOP -> { PowerbarLocation.TOP -> {
val barTop = 15f
val barBottom = barTop + size.barHeight
val rect = RectF( val rect = RectF(
1f, 1f,
15f, barTop,
((canvas.width.toDouble() - 1f) * (progress ?: 0.0).coerceIn(0.0, 1.0)).toFloat(), ((canvas.width.toDouble() - 1f) * (progress ?: 0.0).coerceIn(
15f + barSize.barHeight // barSize.barHeight will be 0f if NONE 0.0,
1.0
)).toFloat(),
barBottom
) )
// Draw bar components only if barSize is not NONE canvas.drawRect(0f, barTop, canvas.width.toFloat(), barBottom, backgroundPaint)
if (barSize != CustomProgressBarBarSize.NONE) {
if (barBackground){
canvas.drawRect(0f, 15f, canvas.width.toFloat(), 15f + barSize.barHeight, backgroundPaint)
}
// Draw target zone fill behind the progress bar // Draw target zone fill behind the progress bar
if (minTarget != null && maxTarget != null) { if (minTarget != null && maxTarget != null) {
@ -153,9 +154,9 @@ class CustomProgressBar @JvmOverloads constructor(
val maxTargetX = (canvas.width * maxTarget!!).toFloat() val maxTargetX = (canvas.width * maxTarget!!).toFloat()
canvas.drawRoundRect( canvas.drawRoundRect(
minTargetX, minTargetX,
15f, barTop,
maxTargetX, maxTargetX,
15f + barSize.barHeight, barBottom,
2f, 2f,
2f, 2f,
targetZoneFillPaint targetZoneFillPaint
@ -165,11 +166,17 @@ class CustomProgressBar @JvmOverloads constructor(
if (progress != null) { if (progress != null) {
canvas.drawRoundRect(rect, 2f, 2f, blurPaint) canvas.drawRoundRect(rect, 2f, 2f, blurPaint)
canvas.drawRoundRect(rect, 2f, 2f, linePaint) canvas.drawRoundRect(rect, 2f, 2f, linePaint)
canvas.drawRoundRect(rect.right-4, rect.top, rect.right+4, rect.bottom, 2f, 2f, blurPaintHighlight)
} canvas.drawRoundRect(
} rect.right - 4,
// Draw label (if progress is not null and showLabel is true) rect.top,
if (progress != null) { rect.right + 4,
rect.bottom,
2f,
2f,
blurPaintHighlight
)
// Draw target zone stroke after progress bar, before label // Draw target zone stroke after progress bar, before label
if (minTarget != null && maxTarget != null) { if (minTarget != null && maxTarget != null) {
val minTargetX = (canvas.width * minTarget!!).toFloat() val minTargetX = (canvas.width * minTarget!!).toFloat()
@ -177,9 +184,9 @@ class CustomProgressBar @JvmOverloads constructor(
// Draw stroked rounded rectangle for the target zone // Draw stroked rounded rectangle for the target zone
canvas.drawRoundRect( canvas.drawRoundRect(
minTargetX, minTargetX,
15f, barTop,
maxTargetX, maxTargetX,
15f + barSize.barHeight, barBottom,
2f, 2f,
2f, 2f,
targetZoneStrokePaint targetZoneStrokePaint
@ -190,54 +197,101 @@ class CustomProgressBar @JvmOverloads constructor(
if (target != null) { if (target != null) {
val targetX = (canvas.width * target!!).toFloat() val targetX = (canvas.width * target!!).toFloat()
targetIndicatorPaint.color = if (isTargetMet) Color.GREEN else Color.RED targetIndicatorPaint.color = if (isTargetMet) Color.GREEN else Color.RED
canvas.drawLine(targetX, 15f, targetX, 15f + barSize.barHeight, targetIndicatorPaint) canvas.drawLine(targetX, barTop, targetX, barBottom, targetIndicatorPaint)
} }
if (showLabel) { if (showLabel) {
val textContent =
label // Store original label, as textPaint.measureText can be slow
val measuredTextWidth = textPaint.measureText(textContent)
val labelBoxWidth = (measuredTextWidth + 20).coerceAtLeast(10f)
val labelBoxHeight = size.fontSize + 10f // Consistent height with padding
// Calculate horizontal position for the label box (centered around progress end, clamped)
val labelBoxLeft = (rect.right - labelBoxWidth / 2f).coerceIn(
0f,
canvas.width - labelBoxWidth
)
var labelBoxTop: Float
var labelBoxBottom: Float
var textYPosition: Float
if (target != null) { // If workout target is present, move label BELOW the bar
val labelPadding = 5f // Padding between bar and label box
labelBoxTop = barBottom + labelPadding
labelBoxBottom = labelBoxTop + labelBoxHeight
// Vertically center text in the new box
val labelBoxCenterY = labelBoxTop + labelBoxHeight / 2f
textYPosition =
labelBoxCenterY - (textPaint.ascent() + textPaint.descent()) / 2f
} else { // Original position for TOP
val yOffsetOriginal = when (size) {
CustomProgressBarSize.SMALL -> (size.fontSize - size.barHeight) / 2 + 2f
CustomProgressBarSize.MEDIUM, CustomProgressBarSize.LARGE -> (size.fontSize - size.barHeight) / 2
}
labelBoxTop = barTop - yOffsetOriginal
labelBoxBottom =
barBottom + yOffsetOriginal // Original calculation was based on rect.bottom which is barBottom
textYPosition = barBottom + 6f // Original text Y
}
lineStrokePaint.color = if (target != null){ lineStrokePaint.color = if (target != null){
if (isTargetMet) Color.GREEN else Color.RED if (isTargetMet) Color.GREEN else Color.RED
} else progressColor } else progressColor
blurPaint.color = lineStrokePaint.color canvas.drawRoundRect(
blurPaintHighlight.color = ColorUtils.blendARGB(lineStrokePaint.color, 0xFFFFFF, 0.5f) labelBoxLeft,
labelBoxTop,
labelBoxLeft + labelBoxWidth,
labelBoxBottom,
2f,
2f,
textBackgroundPaint
)
canvas.drawRoundRect(
labelBoxLeft,
labelBoxTop,
labelBoxLeft + labelBoxWidth,
labelBoxBottom,
2f,
2f,
blurPaint
)
canvas.drawRoundRect(
labelBoxLeft,
labelBoxTop,
labelBoxLeft + labelBoxWidth,
labelBoxBottom,
2f,
2f,
lineStrokePaint
)
val textBounds = textPaint.measureText(label) canvas.drawText(
val xOffset = (textBounds + 20).coerceAtLeast(10f) / 2f textContent,
val x = (rect.right - xOffset).coerceIn(0f..canvas.width-xOffset*2f) labelBoxLeft + labelBoxWidth / 2f,
val r = x + xOffset * 2 textYPosition,
textPaint
val fm = textPaint.fontMetrics )
// barCenterY calculation uses barSize.barHeight, which is 0f for NONE,
// correctly centering the label on the 15f line.
val barCenterY = rect.top + barSize.barHeight / 2f
val centeredTextBaselineY = barCenterY - (fm.ascent + fm.descent) / 2f
val calculatedTextBoxTop = centeredTextBaselineY + fm.ascent
val finalTextBoxTop = calculatedTextBoxTop.coerceAtLeast(0f)
val finalTextBaselineY = finalTextBoxTop - fm.ascent
val finalTextBoxBottom = finalTextBaselineY + fm.descent
canvas.drawRoundRect(x, finalTextBoxTop, r, finalTextBoxBottom, 2f, 2f, textBackgroundPaint)
canvas.drawRoundRect(x, finalTextBoxTop, r, finalTextBoxBottom, 2f, 2f, blurPaint)
canvas.drawRoundRect(x, finalTextBoxTop, r, finalTextBoxBottom, 2f, 2f, lineStrokePaint)
canvas.drawText(label, x + xOffset, finalTextBaselineY, textPaint)
} }
} }
} }
PowerbarLocation.BOTTOM -> { PowerbarLocation.BOTTOM -> {
val barTop = canvas.height.toFloat() - 1f - size.barHeight
val barBottom = canvas.height.toFloat()
val rect = RectF( val rect = RectF(
1f, 1f,
canvas.height.toFloat() - 1f - barSize.barHeight, // barSize.barHeight will be 0f if NONE barTop,
((canvas.width.toDouble() - 1f) * (progress ?: 0.0).coerceIn(0.0, 1.0)).toFloat(), ((canvas.width.toDouble() - 1f) * (progress ?: 0.0).coerceIn(
canvas.height.toFloat() 0.0,
1.0
)).toFloat(),
barBottom
) )
// Draw bar components only if barSize is not NONE canvas.drawRect(0f, barTop, canvas.width.toFloat(), barBottom, backgroundPaint)
if (barSize != CustomProgressBarBarSize.NONE) {
if (barBackground){
// Use barSize.barHeight for background top calculation
canvas.drawRect(0f, canvas.height.toFloat() - barSize.barHeight, canvas.width.toFloat(), canvas.height.toFloat(), backgroundPaint)
}
// Draw target zone fill behind the progress bar // Draw target zone fill behind the progress bar
if (minTarget != null && maxTarget != null) { if (minTarget != null && maxTarget != null) {
@ -245,9 +299,9 @@ class CustomProgressBar @JvmOverloads constructor(
val maxTargetX = (canvas.width * maxTarget!!).toFloat() val maxTargetX = (canvas.width * maxTarget!!).toFloat()
canvas.drawRoundRect( canvas.drawRoundRect(
minTargetX, minTargetX,
canvas.height.toFloat() - barSize.barHeight, barTop,
maxTargetX, maxTargetX,
canvas.height.toFloat(), barBottom,
2f, 2f,
2f, 2f,
targetZoneFillPaint targetZoneFillPaint
@ -257,12 +311,17 @@ class CustomProgressBar @JvmOverloads constructor(
if (progress != null) { if (progress != null) {
canvas.drawRoundRect(rect, 2f, 2f, blurPaint) canvas.drawRoundRect(rect, 2f, 2f, blurPaint)
canvas.drawRoundRect(rect, 2f, 2f, linePaint) canvas.drawRoundRect(rect, 2f, 2f, linePaint)
canvas.drawRoundRect(rect.right-4, rect.top, rect.right+4, rect.bottom, 2f, 2f, blurPaintHighlight)
}
}
// Draw label (if progress is not null and showLabel is true) canvas.drawRoundRect(
if (progress != null) { rect.right - 4,
rect.top,
rect.right + 4,
rect.bottom,
2f,
2f,
blurPaintHighlight
)
// Draw target zone stroke after progress bar, before label // Draw target zone stroke after progress bar, before label
if (minTarget != null && maxTarget != null) { if (minTarget != null && maxTarget != null) {
val minTargetX = (canvas.width * minTarget!!).toFloat() val minTargetX = (canvas.width * minTarget!!).toFloat()
@ -270,9 +329,9 @@ class CustomProgressBar @JvmOverloads constructor(
// Draw stroked rounded rectangle for the target zone // Draw stroked rounded rectangle for the target zone
canvas.drawRoundRect( canvas.drawRoundRect(
minTargetX, minTargetX,
canvas.height.toFloat() - barSize.barHeight, barTop,
maxTargetX, maxTargetX,
canvas.height.toFloat(), barBottom,
2f, 2f,
2f, 2f,
targetZoneStrokePaint targetZoneStrokePaint
@ -283,33 +342,83 @@ class CustomProgressBar @JvmOverloads constructor(
if (target != null) { if (target != null) {
val targetX = (canvas.width * target!!).toFloat() val targetX = (canvas.width * target!!).toFloat()
targetIndicatorPaint.color = if (isTargetMet) Color.GREEN else Color.RED targetIndicatorPaint.color = if (isTargetMet) Color.GREEN else Color.RED
canvas.drawLine(targetX, canvas.height.toFloat() - barSize.barHeight, targetX, canvas.height.toFloat(), targetIndicatorPaint) canvas.drawLine(targetX, barTop, targetX, barBottom, targetIndicatorPaint)
} }
if (showLabel) { if (showLabel) {
val textContent = label // Store original label
val measuredTextWidth = textPaint.measureText(textContent)
val labelBoxWidth = (measuredTextWidth + 20).coerceAtLeast(10f)
val labelBoxHeight = size.fontSize + 10f // Consistent height with padding
// Calculate horizontal position for the label box (centered around progress end, clamped)
val labelBoxLeft = (rect.right - labelBoxWidth / 2f).coerceIn(
0f,
canvas.width - labelBoxWidth
)
var labelBoxTop: Float
var labelBoxBottom: Float
var textYPosition: Float
if (target != null) { // If workout target is present, move label ABOVE the bar
val labelPadding = 5f // Padding between bar and label box
labelBoxBottom = barTop - labelPadding
labelBoxTop = labelBoxBottom - labelBoxHeight
// Vertically center text in the new box
val labelBoxCenterY = labelBoxTop + labelBoxHeight / 2f
textYPosition =
labelBoxCenterY - (textPaint.ascent() + textPaint.descent()) / 2f
} else { // Original position for BOTTOM
val yOffsetOriginal = when (size) {
CustomProgressBarSize.SMALL -> size.fontSize / 2 + 2f
CustomProgressBarSize.MEDIUM -> size.fontSize / 2
CustomProgressBarSize.LARGE -> size.fontSize / 2 - 5f
}
labelBoxTop = barTop - yOffsetOriginal
labelBoxBottom = barBottom + 5f // Original 'b' calculation
textYPosition =
barBottom - 1f // Original text Y (rect.top + size.barHeight -1)
}
lineStrokePaint.color = if (target != null){ lineStrokePaint.color = if (target != null){
if (isTargetMet) Color.GREEN else Color.RED if (isTargetMet) Color.GREEN else Color.RED
} else progressColor } else progressColor
blurPaint.color = lineStrokePaint.color canvas.drawRoundRect(
blurPaintHighlight.color = ColorUtils.blendARGB(lineStrokePaint.color, 0xFFFFFF, 0.5f) labelBoxLeft,
labelBoxTop,
labelBoxLeft + labelBoxWidth,
labelBoxBottom,
2f,
2f,
textBackgroundPaint
)
canvas.drawRoundRect(
labelBoxLeft,
labelBoxTop,
labelBoxLeft + labelBoxWidth,
labelBoxBottom,
2f,
2f,
blurPaint
)
canvas.drawRoundRect(
labelBoxLeft,
labelBoxTop,
labelBoxLeft + labelBoxWidth,
labelBoxBottom,
2f,
2f,
lineStrokePaint
)
val textBounds = textPaint.measureText(label) canvas.drawText(
val xOffset = (textBounds + 20).coerceAtLeast(10f) / 2f textContent,
val x = (rect.right - xOffset).coerceIn(0f..canvas.width-xOffset*2f) labelBoxLeft + labelBoxWidth / 2f,
val r = x + xOffset * 2 textYPosition,
textPaint
// textDrawBaselineY calculation uses rect.top and barSize.barHeight. )
// If NONE, barSize.barHeight is 0f. rect.top becomes canvas.height - 1f.
// So, baseline is (canvas.height - 1f) + 0f - 1f = canvas.height - 2f.
val textDrawBaselineY = rect.top + barSize.barHeight - 1f
val yBox = textDrawBaselineY + textPaint.ascent()
val bBox = textDrawBaselineY + textPaint.descent()
canvas.drawRoundRect(x, yBox, r, bBox, 2f, 2f, textBackgroundPaint)
canvas.drawRoundRect(x, yBox, r, bBox, 2f, 2f, blurPaint)
canvas.drawRoundRect(x, yBox, r, bBox, 2f, 2f, lineStrokePaint)
canvas.drawText(label, x + xOffset, textDrawBaselineY, textPaint)
} }
} }
} }

View File

@ -1,45 +0,0 @@
package de.timklge.karoopowerbar
import kotlinx.serialization.Serializable
@Serializable
enum class CustomProgressBarSize(val id: String, val label: String, val fontSize: Float, val barHeight: Float) {
SMALL("small", "Small", 35f, 10f),
MEDIUM("medium", "Medium", 40f, 15f),
LARGE("large", "Large", 60f, 25f),
}
@Serializable
enum class CustomProgressBarFontSize(val id: String, val label: String, val fontSize: Float) {
SMALL("small", "Small", 35f),
MEDIUM("medium", "Medium", 40f),
LARGE("large", "Large", 60f);
companion object {
fun fromSize(size: CustomProgressBarSize): CustomProgressBarFontSize {
return when (size) {
CustomProgressBarSize.SMALL -> SMALL
CustomProgressBarSize.MEDIUM -> MEDIUM
CustomProgressBarSize.LARGE -> LARGE
}
}
}
}
@Serializable
enum class CustomProgressBarBarSize(val id: String, val label: String, val barHeight: Float) {
NONE("none", "None", 0f),
SMALL("small", "Small", 10f),
MEDIUM("medium", "Medium", 15f),
LARGE("large", "Large", 25f);
companion object {
fun fromSize(size: CustomProgressBarSize): CustomProgressBarBarSize {
return when (size) {
CustomProgressBarSize.SMALL -> SMALL
CustomProgressBarSize.MEDIUM -> MEDIUM
CustomProgressBarSize.LARGE -> LARGE
}
}
}
}

View File

@ -53,7 +53,7 @@ class ForegroundService : Service() {
windows.clear() windows.clear()
if (settings.source != SelectedSource.NONE && showBars) { if (settings.source != SelectedSource.NONE && showBars) {
Window(this@ForegroundService, PowerbarLocation.BOTTOM, settings.showLabelOnBars, settings.barBackground, settings.barBarSize, settings.barFontSize).apply { Window(this@ForegroundService, PowerbarLocation.BOTTOM, settings.showLabelOnBars, settings.barSize).apply {
selectedSource = settings.source selectedSource = settings.source
windows.add(this) windows.add(this)
open() open()
@ -61,7 +61,7 @@ class ForegroundService : Service() {
} }
if (settings.topBarSource != SelectedSource.NONE && showBars){ if (settings.topBarSource != SelectedSource.NONE && showBars){
Window(this@ForegroundService, PowerbarLocation.TOP, settings.showLabelOnBars, settings.barBackground, settings.barBarSize, settings.barFontSize).apply { Window(this@ForegroundService, PowerbarLocation.TOP, settings.showLabelOnBars, settings.barSize).apply {
selectedSource = settings.topBarSource selectedSource = settings.topBarSource
open() open()
windows.add(this) windows.add(this)

View File

@ -2,6 +2,7 @@ package de.timklge.karoopowerbar
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey
import de.timklge.karoopowerbar.screens.SelectedSource import de.timklge.karoopowerbar.screens.SelectedSource
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -20,10 +21,7 @@ data class PowerbarSettings(
val onlyShowWhileRiding: Boolean = true, val onlyShowWhileRiding: Boolean = true,
val showLabelOnBars: Boolean = true, val showLabelOnBars: Boolean = true,
val useZoneColors: Boolean = true, val useZoneColors: Boolean = true,
val barBackground: Boolean = false,
val barSize: CustomProgressBarSize = CustomProgressBarSize.MEDIUM, val barSize: CustomProgressBarSize = CustomProgressBarSize.MEDIUM,
val barFontSize: CustomProgressBarFontSize = CustomProgressBarFontSize.fromSize(barSize),
val barBarSize: CustomProgressBarBarSize = CustomProgressBarBarSize.fromSize(barSize),
val minCadence: Int = defaultMinCadence, val maxCadence: Int = defaultMaxCadence, val minCadence: Int = defaultMinCadence, val maxCadence: Int = defaultMaxCadence,
val minSpeed: Float = defaultMinSpeedMs, val maxSpeed: Float = defaultMaxSpeedMs, // 50 km/h in m/s val minSpeed: Float = defaultMinSpeedMs, val maxSpeed: Float = defaultMaxSpeedMs, // 50 km/h in m/s

View File

@ -54,9 +54,7 @@ class Window(
private val context: Context, private val context: Context,
val powerbarLocation: PowerbarLocation = PowerbarLocation.BOTTOM, val powerbarLocation: PowerbarLocation = PowerbarLocation.BOTTOM,
val showLabel: Boolean, val showLabel: Boolean,
val barBackground: Boolean, val powerbarSize: CustomProgressBarSize
val powerbarBarSize: CustomProgressBarBarSize,
val powerbarFontSize: CustomProgressBarFontSize,
) { ) {
companion object { companion object {
val FIELD_TARGET_VALUE_ID = "FIELD_WORKOUT_TARGET_VALUE_ID"; val FIELD_TARGET_VALUE_ID = "FIELD_WORKOUT_TARGET_VALUE_ID";
@ -136,9 +134,7 @@ class Window(
powerbar.progress = null powerbar.progress = null
powerbar.location = powerbarLocation powerbar.location = powerbarLocation
powerbar.showLabel = showLabel powerbar.showLabel = showLabel
powerbar.barBackground = barBackground powerbar.size = powerbarSize
powerbar.fontSize = powerbarFontSize
powerbar.barSize = powerbarBarSize
powerbar.invalidate() powerbar.invalidate()
Log.i(TAG, "Streaming $selectedSource") Log.i(TAG, "Streaming $selectedSource")

View File

@ -57,8 +57,6 @@ import androidx.compose.ui.window.Dialog
import androidx.core.content.ContextCompat.startActivity import androidx.core.content.ContextCompat.startActivity
import androidx.datastore.preferences.core.edit 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.CustomProgressBarFontSize
import de.timklge.karoopowerbar.CustomProgressBarSize 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
@ -68,6 +66,8 @@ import de.timklge.karoopowerbar.settingsKey
import de.timklge.karoopowerbar.streamSettings import de.timklge.karoopowerbar.streamSettings
import de.timklge.karoopowerbar.streamUserProfile import de.timklge.karoopowerbar.streamUserProfile
import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.HardwareType
import io.hammerhead.karooext.models.PlayBeepPattern
import io.hammerhead.karooext.models.UserProfile import io.hammerhead.karooext.models.UserProfile
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
@ -147,9 +147,7 @@ fun MainScreen(onFinish: () -> Unit) {
var onlyShowWhileRiding by remember { mutableStateOf(false) } var onlyShowWhileRiding by remember { mutableStateOf(false) }
var colorBasedOnZones by remember { mutableStateOf(false) } var colorBasedOnZones by remember { mutableStateOf(false) }
var showLabelOnBars by remember { mutableStateOf(true) } var showLabelOnBars by remember { mutableStateOf(true) }
var barBarSize by remember { mutableStateOf(CustomProgressBarBarSize.MEDIUM) } var barSize by remember { mutableStateOf(CustomProgressBarSize.MEDIUM) }
var barFontSize by remember { mutableStateOf(CustomProgressBarFontSize.MEDIUM) }
var barBackground by remember { mutableStateOf(false) }
var minCadence by remember { mutableStateOf("0") } var minCadence by remember { mutableStateOf("0") }
var maxCadence by remember { mutableStateOf("0") } var maxCadence by remember { mutableStateOf("0") }
@ -179,7 +177,6 @@ fun MainScreen(onFinish: () -> Unit) {
val newSettings = PowerbarSettings( val newSettings = PowerbarSettings(
source = bottomSelectedSource, topBarSource = topSelectedSource, source = bottomSelectedSource, topBarSource = topSelectedSource,
onlyShowWhileRiding = onlyShowWhileRiding, showLabelOnBars = showLabelOnBars, onlyShowWhileRiding = onlyShowWhileRiding, showLabelOnBars = showLabelOnBars,
barBackground = barBackground,
useZoneColors = colorBasedOnZones, useZoneColors = colorBasedOnZones,
minCadence = minCadence.toIntOrNull() ?: PowerbarSettings.defaultMinCadence, minCadence = minCadence.toIntOrNull() ?: PowerbarSettings.defaultMinCadence,
maxCadence = maxCadence.toIntOrNull() ?: PowerbarSettings.defaultMaxCadence, maxCadence = maxCadence.toIntOrNull() ?: PowerbarSettings.defaultMaxCadence,
@ -188,8 +185,7 @@ fun MainScreen(onFinish: () -> Unit) {
maxPower = customMaxPower.toIntOrNull(), maxPower = customMaxPower.toIntOrNull(),
minHr = customMinHr.toIntOrNull(), minHr = customMinHr.toIntOrNull(),
maxHr = customMaxHr.toIntOrNull(), maxHr = customMaxHr.toIntOrNull(),
barBarSize = barBarSize, barSize = barSize,
barFontSize = barFontSize,
useCustomPowerRange = useCustomPowerRange, useCustomPowerRange = useCustomPowerRange,
useCustomHrRange = useCustomHrRange, useCustomHrRange = useCustomHrRange,
) )
@ -231,9 +227,7 @@ fun MainScreen(onFinish: () -> Unit) {
onlyShowWhileRiding = settings.onlyShowWhileRiding onlyShowWhileRiding = settings.onlyShowWhileRiding
showLabelOnBars = settings.showLabelOnBars showLabelOnBars = settings.showLabelOnBars
colorBasedOnZones = settings.useZoneColors colorBasedOnZones = settings.useZoneColors
barBarSize = settings.barBarSize barSize = settings.barSize
barFontSize = settings.barFontSize
barBackground = settings.barBackground
minCadence = settings.minCadence.toString() minCadence = settings.minCadence.toString()
maxCadence = settings.maxCadence.toString() maxCadence = settings.maxCadence.toString()
isImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL isImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
@ -315,23 +309,12 @@ fun MainScreen(onFinish: () -> Unit) {
} }
apply { apply {
val dropdownOptions = CustomProgressBarBarSize.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) } val dropdownOptions = CustomProgressBarSize.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) }
val dropdownInitialSelection by remember(barBarSize) { val dropdownInitialSelection by remember(barSize) {
mutableStateOf(dropdownOptions.find { option -> option.id == barBarSize.id }!!) mutableStateOf(dropdownOptions.find { option -> option.id == barSize.id }!!)
} }
Dropdown(label = "Bar Size", options = dropdownOptions, selected = dropdownInitialSelection) { selectedOption -> Dropdown(label = "Bar Size", options = dropdownOptions, selected = dropdownInitialSelection) { selectedOption ->
barBarSize = CustomProgressBarBarSize.entries.find { unit -> unit.id == selectedOption.id }!! barSize = CustomProgressBarSize.entries.find { unit -> unit.id == selectedOption.id }!!
coroutineScope.launch { updateSettings() }
}
}
apply {
val dropdownOptions = CustomProgressBarFontSize.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) }
val dropdownInitialSelection by remember(barFontSize) {
mutableStateOf(dropdownOptions.find { option -> option.id == barFontSize.id }!!)
}
Dropdown(label = "Text Size", options = dropdownOptions, selected = dropdownInitialSelection) { selectedOption ->
barFontSize = CustomProgressBarFontSize.entries.find { unit -> unit.id == selectedOption.id }!!
coroutineScope.launch { updateSettings() } coroutineScope.launch { updateSettings() }
} }
} }
@ -488,15 +471,6 @@ fun MainScreen(onFinish: () -> Unit) {
Text("Show value on bars") Text("Show value on bars")
} }
Row(verticalAlignment = Alignment.CenterVertically) {
Switch(checked = barBackground, onCheckedChange = {
barBackground = it
coroutineScope.launch { updateSettings() }
})
Spacer(modifier = Modifier.width(10.dp))
Text("Opaque background")
}
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Switch(checked = onlyShowWhileRiding, onCheckedChange = { Switch(checked = onlyShowWhileRiding, onCheckedChange = {
onlyShowWhileRiding = it onlyShowWhileRiding = it