diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/HeadwindDirectionDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/HeadwindDirectionDataType.kt index 75c6543..0ffdcb2 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/HeadwindDirectionDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/HeadwindDirectionDataType.kt @@ -1,6 +1,7 @@ package de.timklge.karooheadwind.datatypes import android.content.Context +import android.graphics.BitmapFactory import android.util.Log import androidx.compose.ui.unit.DpSize import androidx.glance.appwidget.ExperimentalGlanceRemoteViewsApi @@ -54,6 +55,12 @@ class HeadwindDirectionDataType( override fun startView(context: Context, config: ViewConfig, emitter: ViewEmitter) { Log.d(KarooHeadwindExtension.TAG, "Starting headwind direction view with $emitter") + + val baseBitmap = BitmapFactory.decodeResource( + context.resources, + de.timklge.karooheadwind.R.drawable.arrow + ) + val configJob = CoroutineScope(Dispatchers.IO).launch { emitter.onNext(UpdateGraphicConfig(showHeader = false)) awaitCancellation() @@ -76,10 +83,10 @@ class HeadwindDirectionDataType( val windSpeed = streamData.data.current.windSpeed val windDirection = streamData.value val headwindSpeed = cos( (windDirection + 180) * Math.PI / 180.0) * windSpeed - val windSpeedText = if(streamData.settings.showWindspeedOverlay) "${headwindSpeed.roundToInt()}" else null + val windSpeedText = "${headwindSpeed.roundToInt()}" val result = glance.compose(context, DpSize.Unspecified) { - HeadwindDirection(windDirection.roundToInt(), config.textSize, windSpeedText) + HeadwindDirection(baseBitmap, windDirection.roundToInt(), config.textSize, windSpeedText) } emitter.updateView(result.remoteViews) diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/HeadwindDirectionView.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/HeadwindDirectionView.kt index 2840757..09a1a23 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/HeadwindDirectionView.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/HeadwindDirectionView.kt @@ -1,23 +1,21 @@ package de.timklge.karooheadwind.datatypes -import android.R -import android.content.res.Resources +import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.Canvas import android.graphics.Paint -import android.graphics.Path +import android.util.Log import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.StrokeCap -import androidx.compose.ui.unit.TextUnit -import androidx.compose.ui.unit.TextUnitType +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.glance.ColorFilter import androidx.glance.GlanceModifier import androidx.glance.Image import androidx.glance.ImageProvider -import androidx.glance.LocalContext +import androidx.glance.appwidget.background import androidx.glance.background import androidx.glance.color.ColorProvider import androidx.glance.layout.Alignment @@ -27,45 +25,44 @@ import androidx.glance.layout.fillMaxSize import androidx.glance.layout.padding import androidx.glance.preview.ExperimentalGlancePreviewApi import androidx.glance.preview.Preview +import androidx.glance.text.FontFamily import androidx.glance.text.Text import androidx.glance.text.TextStyle +import de.timklge.karooheadwind.KarooHeadwindExtension import kotlin.math.roundToInt -val bitmapsByBearing = mutableMapOf() +data class BitmapWithBearing(val bitmap: Bitmap, val bearing: Int) -fun getArrowBitmapByBearing(bearing: Int): Bitmap { +val bitmapsByBearing = mutableMapOf() + + +fun getArrowBitmapByBearing(baseBitmap: Bitmap, bearing: Int): Bitmap { synchronized(bitmapsByBearing) { - val bearingRounded = (((bearing + 360) / 5.0).roundToInt() * 5) % 360 + val bearingRounded = (((bearing + 360) / 10.0).roundToInt() * 10) % 360 - val storedBitmap = bitmapsByBearing[bearingRounded] + val bitmapWithBearing = BitmapWithBearing(baseBitmap, bearingRounded) + val storedBitmap = bitmapsByBearing[bitmapWithBearing] if (storedBitmap != null) return storedBitmap val bitmap = Bitmap.createBitmap(128, 128, Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) val paint = Paint().apply { - color = android.graphics.Color.WHITE + color = android.graphics.Color.BLACK style = Paint.Style.STROKE - strokeWidth = 15f +// strokeWidth = 15f isAntiAlias = true } - val path = Path().apply { - moveTo(64f, 0f) // Top point of the arrow - lineTo(128f, 128f) // Bottom right point of the arrow - lineTo(64f, 96f) // Middle bottom point of the arrow - lineTo(0f, 128f) // Bottom left point of the arrow - close() // Close the path to form the arrow shape - } - canvas.save() - canvas.rotate(bearing.toFloat(), 64f, 64f) // Rotate the canvas based on the bearing - canvas.scale(0.75f, 0.75f, 64f, 64f) // Scale the arrow down to fit the canvas - canvas.drawPath(path, paint) + canvas.scale((bitmap.width / baseBitmap.width.toFloat()), (bitmap.height / baseBitmap.height.toFloat()), (bitmap.width / 2).toFloat(), (bitmap.height / 2).toFloat()) + Log.d(KarooHeadwindExtension.TAG, "Drawing arrow at $bearingRounded") + canvas.rotate(bearing.toFloat(), (bitmap.width / 2).toFloat(), (bitmap.height / 2).toFloat()) + canvas.drawBitmap(baseBitmap, ((bitmap.width - baseBitmap.width) / 2).toFloat(), ((bitmap.height - baseBitmap.height) / 2).toFloat(), paint) canvas.restore() - bitmapsByBearing[bearingRounded] = bitmap + bitmapsByBearing[bitmapWithBearing] = bitmap return bitmap } @@ -74,7 +71,7 @@ fun getArrowBitmapByBearing(bearing: Int): Bitmap { @OptIn(ExperimentalGlancePreviewApi::class) @Preview(widthDp = 200, heightDp = 150) @Composable -fun HeadwindDirection(bearing: Int, fontSize: Int, overlayText: String? = null) { +fun HeadwindDirection(baseBitmap: Bitmap, bearing: Int, fontSize: Int, overlayText: String) { Box( modifier = GlanceModifier.fillMaxSize().padding(5.dp), contentAlignment = Alignment( @@ -83,19 +80,17 @@ fun HeadwindDirection(bearing: Int, fontSize: Int, overlayText: String? = null) ), ) { Image( - modifier = GlanceModifier.fillMaxSize(), - provider = ImageProvider(getArrowBitmapByBearing(bearing)), - contentDescription = "Relative wind direction indicator", - contentScale = ContentScale.Fit, - colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White)) + modifier = GlanceModifier.fillMaxSize(), + provider = ImageProvider(getArrowBitmapByBearing(baseBitmap, bearing)), + contentDescription = "Relative wind direction indicator", + contentScale = ContentScale.Fit, + colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White)) ) - overlayText?.let { - Text( - overlayText, - style = TextStyle(ColorProvider(Color.White, Color.White), fontSize = TextUnit(fontSize.toFloat()*0.7f, TextUnitType.Sp)), - modifier = GlanceModifier.background(Color(0f, 0f, 0f, 0.5f)).padding(5.dp) - ) - } + Text( + overlayText, + style = TextStyle(ColorProvider(Color.Black, Color.White), fontSize = (0.5 * fontSize).sp, fontFamily = FontFamily.Monospace), + modifier = GlanceModifier.background(Color(1f, 1f, 1f, 0.5f), Color(0f, 0f, 0f, 0.5f)).padding(2.dp) + ) } } \ No newline at end of file diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherDataType.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherDataType.kt index 84c5626..82314dd 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherDataType.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherDataType.kt @@ -1,6 +1,7 @@ package de.timklge.karooheadwind.datatypes import android.content.Context +import android.graphics.BitmapFactory import android.util.Log import androidx.compose.ui.unit.DpSize import androidx.glance.appwidget.ExperimentalGlanceRemoteViewsApi @@ -58,6 +59,11 @@ class WeatherDataType( awaitCancellation() } + val baseBitmap = BitmapFactory.decodeResource( + context.resources, + de.timklge.karooheadwind.R.drawable.arrow_0 + ) + data class StreamData(val data: OpenMeteoCurrentWeatherResponse, val settings: HeadwindSettings) val viewJob = CoroutineScope(Dispatchers.IO).launch { @@ -73,7 +79,7 @@ class WeatherDataType( val interpretation = WeatherInterpretation.fromWeatherCode(data.current.weatherCode) val result = glance.compose(context, DpSize.Unspecified) { - Weather(interpretation, data.current.windDirection.roundToInt(), data.current.windSpeed.roundToInt(), data.current.windGusts.roundToInt()) + Weather(baseBitmap, interpretation, data.current.windDirection.roundToInt(), data.current.windSpeed.roundToInt(), data.current.windGusts.roundToInt()) } emitter.updateView(result.remoteViews) diff --git a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherView.kt b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherView.kt index 01306fb..857a751 100644 --- a/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherView.kt +++ b/app/src/main/kotlin/de/timklge/karooheadwind/datatypes/WeatherView.kt @@ -1,5 +1,6 @@ package de.timklge.karooheadwind.datatypes +import android.graphics.Bitmap import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.TextUnit @@ -41,7 +42,7 @@ fun getWeatherIcon(interpretation: WeatherInterpretation): Int { @OptIn(ExperimentalGlancePreviewApi::class) @Preview(widthDp = 200, heightDp = 150) @Composable -fun Weather(current: WeatherInterpretation, windBearing: Int, windSpeed: Int, windGusts: Int) { +fun Weather(baseBitmap: Bitmap, current: WeatherInterpretation, windBearing: Int, windSpeed: Int, windGusts: Int) { Column(modifier = GlanceModifier.fillMaxSize(), horizontalAlignment = Alignment.End) { Row(modifier = GlanceModifier.defaultWeight(), horizontalAlignment = Alignment.End) { val imageW = 70 @@ -58,7 +59,7 @@ fun Weather(current: WeatherInterpretation, windBearing: Int, windSpeed: Int, wi Row(horizontalAlignment = Alignment.CenterHorizontally, verticalAlignment = Alignment.CenterVertically) { Image( modifier = GlanceModifier.height(20.dp).width(12.dp), - provider = ImageProvider(getArrowBitmapByBearing(windBearing)), + provider = ImageProvider(getArrowBitmapByBearing(baseBitmap, windBearing)), contentDescription = "Current wind direction", contentScale = ContentScale.Fit, colorFilter = ColorFilter.tint(ColorProvider(Color.Black, Color.White)) diff --git a/app/src/main/res/drawable/arrow.png b/app/src/main/res/drawable/arrow.png new file mode 100755 index 0000000..e905730 Binary files /dev/null and b/app/src/main/res/drawable/arrow.png differ diff --git a/app/src/main/res/drawable/arrow_0.png b/app/src/main/res/drawable/arrow_0.png new file mode 100644 index 0000000..a2013b4 Binary files /dev/null and b/app/src/main/res/drawable/arrow_0.png differ