Display value on top of bar
@ -22,7 +22,7 @@ to be displayed at the bottom or at the top of the screen:
|
|||||||
- Average power over the last 10 seconds
|
- Average power over the last 10 seconds
|
||||||
|
|
||||||
Subsequently, the bar(s) will be shown when riding. Bars are filled and colored according
|
Subsequently, the bar(s) will be shown when riding. Bars are filled and colored according
|
||||||
to your current power output / heart rate zone as setup in your Karoo settings.
|
to your current power output / heart rate zone as setup in your Karoo settings. Optionally, the actual data value can be displayed on top of the bar.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
@ -13,8 +13,8 @@ android {
|
|||||||
applicationId = "de.timklge.karoopowerbar"
|
applicationId = "de.timklge.karoopowerbar"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 33
|
targetSdk = 33
|
||||||
versionCode = 4
|
versionCode = 5
|
||||||
versionName = "1.1.1"
|
versionName = "1.2.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
"packageName": "de.timklge.karoopowerbar",
|
"packageName": "de.timklge.karoopowerbar",
|
||||||
"iconUrl": "https://github.com/timklge/karoo-powerbar/releases/latest/download/karoo-powerbar.png",
|
"iconUrl": "https://github.com/timklge/karoo-powerbar/releases/latest/download/karoo-powerbar.png",
|
||||||
"latestApkUrl": "https://github.com/timklge/karoo-powerbar/releases/latest/download/app-release.apk",
|
"latestApkUrl": "https://github.com/timklge/karoo-powerbar/releases/latest/download/app-release.apk",
|
||||||
"latestVersion": "1.1.1",
|
"latestVersion": "1.2.0",
|
||||||
"latestVersionCode": 4,
|
"latestVersionCode": 5,
|
||||||
"developer": "timklge",
|
"developer": "timklge",
|
||||||
"description": "Adds a colored power bar to the bottom of the screen",
|
"description": "Adds a colored power bar to the bottom of the screen",
|
||||||
"releaseNotes": "Add options to add secondary power bar and to hide bar when not riding. Fix manually set up power/hr zones."
|
"releaseNotes": "Add options to add secondary power bar and to hide bar when not riding. Fix manually set up power/hr zones."
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import android.graphics.Canvas
|
|||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import android.graphics.RectF
|
import android.graphics.RectF
|
||||||
|
import android.graphics.Typeface
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
@ -16,71 +17,135 @@ class CustomProgressBar @JvmOverloads constructor(
|
|||||||
) : View(context, attrs) {
|
) : View(context, attrs) {
|
||||||
var progress: Double = 0.5
|
var progress: Double = 0.5
|
||||||
var location: PowerbarLocation = PowerbarLocation.BOTTOM
|
var location: PowerbarLocation = PowerbarLocation.BOTTOM
|
||||||
|
var label: String = ""
|
||||||
|
var showLabel: Boolean = true
|
||||||
@ColorInt var progressColor: Int = 0xFF2b86e6.toInt()
|
@ColorInt var progressColor: Int = 0xFF2b86e6.toInt()
|
||||||
|
|
||||||
|
val fontSize = 40f
|
||||||
|
|
||||||
|
private val linePaint = Paint().apply {
|
||||||
|
isAntiAlias = true
|
||||||
|
strokeWidth = 1f
|
||||||
|
style = Paint.Style.FILL_AND_STROKE
|
||||||
|
color = progressColor
|
||||||
|
}
|
||||||
|
|
||||||
|
private val lineStrokePaint = Paint().apply {
|
||||||
|
isAntiAlias = true
|
||||||
|
strokeWidth = 4f
|
||||||
|
style = Paint.Style.STROKE
|
||||||
|
color = progressColor
|
||||||
|
}
|
||||||
|
|
||||||
|
private val blurPaint = Paint().apply {
|
||||||
|
isAntiAlias = true
|
||||||
|
strokeWidth = 4f
|
||||||
|
style = Paint.Style.STROKE
|
||||||
|
color = progressColor
|
||||||
|
maskFilter = BlurMaskFilter(3f, BlurMaskFilter.Blur.NORMAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val blurPaintHighlight = Paint().apply {
|
||||||
|
isAntiAlias = true
|
||||||
|
strokeWidth = 8f
|
||||||
|
style = Paint.Style.FILL_AND_STROKE
|
||||||
|
color = ColorUtils.blendARGB(progressColor, 0xFFFFFF, 0.5f)
|
||||||
|
maskFilter = BlurMaskFilter(6f, BlurMaskFilter.Blur.NORMAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val backgroundPaint = Paint().apply {
|
||||||
|
style = Paint.Style.FILL
|
||||||
|
color = Color.argb(1.0f, 0f, 0f, 0f)
|
||||||
|
strokeWidth = 2f
|
||||||
|
}
|
||||||
|
|
||||||
|
private val textBackgroundPaint = Paint().apply {
|
||||||
|
style = Paint.Style.FILL
|
||||||
|
color = Color.argb(0.8f, 0f, 0f, 0f)
|
||||||
|
strokeWidth = 2f
|
||||||
|
}
|
||||||
|
|
||||||
|
private val textPaint = Paint().apply {
|
||||||
|
color = Color.WHITE
|
||||||
|
strokeWidth = 3f
|
||||||
|
textSize = fontSize
|
||||||
|
typeface = Typeface.create(Typeface.MONOSPACE, Typeface.BOLD);
|
||||||
|
textAlign = Paint.Align.CENTER
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDrawForeground(canvas: Canvas) {
|
override fun onDrawForeground(canvas: Canvas) {
|
||||||
super.onDrawForeground(canvas)
|
super.onDrawForeground(canvas)
|
||||||
|
|
||||||
val linePaint = Paint().apply {
|
linePaint.color = progressColor
|
||||||
isAntiAlias = true
|
lineStrokePaint.color = progressColor
|
||||||
strokeWidth = 1f
|
blurPaint.color = progressColor
|
||||||
style = Paint.Style.FILL_AND_STROKE
|
blurPaintHighlight.color = ColorUtils.blendARGB(progressColor, 0xFFFFFF, 0.5f)
|
||||||
color = progressColor
|
|
||||||
}
|
|
||||||
|
|
||||||
val blurPaint = Paint().apply {
|
|
||||||
isAntiAlias = true
|
|
||||||
strokeWidth = 2f
|
|
||||||
style = Paint.Style.STROKE
|
|
||||||
color = progressColor
|
|
||||||
maskFilter = BlurMaskFilter(3f, BlurMaskFilter.Blur.NORMAL)
|
|
||||||
}
|
|
||||||
|
|
||||||
val blurPaintHighlight = Paint().apply {
|
|
||||||
isAntiAlias = true
|
|
||||||
strokeWidth = 4f
|
|
||||||
style = Paint.Style.FILL_AND_STROKE
|
|
||||||
color = ColorUtils.blendARGB(progressColor, 0xFFFFFF, 0.5f)
|
|
||||||
maskFilter = BlurMaskFilter(3f, BlurMaskFilter.Blur.NORMAL)
|
|
||||||
}
|
|
||||||
|
|
||||||
val background = Paint().apply {
|
|
||||||
style = Paint.Style.FILL_AND_STROKE
|
|
||||||
color = Color.argb(1.0f, 0f, 0f, 0f)
|
|
||||||
strokeWidth = 2f
|
|
||||||
}
|
|
||||||
|
|
||||||
when(location){
|
when(location){
|
||||||
PowerbarLocation.TOP -> {
|
PowerbarLocation.TOP -> {
|
||||||
val rect = RectF(
|
val rect = RectF(
|
||||||
1f,
|
1f,
|
||||||
1f,
|
15f,
|
||||||
((canvas.width.toDouble() - 1f) * progress.coerceIn(0.0, 1.0)).toFloat(),
|
((canvas.width.toDouble() - 1f) * progress.coerceIn(0.0, 1.0)).toFloat(),
|
||||||
canvas.height.toFloat() - 1f - 4f
|
15f + 20f
|
||||||
)
|
)
|
||||||
|
|
||||||
canvas.drawRoundRect(0f, 2f, canvas.width.toFloat(), canvas.height.toFloat() - 4f, 2f, 2f, background)
|
canvas.drawRoundRect(0f, 15f, canvas.width.toFloat(), 15f + 20f, 2f, 2f, backgroundPaint)
|
||||||
|
|
||||||
if (progress > 0.0) {
|
if (progress > 0.0) {
|
||||||
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, 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 = (fontSize - 15f) / 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)
|
||||||
|
|
||||||
|
canvas.drawText(label, x + xOffset, rect.top + 23, textPaint)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PowerbarLocation.BOTTOM -> {
|
PowerbarLocation.BOTTOM -> {
|
||||||
val rect = RectF(
|
val rect = RectF(
|
||||||
1f,
|
1f,
|
||||||
1f + 4f,
|
canvas.height.toFloat() - 1f - 20f,
|
||||||
((canvas.width.toDouble() - 1f) * progress.coerceIn(0.0, 1.0)).toFloat(),
|
((canvas.width.toDouble() - 1f) * progress.coerceIn(0.0, 1.0)).toFloat(),
|
||||||
canvas.height.toFloat() - 1f
|
canvas.height.toFloat() - 1f
|
||||||
)
|
)
|
||||||
|
|
||||||
canvas.drawRoundRect(0f, 2f + 4f, canvas.width.toFloat(), canvas.height.toFloat(), 2f, 2f, background)
|
canvas.drawRoundRect(0f, canvas.height.toFloat() - 20f, canvas.width.toFloat(), canvas.height.toFloat(), 2f, 2f, backgroundPaint)
|
||||||
|
|
||||||
if (progress > 0.0) {
|
if (progress > 0.0) {
|
||||||
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, 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 = (fontSize + 0f) / 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 + 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)
|
||||||
|
|
||||||
|
canvas.drawText(label, x + xOffset, rect.top + 16, textPaint)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,8 @@ val settingsKey = stringPreferencesKey("settings")
|
|||||||
data class PowerbarSettings(
|
data class PowerbarSettings(
|
||||||
val source: SelectedSource = SelectedSource.POWER,
|
val source: SelectedSource = SelectedSource.POWER,
|
||||||
val topBarSource: SelectedSource = SelectedSource.NONE,
|
val topBarSource: SelectedSource = SelectedSource.NONE,
|
||||||
val onlyShowWhileRiding: Boolean = true
|
val onlyShowWhileRiding: Boolean = true,
|
||||||
|
val showLabelOnBars: Boolean = true
|
||||||
){
|
){
|
||||||
companion object {
|
companion object {
|
||||||
val defaultSettings = Json.encodeToString(PowerbarSettings())
|
val defaultSettings = Json.encodeToString(PowerbarSettings())
|
||||||
|
|||||||
@ -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).apply {
|
Window(this@ForegroundService, PowerbarLocation.BOTTOM, settings.showLabelOnBars).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).apply {
|
Window(this@ForegroundService, PowerbarLocation.TOP, settings.showLabelOnBars).apply {
|
||||||
selectedSource = settings.topBarSource
|
selectedSource = settings.topBarSource
|
||||||
open()
|
open()
|
||||||
windows.add(this)
|
windows.add(this)
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class KarooPowerbarExtension : KarooExtension("karoo-powerbar", "1.1.1") {
|
class KarooPowerbarExtension : KarooExtension("karoo-powerbar", "1.2.0") {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "karoo-powerbar"
|
const val TAG = "karoo-powerbar"
|
||||||
|
|||||||
@ -39,7 +39,8 @@ enum class PowerbarLocation {
|
|||||||
|
|
||||||
class Window(
|
class Window(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
val powerbarLocation: PowerbarLocation = PowerbarLocation.BOTTOM
|
val powerbarLocation: PowerbarLocation = PowerbarLocation.BOTTOM,
|
||||||
|
val showLabel: Boolean
|
||||||
) {
|
) {
|
||||||
private val rootView: View
|
private val rootView: View
|
||||||
private var layoutParams: WindowManager.LayoutParams? = null
|
private var layoutParams: WindowManager.LayoutParams? = null
|
||||||
@ -83,7 +84,7 @@ class Window(
|
|||||||
PowerbarLocation.BOTTOM -> Gravity.BOTTOM
|
PowerbarLocation.BOTTOM -> Gravity.BOTTOM
|
||||||
}
|
}
|
||||||
if (powerbarLocation == PowerbarLocation.TOP) {
|
if (powerbarLocation == PowerbarLocation.TOP) {
|
||||||
layoutParams?.y = 10
|
layoutParams?.y = 0
|
||||||
} else {
|
} else {
|
||||||
layoutParams?.y = 0
|
layoutParams?.y = 0
|
||||||
}
|
}
|
||||||
@ -105,6 +106,8 @@ class Window(
|
|||||||
|
|
||||||
powerbar.progressColor = context.resources.getColor(R.color.zone7)
|
powerbar.progressColor = context.resources.getColor(R.color.zone7)
|
||||||
powerbar.progress = 0.0
|
powerbar.progress = 0.0
|
||||||
|
powerbar.location = powerbarLocation
|
||||||
|
powerbar.showLabel = showLabel
|
||||||
powerbar.invalidate()
|
powerbar.invalidate()
|
||||||
|
|
||||||
Log.i(TAG, "Streaming $selectedSource")
|
Log.i(TAG, "Streaming $selectedSource")
|
||||||
@ -142,7 +145,7 @@ class Window(
|
|||||||
.collect { streamData ->
|
.collect { streamData ->
|
||||||
val value = streamData.value.roundToInt()
|
val value = streamData.value.roundToInt()
|
||||||
val color = context.getColor(
|
val color = context.getColor(
|
||||||
streamData.userProfile.getZone(streamData.userProfile.heartRateZones, value)?.colorResource
|
getZone(streamData.userProfile.heartRateZones, value)?.colorResource
|
||||||
?: R.color.zone7
|
?: R.color.zone7
|
||||||
)
|
)
|
||||||
val minHr = streamData.userProfile.restingHr
|
val minHr = streamData.userProfile.restingHr
|
||||||
@ -152,6 +155,7 @@ class Window(
|
|||||||
|
|
||||||
powerbar.progressColor = color
|
powerbar.progressColor = color
|
||||||
powerbar.progress = progress
|
powerbar.progress = progress
|
||||||
|
powerbar.label = "$value"
|
||||||
powerbar.invalidate()
|
powerbar.invalidate()
|
||||||
|
|
||||||
Log.d(TAG, "Hr: $value min: $minHr max: $maxHr")
|
Log.d(TAG, "Hr: $value min: $minHr max: $maxHr")
|
||||||
@ -177,7 +181,7 @@ class Window(
|
|||||||
.collect { streamData ->
|
.collect { streamData ->
|
||||||
val value = streamData.value.roundToInt()
|
val value = streamData.value.roundToInt()
|
||||||
val color = context.getColor(
|
val color = context.getColor(
|
||||||
streamData.userProfile.getZone(streamData.userProfile.powerZones, value)?.colorResource
|
getZone(streamData.userProfile.powerZones, value)?.colorResource
|
||||||
?: R.color.zone7
|
?: R.color.zone7
|
||||||
)
|
)
|
||||||
val minPower = streamData.userProfile.powerZones.first().min
|
val minPower = streamData.userProfile.powerZones.first().min
|
||||||
@ -187,9 +191,10 @@ class Window(
|
|||||||
|
|
||||||
powerbar.progressColor = color
|
powerbar.progressColor = color
|
||||||
powerbar.progress = progress
|
powerbar.progress = progress
|
||||||
|
powerbar.label = "${value}W"
|
||||||
powerbar.invalidate()
|
powerbar.invalidate()
|
||||||
|
|
||||||
Log.d(TAG, "Power: ${value} min: $minPower max: $maxPower")
|
Log.d(TAG, "Power: $value min: $minPower max: $maxPower")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ val zones = mapOf(
|
|||||||
9 to listOf(Zone.Zone0, Zone.Zone1, Zone.Zone2, Zone.Zone3, Zone.Zone4, Zone.Zone5, Zone.Zone6, Zone.Zone7, Zone.Zone8)
|
9 to listOf(Zone.Zone0, Zone.Zone1, Zone.Zone2, Zone.Zone3, Zone.Zone4, Zone.Zone5, Zone.Zone6, Zone.Zone7, Zone.Zone8)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun UserProfile.getZone(userZones: List<UserProfile.Zone>, value: Int): Zone? {
|
fun getZone(userZones: List<UserProfile.Zone>, value: Int): Zone? {
|
||||||
val zoneList = zones[userZones.size] ?: return null
|
val zoneList = zones[userZones.size] ?: return null
|
||||||
|
|
||||||
userZones.forEachIndexed { index, zone ->
|
userZones.forEachIndexed { index, zone ->
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
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
|
||||||
@ -41,8 +42,10 @@ import androidx.core.content.ContextCompat.startActivity
|
|||||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||||
import de.timklge.karoopowerbar.PowerbarSettings
|
import de.timklge.karoopowerbar.PowerbarSettings
|
||||||
import de.timklge.karoopowerbar.saveSettings
|
import de.timklge.karoopowerbar.saveSettings
|
||||||
|
import de.timklge.karoopowerbar.streamRideState
|
||||||
import de.timklge.karoopowerbar.streamSettings
|
import de.timklge.karoopowerbar.streamSettings
|
||||||
import io.hammerhead.karooext.KarooSystemService
|
import io.hammerhead.karooext.KarooSystemService
|
||||||
|
import io.hammerhead.karooext.models.RideState
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@ -62,6 +65,8 @@ fun MainScreen() {
|
|||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val karooSystem = remember { KarooSystemService(ctx) }
|
val karooSystem = remember { KarooSystemService(ctx) }
|
||||||
|
|
||||||
|
val rideState: RideState by karooSystem.streamRideState().collectAsState(RideState.Idle)
|
||||||
|
|
||||||
var bottomSelectedSource by remember { mutableStateOf(SelectedSource.POWER) }
|
var bottomSelectedSource by remember { mutableStateOf(SelectedSource.POWER) }
|
||||||
var topSelectedSource by remember { mutableStateOf(SelectedSource.NONE) }
|
var topSelectedSource by remember { mutableStateOf(SelectedSource.NONE) }
|
||||||
|
|
||||||
@ -70,6 +75,7 @@ fun MainScreen() {
|
|||||||
var givenPermissions by remember { mutableStateOf(false) }
|
var givenPermissions by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
var onlyShowWhileRiding by remember { mutableStateOf(false) }
|
var onlyShowWhileRiding by remember { mutableStateOf(false) }
|
||||||
|
var showLabelOnBars by remember { mutableStateOf(true) }
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
givenPermissions = Settings.canDrawOverlays(ctx)
|
givenPermissions = Settings.canDrawOverlays(ctx)
|
||||||
@ -78,6 +84,7 @@ fun MainScreen() {
|
|||||||
bottomSelectedSource = settings.source
|
bottomSelectedSource = settings.source
|
||||||
topSelectedSource = settings.topBarSource
|
topSelectedSource = settings.topBarSource
|
||||||
onlyShowWhileRiding = settings.onlyShowWhileRiding
|
onlyShowWhileRiding = settings.onlyShowWhileRiding
|
||||||
|
showLabelOnBars = settings.showLabelOnBars
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,6 +135,12 @@ fun MainScreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Switch(checked = showLabelOnBars, onCheckedChange = { showLabelOnBars = it})
|
||||||
|
Spacer(modifier = Modifier.width(10.dp))
|
||||||
|
Text("Show value on bars")
|
||||||
|
}
|
||||||
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Switch(checked = onlyShowWhileRiding, onCheckedChange = { onlyShowWhileRiding = it})
|
Switch(checked = onlyShowWhileRiding, onCheckedChange = { onlyShowWhileRiding = it})
|
||||||
Spacer(modifier = Modifier.width(10.dp))
|
Spacer(modifier = Modifier.width(10.dp))
|
||||||
@ -137,7 +150,10 @@ fun MainScreen() {
|
|||||||
FilledTonalButton(modifier = Modifier
|
FilledTonalButton(modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(50.dp), onClick = {
|
.height(50.dp), onClick = {
|
||||||
val newSettings = PowerbarSettings(source = bottomSelectedSource, topBarSource = topSelectedSource, onlyShowWhileRiding = onlyShowWhileRiding)
|
val newSettings = PowerbarSettings(
|
||||||
|
source = bottomSelectedSource, topBarSource = topSelectedSource,
|
||||||
|
onlyShowWhileRiding = onlyShowWhileRiding, showLabelOnBars = showLabelOnBars
|
||||||
|
)
|
||||||
|
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
saveSettings(ctx, newSettings)
|
saveSettings(ctx, newSettings)
|
||||||
@ -149,6 +165,16 @@ fun MainScreen() {
|
|||||||
Text("Save")
|
Text("Save")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (onlyShowWhileRiding && karooConnected) {
|
||||||
|
val hardwareName = karooSystem.hardwareType?.name ?: "unknown device"
|
||||||
|
val state = when (rideState) {
|
||||||
|
RideState.Idle -> "No ride started"
|
||||||
|
is RideState.Paused -> "Ride is paused"
|
||||||
|
RideState.Recording -> "Currently riding"
|
||||||
|
}
|
||||||
|
Text(modifier = Modifier.padding(5.dp), text = "Running on $hardwareName. $state.")
|
||||||
|
}
|
||||||
|
|
||||||
if (showAlerts){
|
if (showAlerts){
|
||||||
if(!karooConnected){
|
if(!karooConnected){
|
||||||
Text(modifier = Modifier.padding(5.dp), text = "Could not read device status. Is your Karoo updated?")
|
Text(modifier = Modifier.padding(5.dp), text = "Could not read device status. Is your Karoo updated?")
|
||||||
|
|||||||
@ -2,12 +2,12 @@
|
|||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="14dp">
|
android:layout_height="40dp">
|
||||||
|
|
||||||
<de.timklge.karoopowerbar.CustomProgressBar
|
<de.timklge.karoopowerbar.CustomProgressBar
|
||||||
android:id="@+id/progressBar"
|
android:id="@+id/progressBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="14dp"
|
android:layout_height="40dp"
|
||||||
android:layout_gravity="center" />
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|||||||
BIN
powerbar0.png
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 33 KiB |
BIN
powerbar1.png
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 47 KiB |
BIN
powerbar2.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
powerbar_min.gif
|
Before Width: | Height: | Size: 3.0 MiB After Width: | Height: | Size: 173 KiB |