* fix #17: Adds optional custom range inputs for power, heart rate data sources * Update karoo-ext * Fix display of overlay value if out of range * Fix custom speed range
This commit is contained in:
parent
4bbf79ecb0
commit
c7686e43df
@ -4,7 +4,9 @@
|
||||
[](https://github.com/timklge/karoo-powerbar/releases)
|
||||

|
||||
|
||||
Simple karoo extension that shows an overlay power bar at the edge of the screen. For Karoo 2 and Karoo 3 devices.
|
||||
Simple karoo extension that shows an overlay power bar at the edge of the screen, comparable to the
|
||||
dedicated LEDs featured on Wahoo devices.
|
||||
For Karoo 2 and Karoo 3 devices.
|
||||
|
||||

|
||||

|
||||
|
||||
@ -15,8 +15,8 @@ android {
|
||||
applicationId = "de.timklge.karoopowerbar"
|
||||
minSdk = 26
|
||||
targetSdk = 33
|
||||
versionCode = 11
|
||||
versionName = "1.3.2"
|
||||
versionCode = 12
|
||||
versionName = "1.3.3"
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
|
||||
@ -3,9 +3,9 @@
|
||||
"packageName": "de.timklge.karoopowerbar",
|
||||
"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",
|
||||
"latestVersion": "1.3.2",
|
||||
"latestVersionCode": 11,
|
||||
"latestVersion": "1.3.3",
|
||||
"latestVersionCode": 12,
|
||||
"developer": "timklge",
|
||||
"description": "Adds a colored power bar to the bottom of the screen",
|
||||
"releaseNotes": "Add size setting, cadence and speed data sources with custom ranges"
|
||||
"releaseNotes": "Adds option to set a custom range for power and heart rate bar"
|
||||
}
|
||||
@ -23,8 +23,7 @@ enum class CustomProgressBarSize(val id: String, val label: String, val fontSize
|
||||
class CustomProgressBar @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null
|
||||
) : View(context, attrs) {
|
||||
var progress: Double = 0.5
|
||||
var showValueIfNull: Boolean = false
|
||||
var progress: Double? = 0.5
|
||||
var location: PowerbarLocation = PowerbarLocation.BOTTOM
|
||||
var label: String = ""
|
||||
var showLabel: Boolean = true
|
||||
@ -99,13 +98,13 @@ class CustomProgressBar @JvmOverloads constructor(
|
||||
val rect = RectF(
|
||||
1f,
|
||||
15f,
|
||||
((canvas.width.toDouble() - 1f) * progress.coerceIn(0.0, 1.0)).toFloat(),
|
||||
((canvas.width.toDouble() - 1f) * (progress ?: 0.0).coerceIn(0.0, 1.0)).toFloat(),
|
||||
15f + size.barHeight
|
||||
)
|
||||
|
||||
canvas.drawRect(0f, 15f, canvas.width.toFloat(), 15f + size.barHeight, backgroundPaint)
|
||||
|
||||
if (progress > 0.0 || showValueIfNull) {
|
||||
if (progress != null) {
|
||||
canvas.drawRoundRect(rect, 2f, 2f, blurPaint)
|
||||
canvas.drawRoundRect(rect, 2f, 2f, linePaint)
|
||||
|
||||
@ -135,13 +134,13 @@ class CustomProgressBar @JvmOverloads constructor(
|
||||
val rect = RectF(
|
||||
1f,
|
||||
canvas.height.toFloat() - 1f - size.barHeight,
|
||||
((canvas.width.toDouble() - 1f) * progress.coerceIn(0.0, 1.0)).toFloat(),
|
||||
((canvas.width.toDouble() - 1f) * (progress ?: 0.0).coerceIn(0.0, 1.0)).toFloat(),
|
||||
canvas.height.toFloat()
|
||||
)
|
||||
|
||||
canvas.drawRect(0f, canvas.height.toFloat() - size.barHeight, canvas.width.toFloat(), canvas.height.toFloat(), backgroundPaint)
|
||||
|
||||
if (progress > 0.0 || showValueIfNull) {
|
||||
if (progress != null) {
|
||||
canvas.drawRoundRect(rect, 2f, 2f, blurPaint)
|
||||
canvas.drawRoundRect(rect, 2f, 2f, linePaint)
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class KarooPowerbarExtension : KarooExtension("karoo-powerbar", "1.3.2") {
|
||||
class KarooPowerbarExtension : KarooExtension("karoo-powerbar", "1.3.3") {
|
||||
|
||||
companion object {
|
||||
const val TAG = "karoo-powerbar"
|
||||
|
||||
@ -25,13 +25,16 @@ data class PowerbarSettings(
|
||||
|
||||
val minCadence: Int = defaultMinCadence, val maxCadence: Int = defaultMaxCadence,
|
||||
val minSpeed: Float = defaultMinSpeedMs, val maxSpeed: Float = defaultMaxSpeedMs, // 50 km/h in m/s
|
||||
val minPower: Int? = null, val maxPower: Int? = null,
|
||||
val minHr: Int? = null, val maxHr: Int? = null,
|
||||
val useCustomHrRange: Boolean = false, val useCustomPowerRange: Boolean = false
|
||||
){
|
||||
companion object {
|
||||
val defaultSettings = Json.encodeToString(PowerbarSettings())
|
||||
val defaultMinSpeedMs = 0f
|
||||
val defaultMaxSpeedMs = 13.89f
|
||||
val defaultMinCadence = 50
|
||||
val defaultMaxCadence = 120
|
||||
const val defaultMinSpeedMs = 0f
|
||||
const val defaultMaxSpeedMs = 13.89f
|
||||
const val defaultMinCadence = 50
|
||||
const val defaultMaxCadence = 120
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@ class Window(
|
||||
layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
rootView = layoutInflater.inflate(R.layout.popup_window, null)
|
||||
powerbar = rootView.findViewById(R.id.progressBar)
|
||||
powerbar.progress = 0.0
|
||||
powerbar.progress = null
|
||||
|
||||
windowManager = context.getSystemService(WINDOW_SERVICE) as WindowManager
|
||||
val displayMetrics = DisplayMetrics()
|
||||
@ -119,7 +119,7 @@ class Window(
|
||||
}
|
||||
|
||||
powerbar.progressColor = context.resources.getColor(R.color.zone7)
|
||||
powerbar.progress = 0.0
|
||||
powerbar.progress = null
|
||||
powerbar.location = powerbarLocation
|
||||
powerbar.showLabel = showLabel
|
||||
powerbar.size = powerbarSize
|
||||
@ -175,7 +175,6 @@ class Window(
|
||||
val maxSpeed = streamData.settings?.maxSpeed ?: PowerbarSettings.defaultMaxSpeedMs
|
||||
val progress =
|
||||
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
|
||||
|
||||
@ -184,14 +183,13 @@ class Window(
|
||||
} else {
|
||||
context.getColor(R.color.zone0)
|
||||
}
|
||||
powerbar.progress = progress
|
||||
powerbar.progress = if (value > 0) progress else null
|
||||
powerbar.label = "$value"
|
||||
|
||||
Log.d(TAG, "Speed: $value min: $minSpeed max: $maxSpeed")
|
||||
} else {
|
||||
powerbar.progressColor = context.getColor(R.color.zone0)
|
||||
powerbar.progress = 0.0
|
||||
powerbar.showValueIfNull = false
|
||||
powerbar.progress = null
|
||||
powerbar.label = "?"
|
||||
|
||||
Log.d(TAG, "Speed: Unavailable")
|
||||
@ -223,20 +221,18 @@ class Window(
|
||||
|
||||
@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) {
|
||||
context.getColor(zoneColorRes)
|
||||
} else {
|
||||
context.getColor(R.color.zone0)
|
||||
}
|
||||
powerbar.progress = progress
|
||||
powerbar.progress = if (value > 0) progress else null
|
||||
powerbar.label = "$value"
|
||||
|
||||
Log.d(TAG, "Cadence: $value min: $minCadence max: $maxCadence")
|
||||
} else {
|
||||
powerbar.progressColor = context.getColor(R.color.zone0)
|
||||
powerbar.progress = 0.0
|
||||
powerbar.showValueIfNull = false
|
||||
powerbar.progress = null
|
||||
powerbar.label = "?"
|
||||
|
||||
Log.d(TAG, "Cadence: Unavailable")
|
||||
@ -261,23 +257,24 @@ class Window(
|
||||
val value = streamData.value?.roundToInt()
|
||||
|
||||
if (value != null) {
|
||||
val minHr = streamData.userProfile.restingHr
|
||||
val maxHr = streamData.userProfile.maxHr
|
||||
val progress =
|
||||
remap(value.toDouble(), minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
||||
val customMinHr = if (streamData.settings?.useCustomHrRange == true) streamData.settings.minHr else null
|
||||
val customMaxHr = if (streamData.settings?.useCustomHrRange == true) streamData.settings.maxHr else null
|
||||
val minHr = customMinHr ?: streamData.userProfile.restingHr
|
||||
val maxHr = customMaxHr ?: streamData.userProfile.maxHr
|
||||
val progress = remap(value.toDouble(), minHr.toDouble(), maxHr.toDouble(), 0.0, 1.0)
|
||||
|
||||
powerbar.progressColor = if (streamData.settings?.useZoneColors == true) {
|
||||
context.getColor(getZone(streamData.userProfile.heartRateZones, value)?.colorResource ?: R.color.zone7)
|
||||
} else {
|
||||
context.getColor(R.color.zone0)
|
||||
}
|
||||
powerbar.progress = progress
|
||||
powerbar.progress = if (value > 0) progress else null
|
||||
powerbar.label = "$value"
|
||||
|
||||
Log.d(TAG, "Hr: $value min: $minHr max: $maxHr")
|
||||
} else {
|
||||
powerbar.progressColor = context.getColor(R.color.zone0)
|
||||
powerbar.progress = 0.0
|
||||
powerbar.progress = null
|
||||
powerbar.label = "?"
|
||||
|
||||
Log.d(TAG, "Hr: Unavailable")
|
||||
@ -308,23 +305,24 @@ class Window(
|
||||
val value = streamData.value?.roundToInt()
|
||||
|
||||
if (value != null) {
|
||||
val minPower = streamData.userProfile.powerZones.first().min
|
||||
val maxPower = streamData.userProfile.powerZones.last().min + 50
|
||||
val progress =
|
||||
remap(value.toDouble(), minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
||||
val customMinPower = if (streamData.settings?.useCustomPowerRange == true) streamData.settings.minPower else null
|
||||
val customMaxPower = if (streamData.settings?.useCustomPowerRange == true) streamData.settings.maxPower else null
|
||||
val minPower = customMinPower ?: streamData.userProfile.powerZones.first().min
|
||||
val maxPower = customMaxPower ?: (streamData.userProfile.powerZones.last().min + 50)
|
||||
val progress = remap(value.toDouble(), minPower.toDouble(), maxPower.toDouble(), 0.0, 1.0)
|
||||
|
||||
powerbar.progressColor = if (streamData.settings?.useZoneColors == true) {
|
||||
context.getColor(getZone(streamData.userProfile.powerZones, value)?.colorResource ?: R.color.zone7)
|
||||
} else {
|
||||
context.getColor(R.color.zone0)
|
||||
}
|
||||
powerbar.progress = progress
|
||||
powerbar.progress = if (value > 0) progress else null
|
||||
powerbar.label = "${value}W"
|
||||
|
||||
Log.d(TAG, "Power: $value min: $minPower max: $maxPower")
|
||||
} else {
|
||||
powerbar.progressColor = context.getColor(R.color.zone0)
|
||||
powerbar.progress = 0.0
|
||||
powerbar.progress = null
|
||||
powerbar.label = "?"
|
||||
|
||||
Log.d(TAG, "Power: Unavailable")
|
||||
|
||||
@ -32,6 +32,7 @@ import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
@ -41,6 +42,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||
import de.timklge.karoopowerbar.CustomProgressBarSize
|
||||
@ -65,7 +67,9 @@ enum class SelectedSource(val id: String, val label: String) {
|
||||
SPEED("speed", "Speed"),
|
||||
SPEED_3S("speed_3s", "Speed (3 sec avg"),
|
||||
CADENCE("cadence", "Cadence"),
|
||||
CADENCE_3S("cadence_3s", "Cadence (3 sec avg)"),
|
||||
CADENCE_3S("cadence_3s", "Cadence (3 sec avg)");
|
||||
|
||||
fun isPower() = this == POWER || this == POWER_3S || this == POWER_10S
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@ -93,10 +97,25 @@ fun MainScreen() {
|
||||
var minSpeed by remember { mutableStateOf("0") }
|
||||
var maxSpeed by remember { mutableStateOf("0") }
|
||||
var isImperial by remember { mutableStateOf(false) }
|
||||
var customMinPower by remember { mutableStateOf("") }
|
||||
var customMaxPower by remember { mutableStateOf("") }
|
||||
var customMinHr by remember { mutableStateOf("") }
|
||||
var customMaxHr by remember { mutableStateOf("") }
|
||||
var useCustomPowerRange by remember { mutableStateOf(false) }
|
||||
var useCustomHrRange by remember { mutableStateOf(false) }
|
||||
|
||||
var profileMaxHr by remember { mutableIntStateOf(0) }
|
||||
var profileRestHr by remember { mutableIntStateOf(0) }
|
||||
var profileMinPower by remember { mutableIntStateOf(0) }
|
||||
var profileMaxPower by remember { mutableIntStateOf(0) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
karooSystem.streamUserProfile().distinctUntilChanged().collect {
|
||||
isImperial = it.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
||||
karooSystem.streamUserProfile().distinctUntilChanged().collect { profileData ->
|
||||
isImperial = profileData.preferredUnit.distance == UserProfile.PreferredUnit.UnitType.IMPERIAL
|
||||
profileMaxHr = profileData.maxHr
|
||||
profileRestHr = profileData.restingHr
|
||||
profileMinPower = profileData.powerZones.first().min
|
||||
profileMaxPower = profileData.powerZones.last().min + 50
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,6 +137,12 @@ fun MainScreen() {
|
||||
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()
|
||||
customMinPower = settings.minPower?.toString() ?: ""
|
||||
customMaxPower = settings.maxPower?.toString() ?: ""
|
||||
customMinHr = settings.minHr?.toString() ?: ""
|
||||
customMaxHr = settings.maxHr?.toString() ?: ""
|
||||
useCustomPowerRange = settings.useCustomPowerRange
|
||||
useCustomHrRange = settings.useCustomHrRange
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,7 +207,9 @@ fun MainScreen() {
|
||||
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),
|
||||
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") },
|
||||
@ -190,7 +217,9 @@ fun MainScreen() {
|
||||
singleLine = true
|
||||
)
|
||||
|
||||
OutlinedTextField(value = maxSpeed, modifier = Modifier.weight(1f).absolutePadding(left = 2.dp),
|
||||
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") },
|
||||
@ -200,11 +229,81 @@ fun MainScreen() {
|
||||
}
|
||||
}
|
||||
|
||||
if (topSelectedSource.isPower() || bottomSelectedSource.isPower()){
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Switch(checked = useCustomPowerRange, onCheckedChange = { useCustomPowerRange = it})
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text("Use custom power range")
|
||||
}
|
||||
|
||||
if(useCustomPowerRange){
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
||||
OutlinedTextField(value = customMinPower, modifier = Modifier
|
||||
.weight(1f)
|
||||
.absolutePadding(right = 2.dp),
|
||||
onValueChange = { customMinPower = it },
|
||||
label = { Text("Min Power", fontSize = 12.sp) },
|
||||
suffix = { Text("W") },
|
||||
placeholder = { Text("$profileMinPower") },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
singleLine = true
|
||||
)
|
||||
|
||||
OutlinedTextField(value = customMaxPower, modifier = Modifier
|
||||
.weight(1f)
|
||||
.absolutePadding(left = 2.dp),
|
||||
onValueChange = { customMaxPower = it },
|
||||
label = { Text("Max Power", fontSize = 12.sp) },
|
||||
suffix = { Text("W") },
|
||||
placeholder = { Text("$profileMaxPower") },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
singleLine = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (topSelectedSource == SelectedSource.HEART_RATE || bottomSelectedSource == SelectedSource.HEART_RATE){
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Switch(checked = useCustomHrRange, onCheckedChange = { useCustomHrRange = it})
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text("Use custom HR range")
|
||||
}
|
||||
|
||||
if (useCustomHrRange){
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
||||
OutlinedTextField(value = customMinHr, modifier = Modifier
|
||||
.weight(1f)
|
||||
.absolutePadding(right = 2.dp),
|
||||
onValueChange = { customMinHr = it },
|
||||
label = { Text("Min Hr") },
|
||||
suffix = { Text("bpm") },
|
||||
placeholder = { if(profileRestHr > 0) Text("$profileRestHr") else Unit },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
singleLine = true
|
||||
)
|
||||
|
||||
OutlinedTextField(value = customMaxHr, modifier = Modifier
|
||||
.weight(1f)
|
||||
.absolutePadding(left = 2.dp),
|
||||
onValueChange = { customMaxHr = it },
|
||||
label = { Text("Max Hr") },
|
||||
suffix = { Text("bpm") },
|
||||
placeholder = { if(profileMaxHr > 0) Text("$profileMaxHr") else Unit },
|
||||
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),
|
||||
OutlinedTextField(value = minCadence, modifier = Modifier
|
||||
.weight(1f)
|
||||
.absolutePadding(right = 2.dp),
|
||||
onValueChange = { minCadence = it },
|
||||
label = { Text("Min Cadence") },
|
||||
suffix = { Text("rpm") },
|
||||
@ -212,7 +311,9 @@ fun MainScreen() {
|
||||
singleLine = true
|
||||
)
|
||||
|
||||
OutlinedTextField(value = maxCadence, modifier = Modifier.weight(1f).absolutePadding(left = 2.dp),
|
||||
OutlinedTextField(value = maxCadence, modifier = Modifier
|
||||
.weight(1f)
|
||||
.absolutePadding(left = 2.dp),
|
||||
onValueChange = { maxCadence = it },
|
||||
label = { Text("Min Cadence") },
|
||||
suffix = { Text("rpm") },
|
||||
@ -253,7 +354,13 @@ fun MainScreen() {
|
||||
minCadence = minCadence.toIntOrNull() ?: PowerbarSettings.defaultMinCadence,
|
||||
maxCadence = maxCadence.toIntOrNull() ?: PowerbarSettings.defaultMaxCadence,
|
||||
minSpeed = minSpeedSetting, maxSpeed = maxSpeedSetting,
|
||||
barSize = barSize
|
||||
minPower = customMinPower.toIntOrNull(),
|
||||
maxPower = customMaxPower.toIntOrNull(),
|
||||
minHr = customMinHr.toIntOrNull(),
|
||||
maxHr = customMaxHr.toIntOrNull(),
|
||||
barSize = barSize,
|
||||
useCustomPowerRange = useCustomPowerRange,
|
||||
useCustomHrRange = useCustomHrRange,
|
||||
)
|
||||
|
||||
coroutineScope.launch {
|
||||
|
||||
@ -9,7 +9,6 @@ androidxLifecycle = "2.8.6"
|
||||
androidxActivity = "1.9.3"
|
||||
androidxComposeUi = "1.7.4"
|
||||
androidxComposeMaterial = "1.3.0"
|
||||
glance = "1.1.1"
|
||||
kotlinxSerializationJson = "1.7.3"
|
||||
lifecycleRuntimeKtx = "2.8.7"
|
||||
navigationRuntimeKtx = "2.8.4"
|
||||
@ -25,7 +24,7 @@ compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "
|
||||
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
|
||||
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
|
||||
color = { module = "com.maxkeppeler.sheets-compose-dialogs:color", version.ref = "color" }
|
||||
hammerhead-karoo-ext = { group = "io.hammerhead", name = "karoo-ext", version = "1.1.1" }
|
||||
hammerhead-karoo-ext = { group = "io.hammerhead", name = "karoo-ext", version = "1.1.2" }
|
||||
|
||||
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidxCore" }
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user