Add separate settings for font size, bar size (#38)
* Add separate settings for font size, bar size * Remove labelVerticalPadding
This commit is contained in:
parent
aa764bd0a8
commit
820fdb6ef9
@ -11,14 +11,6 @@ import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.annotation.ColorInt
|
||||
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(
|
||||
context: Context, attrs: AttributeSet? = null
|
||||
@ -30,10 +22,17 @@ class CustomProgressBar @JvmOverloads constructor(
|
||||
var barBackground: Boolean = false
|
||||
@ColorInt var progressColor: Int = 0xFF2b86e6.toInt()
|
||||
|
||||
var size = CustomProgressBarSize.MEDIUM
|
||||
var fontSize = CustomProgressBarFontSize.MEDIUM
|
||||
set(value) {
|
||||
field = value
|
||||
textPaint.textSize = value.fontSize
|
||||
invalidate() // Redraw to apply new font size
|
||||
}
|
||||
|
||||
var barSize = CustomProgressBarBarSize.MEDIUM
|
||||
set(value) {
|
||||
field = value
|
||||
invalidate() // Redraw to apply new bar size
|
||||
}
|
||||
|
||||
private val linePaint = Paint().apply {
|
||||
@ -81,7 +80,7 @@ class CustomProgressBar @JvmOverloads constructor(
|
||||
private val textPaint = Paint().apply {
|
||||
color = Color.WHITE
|
||||
strokeWidth = 3f
|
||||
textSize = size.fontSize
|
||||
textSize = fontSize.fontSize
|
||||
typeface = Typeface.create(Typeface.MONOSPACE, Typeface.BOLD);
|
||||
textAlign = Paint.Align.CENTER
|
||||
}
|
||||
@ -100,78 +99,91 @@ class CustomProgressBar @JvmOverloads constructor(
|
||||
1f,
|
||||
15f,
|
||||
((canvas.width.toDouble() - 1f) * (progress ?: 0.0).coerceIn(0.0, 1.0)).toFloat(),
|
||||
15f + size.barHeight
|
||||
15f + barSize.barHeight // barSize.barHeight will be 0f if NONE
|
||||
)
|
||||
|
||||
if (barBackground){
|
||||
canvas.drawRect(0f, 15f, canvas.width.toFloat(), 15f + size.barHeight, backgroundPaint)
|
||||
// Draw bar components only if barSize is not NONE
|
||||
if (barSize != CustomProgressBarBarSize.NONE) {
|
||||
if (barBackground){
|
||||
canvas.drawRect(0f, 15f, canvas.width.toFloat(), 15f + barSize.barHeight, backgroundPaint)
|
||||
}
|
||||
|
||||
if (progress != null) {
|
||||
canvas.drawRoundRect(rect, 2f, 2f, blurPaint)
|
||||
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)
|
||||
if (progress != null) {
|
||||
canvas.drawRoundRect(rect, 2f, 2f, blurPaint)
|
||||
canvas.drawRoundRect(rect, 2f, 2f, linePaint)
|
||||
|
||||
canvas.drawRoundRect(rect.right-4, rect.top, rect.right+4, rect.bottom, 2f, 2f, blurPaintHighlight)
|
||||
|
||||
if (showLabel){
|
||||
val textBounds = textPaint.measureText(label)
|
||||
val xOffset = (textBounds + 20).coerceAtLeast(10f) / 2f
|
||||
val yOffset = when(size){
|
||||
CustomProgressBarSize.SMALL -> (size.fontSize - size.barHeight) / 2 + 2f
|
||||
CustomProgressBarSize.MEDIUM, CustomProgressBarSize.LARGE -> (size.fontSize - size.barHeight) / 2
|
||||
}
|
||||
val x = (rect.right - xOffset).coerceIn(0f..canvas.width-xOffset*2f)
|
||||
val y = rect.top - yOffset
|
||||
val r = x + xOffset * 2
|
||||
val b = rect.bottom + yOffset
|
||||
|
||||
canvas.drawRoundRect(x, y, r, b, 2f, 2f, textBackgroundPaint)
|
||||
canvas.drawRoundRect(x, y, r, b, 2f, 2f, blurPaint)
|
||||
canvas.drawRoundRect(x, y, r, b, 2f, 2f, lineStrokePaint)
|
||||
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.drawText(label, x + xOffset, rect.top + size.barHeight + 6, textPaint)
|
||||
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 -> {
|
||||
val rect = RectF(
|
||||
1f,
|
||||
canvas.height.toFloat() - 1f - size.barHeight,
|
||||
canvas.height.toFloat() - 1f - barSize.barHeight, // barSize.barHeight will be 0f if NONE
|
||||
((canvas.width.toDouble() - 1f) * (progress ?: 0.0).coerceIn(0.0, 1.0)).toFloat(),
|
||||
canvas.height.toFloat()
|
||||
)
|
||||
|
||||
if (barBackground){
|
||||
canvas.drawRect(0f, canvas.height.toFloat() - size.barHeight, canvas.width.toFloat(), canvas.height.toFloat(), backgroundPaint)
|
||||
// Draw bar components only if barSize is not NONE
|
||||
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)
|
||||
}
|
||||
|
||||
if (progress != null) {
|
||||
canvas.drawRoundRect(rect, 2f, 2f, blurPaint)
|
||||
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)
|
||||
if (progress != null) {
|
||||
canvas.drawRoundRect(rect, 2f, 2f, blurPaint)
|
||||
canvas.drawRoundRect(rect, 2f, 2f, linePaint)
|
||||
|
||||
canvas.drawRoundRect(rect.right-4, rect.top, rect.right+4, rect.bottom, 2f, 2f, blurPaintHighlight)
|
||||
|
||||
if (showLabel){
|
||||
val textBounds = textPaint.measureText(label)
|
||||
val xOffset = (textBounds + 20).coerceAtLeast(10f) / 2f
|
||||
val yOffset = when(size){
|
||||
CustomProgressBarSize.SMALL -> size.fontSize / 2 + 2f
|
||||
CustomProgressBarSize.MEDIUM -> size.fontSize / 2
|
||||
CustomProgressBarSize.LARGE -> size.fontSize / 2 - 5f
|
||||
}
|
||||
val x = (rect.right - xOffset).coerceIn(0f..canvas.width-xOffset*2f)
|
||||
val y = (rect.top - yOffset)
|
||||
val r = x + xOffset * 2
|
||||
val b = rect.bottom + 5
|
||||
|
||||
canvas.drawRoundRect(x, y, r, b, 2f, 2f, textBackgroundPaint)
|
||||
canvas.drawRoundRect(x, y, r, b, 2f, 2f, blurPaint)
|
||||
canvas.drawRoundRect(x, y, r, b, 2f, 2f, lineStrokePaint)
|
||||
// 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.drawText(label, x + xOffset, rect.top + size.barHeight - 1, textPaint)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -53,7 +53,7 @@ class ForegroundService : Service() {
|
||||
windows.clear()
|
||||
|
||||
if (settings.source != SelectedSource.NONE && showBars) {
|
||||
Window(this@ForegroundService, PowerbarLocation.BOTTOM, settings.showLabelOnBars, settings.barBackground, settings.barSize).apply {
|
||||
Window(this@ForegroundService, PowerbarLocation.BOTTOM, settings.showLabelOnBars, settings.barBackground, settings.barBarSize, settings.barFontSize).apply {
|
||||
selectedSource = settings.source
|
||||
windows.add(this)
|
||||
open()
|
||||
@ -61,7 +61,7 @@ class ForegroundService : Service() {
|
||||
}
|
||||
|
||||
if (settings.topBarSource != SelectedSource.NONE && showBars){
|
||||
Window(this@ForegroundService, PowerbarLocation.TOP, settings.showLabelOnBars, settings.barBackground, settings.barSize).apply {
|
||||
Window(this@ForegroundService, PowerbarLocation.TOP, settings.showLabelOnBars, settings.barBackground, settings.barBarSize, settings.barFontSize).apply {
|
||||
selectedSource = settings.topBarSource
|
||||
open()
|
||||
windows.add(this)
|
||||
|
||||
@ -2,7 +2,6 @@ package de.timklge.karoopowerbar
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import de.timklge.karoopowerbar.screens.SelectedSource
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@ -23,6 +22,8 @@ data class PowerbarSettings(
|
||||
val useZoneColors: Boolean = true,
|
||||
val barBackground: Boolean = false,
|
||||
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 minSpeed: Float = defaultMinSpeedMs, val maxSpeed: Float = defaultMaxSpeedMs, // 50 km/h in m/s
|
||||
|
||||
@ -47,7 +47,8 @@ class Window(
|
||||
val powerbarLocation: PowerbarLocation = PowerbarLocation.BOTTOM,
|
||||
val showLabel: Boolean,
|
||||
val barBackground: Boolean,
|
||||
val powerbarSize: CustomProgressBarSize
|
||||
val powerbarBarSize: CustomProgressBarBarSize,
|
||||
val powerbarFontSize: CustomProgressBarFontSize,
|
||||
) {
|
||||
private val rootView: View
|
||||
private var layoutParams: WindowManager.LayoutParams? = null
|
||||
@ -124,7 +125,8 @@ class Window(
|
||||
powerbar.location = powerbarLocation
|
||||
powerbar.showLabel = showLabel
|
||||
powerbar.barBackground = barBackground
|
||||
powerbar.size = powerbarSize
|
||||
powerbar.fontSize = powerbarFontSize
|
||||
powerbar.barSize = powerbarBarSize
|
||||
powerbar.invalidate()
|
||||
|
||||
Log.i(TAG, "Streaming $selectedSource")
|
||||
|
||||
@ -57,6 +57,8 @@ import androidx.compose.ui.window.Dialog
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||
import de.timklge.karoopowerbar.CustomProgressBarBarSize
|
||||
import de.timklge.karoopowerbar.CustomProgressBarFontSize
|
||||
import de.timklge.karoopowerbar.CustomProgressBarSize
|
||||
import de.timklge.karoopowerbar.KarooPowerbarExtension
|
||||
import de.timklge.karoopowerbar.PowerbarSettings
|
||||
@ -144,7 +146,8 @@ fun MainScreen(onFinish: () -> Unit) {
|
||||
var onlyShowWhileRiding by remember { mutableStateOf(false) }
|
||||
var colorBasedOnZones by remember { mutableStateOf(false) }
|
||||
var showLabelOnBars by remember { mutableStateOf(true) }
|
||||
var barSize by remember { mutableStateOf(CustomProgressBarSize.MEDIUM) }
|
||||
var barBarSize by remember { mutableStateOf(CustomProgressBarBarSize.MEDIUM) }
|
||||
var barFontSize by remember { mutableStateOf(CustomProgressBarFontSize.MEDIUM) }
|
||||
var barBackground by remember { mutableStateOf(false) }
|
||||
|
||||
var minCadence by remember { mutableStateOf("0") }
|
||||
@ -184,7 +187,8 @@ fun MainScreen(onFinish: () -> Unit) {
|
||||
maxPower = customMaxPower.toIntOrNull(),
|
||||
minHr = customMinHr.toIntOrNull(),
|
||||
maxHr = customMaxHr.toIntOrNull(),
|
||||
barSize = barSize,
|
||||
barBarSize = barBarSize,
|
||||
barFontSize = barFontSize,
|
||||
useCustomPowerRange = useCustomPowerRange,
|
||||
useCustomHrRange = useCustomHrRange,
|
||||
)
|
||||
@ -226,7 +230,8 @@ fun MainScreen(onFinish: () -> Unit) {
|
||||
onlyShowWhileRiding = settings.onlyShowWhileRiding
|
||||
showLabelOnBars = settings.showLabelOnBars
|
||||
colorBasedOnZones = settings.useZoneColors
|
||||
barSize = settings.barSize
|
||||
barBarSize = settings.barBarSize
|
||||
barFontSize = settings.barFontSize
|
||||
barBackground = settings.barBackground
|
||||
minCadence = settings.minCadence.toString()
|
||||
maxCadence = settings.maxCadence.toString()
|
||||
@ -309,12 +314,23 @@ fun MainScreen(onFinish: () -> Unit) {
|
||||
}
|
||||
|
||||
apply {
|
||||
val dropdownOptions = CustomProgressBarSize.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) }
|
||||
val dropdownInitialSelection by remember(barSize) {
|
||||
mutableStateOf(dropdownOptions.find { option -> option.id == barSize.id }!!)
|
||||
val dropdownOptions = CustomProgressBarBarSize.entries.toList().map { unit -> DropdownOption(unit.id, unit.label) }
|
||||
val dropdownInitialSelection by remember(barBarSize) {
|
||||
mutableStateOf(dropdownOptions.find { option -> option.id == barBarSize.id }!!)
|
||||
}
|
||||
Dropdown(label = "Bar Size", options = dropdownOptions, selected = dropdownInitialSelection) { selectedOption ->
|
||||
barSize = CustomProgressBarSize.entries.find { unit -> unit.id == selectedOption.id }!!
|
||||
barBarSize = CustomProgressBarBarSize.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() }
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user