From 3f1ae6d37f2afeb031c88502c4d7e93d5e236a47 Mon Sep 17 00:00:00 2001 From: Tim Kluge Date: Thu, 12 Dec 2024 23:06:20 +0100 Subject: [PATCH] ref #8,9: Replace arrow graphics --- .../datatypes/HeadwindDirectionDataType.kt | 11 ++- .../datatypes/HeadwindDirectionView.kt | 71 ++++++++---------- .../datatypes/WeatherDataType.kt | 8 +- .../karooheadwind/datatypes/WeatherView.kt | 5 +- app/src/main/res/drawable/arrow.png | Bin 0 -> 7148 bytes app/src/main/res/drawable/arrow_0.png | Bin 0 -> 980 bytes 6 files changed, 52 insertions(+), 43 deletions(-) create mode 100755 app/src/main/res/drawable/arrow.png create mode 100644 app/src/main/res/drawable/arrow_0.png 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 0000000000000000000000000000000000000000..e90573024d66cc60e7adc86241d03218505833e6 GIT binary patch literal 7148 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 V&r958Vc?k^L@+yKT6usJ^Ix8wq$>ab literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..a2013b4cad8b1180bef57bc2c95d27e8e6560d44 GIT binary patch literal 980 zcmeAS@N?(olHy`uVBq!ia0vp^?I6s-0wkxsYia~i3dtTpz6=aiY77hwEes65fI!oJfE3_0Js3;D^sNDPH;w>@G ziF(!V6#{l$)33T#Ev|TJ`Y+GW(EKl@@AsCx*JpDqGkC`LN&eUz$8SkzM4u=elW}A- ze8yHJlI*A8DN)Smd29x=huEnhOvxdi59yJ+?37Gd7Hta}pVJ|%1!E=dKSWS$)pdcpkQ^wIT$H2>i zsVO3HN+ApL#={yL%-+E>PVQ)z_z>Yw*g_s&UJ~4G&&0 zT;e+1c35(WY@29%$GSNVQAsxnEgH8R-SDJ?)$k{2iKZ@_n)s zWO`%;l6&H0&N~zty10A^s?R#=n)~2nd8dr{Gj03Wch^!U>wi5aw^+TsBaSy&=goAR zT}#`KSikK)y7>D&zdhnTvX%-(4o@0RFivDvVt3)|kP)Dn0B_x|@-6E>X=UDteEEO( bl<(3fQrj!P-|^ZB%tZ{Iu6{1-oD!M