ref #8,9: Replace arrow graphics
This commit is contained in:
parent
7d1715707e
commit
3f1ae6d37f
@ -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)
|
||||
|
||||
@ -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<Int, Bitmap>()
|
||||
data class BitmapWithBearing(val bitmap: Bitmap, val bearing: Int)
|
||||
|
||||
fun getArrowBitmapByBearing(bearing: Int): Bitmap {
|
||||
val bitmapsByBearing = mutableMapOf<BitmapWithBearing, Bitmap>()
|
||||
|
||||
|
||||
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)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
|
||||
@ -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))
|
||||
|
||||
BIN
app/src/main/res/drawable/arrow.png
Executable file
BIN
app/src/main/res/drawable/arrow.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 7.0 KiB |
BIN
app/src/main/res/drawable/arrow_0.png
Normal file
BIN
app/src/main/res/drawable/arrow_0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 980 B |
Loading…
x
Reference in New Issue
Block a user