Add settings for custom cadence, speed ranges (#16)

* Add settings for custom cadence, speed ranges

* Remove unused imports
This commit is contained in:
timklge 2025-01-07 19:32:57 +01:00 committed by GitHub
parent 546f219d6d
commit 4bbf79ecb0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 182 additions and 108 deletions

View File

@ -15,8 +15,8 @@ android {
applicationId = "de.timklge.karoopowerbar" applicationId = "de.timklge.karoopowerbar"
minSdk = 26 minSdk = 26
targetSdk = 33 targetSdk = 33
versionCode = 10 versionCode = 11
versionName = "1.3.1" versionName = "1.3.2"
} }
signingConfigs { signingConfigs {

View File

@ -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.3.1", "latestVersion": "1.3.2",
"latestVersionCode": 10, "latestVersionCode": 11,
"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 size setting, cadence and speed data sources" "releaseNotes": "Add size setting, cadence and speed data sources with custom ranges"
} }

View File

@ -24,6 +24,7 @@ class CustomProgressBar @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null context: Context, attrs: AttributeSet? = null
) : View(context, attrs) { ) : View(context, attrs) {
var progress: Double = 0.5 var progress: Double = 0.5
var showValueIfNull: Boolean = false
var location: PowerbarLocation = PowerbarLocation.BOTTOM var location: PowerbarLocation = PowerbarLocation.BOTTOM
var label: String = "" var label: String = ""
var showLabel: Boolean = true var showLabel: Boolean = true
@ -104,7 +105,7 @@ class CustomProgressBar @JvmOverloads constructor(
canvas.drawRect(0f, 15f, canvas.width.toFloat(), 15f + size.barHeight, backgroundPaint) canvas.drawRect(0f, 15f, canvas.width.toFloat(), 15f + size.barHeight, backgroundPaint)
if (progress > 0.0) { if (progress > 0.0 || showValueIfNull) {
canvas.drawRoundRect(rect, 2f, 2f, blurPaint) canvas.drawRoundRect(rect, 2f, 2f, blurPaint)
canvas.drawRoundRect(rect, 2f, 2f, linePaint) canvas.drawRoundRect(rect, 2f, 2f, linePaint)
@ -140,7 +141,7 @@ class CustomProgressBar @JvmOverloads constructor(
canvas.drawRect(0f, canvas.height.toFloat() - size.barHeight, canvas.width.toFloat(), canvas.height.toFloat(), backgroundPaint) canvas.drawRect(0f, canvas.height.toFloat() - size.barHeight, canvas.width.toFloat(), canvas.height.toFloat(), backgroundPaint)
if (progress > 0.0) { if (progress > 0.0 || showValueIfNull) {
canvas.drawRoundRect(rect, 2f, 2f, blurPaint) canvas.drawRoundRect(rect, 2f, 2f, blurPaint)
canvas.drawRoundRect(rect, 2f, 2f, linePaint) canvas.drawRoundRect(rect, 2f, 2f, linePaint)

View File

@ -1,10 +1,5 @@
package de.timklge.karoopowerbar 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 io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.OnStreamState import io.hammerhead.karooext.models.OnStreamState
import io.hammerhead.karooext.models.RideState import io.hammerhead.karooext.models.RideState
@ -14,49 +9,10 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.trySendBlocking import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
val jsonWithUnknownKeys = Json { ignoreUnknownKeys = true } val jsonWithUnknownKeys = Json { ignoreUnknownKeys = true }
val settingsKey = stringPreferencesKey("settings")
@Serializable
data class PowerbarSettings(
val source: SelectedSource = SelectedSource.POWER,
val topBarSource: SelectedSource = SelectedSource.NONE,
val onlyShowWhileRiding: Boolean = true,
val showLabelOnBars: Boolean = true,
val useZoneColors: Boolean = true,
val barSize: CustomProgressBarSize = CustomProgressBarSize.MEDIUM
){
companion object {
val defaultSettings = Json.encodeToString(PowerbarSettings())
}
}
suspend fun saveSettings(context: Context, settings: PowerbarSettings) {
context.dataStore.edit { t ->
t[settingsKey] = Json.encodeToString(settings)
}
}
fun Context.streamSettings(): Flow<PowerbarSettings> {
return dataStore.data.map { settingsJson ->
try {
jsonWithUnknownKeys.decodeFromString<PowerbarSettings>(
settingsJson[settingsKey] ?: PowerbarSettings.defaultSettings
)
} catch(e: Throwable){
Log.e(KarooPowerbarExtension.TAG, "Failed to read preferences", e)
jsonWithUnknownKeys.decodeFromString<PowerbarSettings>(PowerbarSettings.defaultSettings)
}
}.distinctUntilChanged()
}
fun KarooSystemService.streamDataFlow(dataTypeId: String): Flow<StreamState> { fun KarooSystemService.streamDataFlow(dataTypeId: String): Flow<StreamState> {
return callbackFlow { return callbackFlow {
val listenerId = addConsumer(OnStreamState.StartStreaming(dataTypeId)) { event: OnStreamState -> val listenerId = addConsumer(OnStreamState.StartStreaming(dataTypeId)) { event: OnStreamState ->

View File

@ -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.3.1") { class KarooPowerbarExtension : KarooExtension("karoo-powerbar", "1.3.2") {
companion object { companion object {
const val TAG = "karoo-powerbar" const val TAG = "karoo-powerbar"

View File

@ -1,14 +1,11 @@
package de.timklge.karoopowerbar package de.timklge.karoopowerbar
import android.R
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.provider.Settings
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.material3.Text
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore import androidx.datastore.preferences.preferencesDataStore

View File

@ -0,0 +1,55 @@
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
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
val settingsKey = stringPreferencesKey("settings")
@Serializable
data class PowerbarSettings(
val source: SelectedSource = SelectedSource.POWER,
val topBarSource: SelectedSource = SelectedSource.NONE,
val onlyShowWhileRiding: Boolean = true,
val showLabelOnBars: Boolean = true,
val useZoneColors: Boolean = true,
val barSize: CustomProgressBarSize = CustomProgressBarSize.MEDIUM,
val minCadence: Int = defaultMinCadence, val maxCadence: Int = defaultMaxCadence,
val minSpeed: Float = defaultMinSpeedMs, val maxSpeed: Float = defaultMaxSpeedMs, // 50 km/h in m/s
){
companion object {
val defaultSettings = Json.encodeToString(PowerbarSettings())
val defaultMinSpeedMs = 0f
val defaultMaxSpeedMs = 13.89f
val defaultMinCadence = 50
val defaultMaxCadence = 120
}
}
suspend fun saveSettings(context: Context, settings: PowerbarSettings) {
context.dataStore.edit { t ->
t[settingsKey] = Json.encodeToString(settings)
}
}
fun Context.streamSettings(): Flow<PowerbarSettings> {
return dataStore.data.map { settingsJson ->
try {
jsonWithUnknownKeys.decodeFromString<PowerbarSettings>(
settingsJson[settingsKey] ?: PowerbarSettings.defaultSettings
)
} catch(e: Throwable){
Log.e(KarooPowerbarExtension.TAG, "Failed to read preferences", e)
jsonWithUnknownKeys.decodeFromString<PowerbarSettings>(PowerbarSettings.defaultSettings)
}
}.distinctUntilChanged()
}

View File

@ -16,6 +16,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowInsets import android.view.WindowInsets
import android.view.WindowManager import android.view.WindowManager
import androidx.annotation.ColorRes
import de.timklge.karoopowerbar.KarooPowerbarExtension.Companion.TAG import de.timklge.karoopowerbar.KarooPowerbarExtension.Companion.TAG
import de.timklge.karoopowerbar.screens.SelectedSource import de.timklge.karoopowerbar.screens.SelectedSource
import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
@ -150,28 +151,6 @@ class Window(
} }
} }
companion object {
val speedZones = listOf(
UserProfile.Zone(0, 9),
UserProfile.Zone(10, 19),
UserProfile.Zone(20, 24),
UserProfile.Zone(25, 29),
UserProfile.Zone(30, 34),
UserProfile.Zone(34, 39),
UserProfile.Zone(40, 44),
)
val cadenceZones = listOf(
UserProfile.Zone(0, 59),
UserProfile.Zone(60, 79),
UserProfile.Zone(80, 89),
UserProfile.Zone(90, 99),
UserProfile.Zone(100, 109),
UserProfile.Zone(110, 119),
UserProfile.Zone(120, 129),
)
}
private suspend fun streamSpeed(smoothed: Boolean) { private suspend fun streamSpeed(smoothed: Boolean) {
val speedFlow = karooSystem.streamDataFlow(if(smoothed) DataType.Type.SMOOTHED_3S_AVERAGE_SPEED else DataType.Type.SPEED) val speedFlow = karooSystem.streamDataFlow(if(smoothed) DataType.Type.SMOOTHED_3S_AVERAGE_SPEED else DataType.Type.SPEED)
.map { (it as? StreamState.Streaming)?.dataPoint?.singleValue } .map { (it as? StreamState.Streaming)?.dataPoint?.singleValue }
@ -185,20 +164,23 @@ class Window(
.combine(settingsFlow) { streamData, settings -> streamData.copy(settings = settings) } .combine(settingsFlow) { streamData, settings -> streamData.copy(settings = settings) }
.distinctUntilChanged() .distinctUntilChanged()
.collect { streamData -> .collect { streamData ->
val valueMetersPerSecond = streamData.value?.roundToInt() val valueMetersPerSecond = streamData.value
val value = when (streamData.userProfile.preferredUnit.distance){ val value = when (streamData.userProfile.preferredUnit.distance){
UserProfile.PreferredUnit.UnitType.IMPERIAL -> valueMetersPerSecond?.times(2.23694) UserProfile.PreferredUnit.UnitType.IMPERIAL -> valueMetersPerSecond?.times(2.23694)
else -> valueMetersPerSecond?.times(3.6) else -> valueMetersPerSecond?.times(3.6)
}?.roundToInt() }?.roundToInt()
if (value != null) { if (value != null && valueMetersPerSecond != null) {
val minSpeed = speedZones.first().min val minSpeed = streamData.settings?.minSpeed ?: PowerbarSettings.defaultMinSpeedMs
val maxSpeed = speedZones.last().min + 5 val maxSpeed = streamData.settings?.maxSpeed ?: PowerbarSettings.defaultMaxSpeedMs
val progress = val progress =
remap(value.toDouble(), minSpeed.toDouble(), maxSpeed.toDouble(), 0.0, 1.0) remap(valueMetersPerSecond, minSpeed.toDouble(), maxSpeed.toDouble(), 0.0, 1.0)
powerbar.showValueIfNull = valueMetersPerSecond != 0.0
@ColorRes val zoneColorRes = Zone.entries[(progress * Zone.entries.size).roundToInt().coerceIn(0..<Zone.entries.size)].colorResource
powerbar.progressColor = if (streamData.settings?.useZoneColors == true) { powerbar.progressColor = if (streamData.settings?.useZoneColors == true) {
context.getColor(getZone(speedZones, value)?.colorResource ?: R.color.zone7) context.getColor(zoneColorRes)
} else { } else {
context.getColor(R.color.zone0) context.getColor(R.color.zone0)
} }
@ -209,6 +191,7 @@ class Window(
} else { } else {
powerbar.progressColor = context.getColor(R.color.zone0) powerbar.progressColor = context.getColor(R.color.zone0)
powerbar.progress = 0.0 powerbar.progress = 0.0
powerbar.showValueIfNull = false
powerbar.label = "?" powerbar.label = "?"
Log.d(TAG, "Speed: Unavailable") Log.d(TAG, "Speed: Unavailable")
@ -233,13 +216,16 @@ class Window(
val value = streamData.value?.roundToInt() val value = streamData.value?.roundToInt()
if (value != null) { if (value != null) {
val minCadence = cadenceZones.first().min val minCadence = streamData.settings?.minCadence ?: PowerbarSettings.defaultMinCadence
val maxCadence = cadenceZones.last().min + 5 val maxCadence = streamData.settings?.maxCadence ?: PowerbarSettings.defaultMaxCadence
val progress = val progress =
remap(value.toDouble(), minCadence.toDouble(), maxCadence.toDouble(), 0.0, 1.0) remap(value.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
powerbar.showValueIfNull = value != 0
powerbar.progressColor = if (streamData.settings?.useZoneColors == true) { powerbar.progressColor = if (streamData.settings?.useZoneColors == true) {
context.getColor(getZone(cadenceZones, value)?.colorResource ?: R.color.zone7) context.getColor(zoneColorRes)
} else { } else {
context.getColor(R.color.zone0) context.getColor(R.color.zone0)
} }
@ -250,6 +236,7 @@ class Window(
} else { } else {
powerbar.progressColor = context.getColor(R.color.zone0) powerbar.progressColor = context.getColor(R.color.zone0)
powerbar.progress = 0.0 powerbar.progress = 0.0
powerbar.showValueIfNull = false
powerbar.label = "?" powerbar.label = "?"
Log.d(TAG, "Cadence: Unavailable") Log.d(TAG, "Cadence: Unavailable")

View File

@ -10,7 +10,6 @@ import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember

View File

@ -7,12 +7,14 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.absolutePadding
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.Build
@ -23,6 +25,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
@ -36,6 +39,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat.startActivity import androidx.core.content.ContextCompat.startActivity
import androidx.lifecycle.compose.LifecycleResumeEffect import androidx.lifecycle.compose.LifecycleResumeEffect
@ -43,20 +47,25 @@ import de.timklge.karoopowerbar.CustomProgressBarSize
import de.timklge.karoopowerbar.PowerbarSettings import de.timklge.karoopowerbar.PowerbarSettings
import de.timklge.karoopowerbar.saveSettings import de.timklge.karoopowerbar.saveSettings
import de.timklge.karoopowerbar.streamSettings import de.timklge.karoopowerbar.streamSettings
import de.timklge.karoopowerbar.streamUserProfile
import io.hammerhead.karooext.KarooSystemService import io.hammerhead.karooext.KarooSystemService
import io.hammerhead.karooext.models.UserProfile
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.math.roundToInt
enum class SelectedSource(val id: String, val label: String) { enum class SelectedSource(val id: String, val label: String) {
NONE("none", "None"), NONE("none", "None"),
HEART_RATE("hr", "Heart Rate"), HEART_RATE("hr", "Heart Rate"),
POWER("power", "Power"), POWER("power", "Power"),
POWER_3S("power_3s", "Power (3 second avg)"), POWER_3S("power_3s", "Power (3 sec avg)"),
POWER_10S("power_10s", "Power (10 second avg)"), POWER_10S("power_10s", "Power (10 sec avg)"),
SPEED("speed", "Speed"), SPEED("speed", "Speed"),
SPEED_3S("speed_3s", "Speed (3 second avg"), SPEED_3S("speed_3s", "Speed (3 sec avg"),
CADENCE("cadence", "Cadence"), CADENCE("cadence", "Cadence"),
CADENCE_3S("cadence_3s", "Cadence (3 second avg)"), CADENCE_3S("cadence_3s", "Cadence (3 sec avg)"),
} }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@ -79,16 +88,36 @@ fun MainScreen() {
var showLabelOnBars by remember { mutableStateOf(true) } var showLabelOnBars by remember { mutableStateOf(true) }
var barSize by remember { mutableStateOf(CustomProgressBarSize.MEDIUM) } var barSize by remember { mutableStateOf(CustomProgressBarSize.MEDIUM) }
var minCadence by remember { mutableStateOf("0") }
var maxCadence by remember { mutableStateOf("0") }
var minSpeed by remember { mutableStateOf("0") }
var maxSpeed by remember { mutableStateOf("0") }
var isImperial by remember { mutableStateOf(false) }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
karooSystem.streamUserProfile().distinctUntilChanged().collect {
isImperial = it.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
}
}
LaunchedEffect(isImperial) {
givenPermissions = Settings.canDrawOverlays(ctx) givenPermissions = Settings.canDrawOverlays(ctx)
ctx.streamSettings().collect { settings -> ctx.streamSettings()
.combine(karooSystem.streamUserProfile()) { settings, profile -> settings to profile }
.distinctUntilChanged()
.collect { (settings, profile) ->
bottomSelectedSource = settings.source bottomSelectedSource = settings.source
topSelectedSource = settings.topBarSource topSelectedSource = settings.topBarSource
onlyShowWhileRiding = settings.onlyShowWhileRiding onlyShowWhileRiding = settings.onlyShowWhileRiding
showLabelOnBars = settings.showLabelOnBars showLabelOnBars = settings.showLabelOnBars
colorBasedOnZones = settings.useZoneColors colorBasedOnZones = settings.useZoneColors
barSize = settings.barSize barSize = settings.barSize
minCadence = settings.minCadence.toString()
maxCadence = settings.maxCadence.toString()
isImperial = profile.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
minSpeed = (if(isImperial) settings.minSpeed * 2.23694f else settings.minSpeed * 3.6f).roundToInt().toString()
maxSpeed = (if(isImperial) settings.maxSpeed * 2.23694f else settings.maxSpeed * 3.6f).roundToInt().toString()
} }
} }
@ -149,6 +178,50 @@ fun MainScreen() {
} }
} }
if (topSelectedSource == SelectedSource.SPEED || topSelectedSource == SelectedSource.SPEED_3S ||
bottomSelectedSource == SelectedSource.SPEED || bottomSelectedSource == SelectedSource.SPEED_3S){
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
OutlinedTextField(value = minSpeed, modifier = Modifier.weight(1f).absolutePadding(right = 2.dp),
onValueChange = { minSpeed = it },
label = { Text("Min Speed") },
suffix = { Text(if (isImperial) "mph" else "kph") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
singleLine = true
)
OutlinedTextField(value = maxSpeed, modifier = Modifier.weight(1f).absolutePadding(left = 2.dp),
onValueChange = { maxSpeed = it },
label = { Text("Max Speed") },
suffix = { Text(if (isImperial) "mph" else "kph") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
singleLine = true
)
}
}
if (bottomSelectedSource == SelectedSource.CADENCE || topSelectedSource == SelectedSource.CADENCE ||
bottomSelectedSource == SelectedSource.CADENCE_3S || topSelectedSource == SelectedSource.CADENCE_3S){
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
OutlinedTextField(value = minCadence, modifier = Modifier.weight(1f).absolutePadding(right = 2.dp),
onValueChange = { minCadence = it },
label = { Text("Min Cadence") },
suffix = { Text("rpm") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
singleLine = true
)
OutlinedTextField(value = maxCadence, modifier = Modifier.weight(1f).absolutePadding(left = 2.dp),
onValueChange = { maxCadence = it },
label = { Text("Min Cadence") },
suffix = { Text("rpm") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
singleLine = true
)
}
}
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Switch(checked = colorBasedOnZones, onCheckedChange = { colorBasedOnZones = it}) Switch(checked = colorBasedOnZones, onCheckedChange = { colorBasedOnZones = it})
Spacer(modifier = Modifier.width(10.dp)) Spacer(modifier = Modifier.width(10.dp))
@ -170,10 +243,16 @@ fun MainScreen() {
FilledTonalButton(modifier = Modifier FilledTonalButton(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(50.dp), onClick = { .height(50.dp), onClick = {
val minSpeedSetting = (minSpeed.toIntOrNull()?.toFloat()?.div((if(isImperial) 2.23694f else 3.6f))) ?: PowerbarSettings.defaultMinSpeedMs
val maxSpeedSetting = (maxSpeed.toIntOrNull()?.toFloat()?.div((if(isImperial) 2.23694f else 3.6f))) ?: PowerbarSettings.defaultMaxSpeedMs
val newSettings = PowerbarSettings( val newSettings = PowerbarSettings(
source = bottomSelectedSource, topBarSource = topSelectedSource, source = bottomSelectedSource, topBarSource = topSelectedSource,
onlyShowWhileRiding = onlyShowWhileRiding, showLabelOnBars = showLabelOnBars, onlyShowWhileRiding = onlyShowWhileRiding, showLabelOnBars = showLabelOnBars,
useZoneColors = colorBasedOnZones, useZoneColors = colorBasedOnZones,
minCadence = minCadence.toIntOrNull() ?: PowerbarSettings.defaultMinCadence,
maxCadence = maxCadence.toIntOrNull() ?: PowerbarSettings.defaultMaxCadence,
minSpeed = minSpeedSetting, maxSpeed = maxSpeedSetting,
barSize = barSize barSize = barSize
) )