Rename weather icons, add monochrome variant
This commit is contained in:
@@ -3,13 +3,35 @@ package de.mm20.launcher2.ui.component.weather
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.animation.animateColor
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.animation.core.InfiniteRepeatableSpec
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.animateOffset
|
||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.core.updateTransition
|
||||
import androidx.compose.animation.graphics.res.animatedVectorResource
|
||||
import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
|
||||
import androidx.compose.animation.graphics.vector.AnimatedImageVector
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
@@ -41,9 +63,7 @@ fun AnimatedWeatherIcon(
|
||||
SunMoon(icon, night, colors)
|
||||
Precipitation(icon, colors)
|
||||
LightningBolt(icon, colors)
|
||||
LightningBolt2(icon, colors)
|
||||
Cloud1(icon, colors)
|
||||
Wind2(icon, colors)
|
||||
Cloud2(icon, colors)
|
||||
Cloud3(icon, colors)
|
||||
Fog(icon, colors)
|
||||
@@ -63,18 +83,16 @@ private fun SunMoon(icon: WeatherIcon, night: Boolean, colors: WeatherIconColors
|
||||
when (it) {
|
||||
WeatherIcon.Clear,
|
||||
WeatherIcon.PartlyCloudy,
|
||||
WeatherIcon.BrokenClouds,
|
||||
WeatherIcon.Haze -> 1f
|
||||
WeatherIcon.MostlyCloudy -> 0.8f
|
||||
|
||||
else -> 0f
|
||||
}
|
||||
}
|
||||
val offset by transition.animateOffset(label = "sunOffset") {
|
||||
when (it) {
|
||||
WeatherIcon.Clear,
|
||||
WeatherIcon.BrokenClouds,
|
||||
WeatherIcon.Haze -> Offset.Zero
|
||||
WeatherIcon.MostlyCloudy -> Offset(6f, -4f)
|
||||
|
||||
WeatherIcon.PartlyCloudy -> Offset(3f, -2f)
|
||||
else -> Offset.Zero
|
||||
}
|
||||
@@ -97,19 +115,17 @@ private fun LightningBolt(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
|
||||
val scale by transition.animateFloat(label = "scale") {
|
||||
when (it) {
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm -> 0.6f
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Thunderstorm -> 0.6f
|
||||
|
||||
else -> 0f
|
||||
}
|
||||
}
|
||||
val offset by transition.animateOffset(label = "offset") {
|
||||
when (it) {
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Thunderstorm -> Offset(1f, 8f)
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm -> Offset(6f, 8f)
|
||||
|
||||
else -> Offset.Zero
|
||||
}
|
||||
}
|
||||
@@ -125,35 +141,6 @@ private fun LightningBolt(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LightningBolt2(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
val transition = updateTransition(targetState = icon, "AnimatedWeatherIconBolt2")
|
||||
|
||||
val scale by transition.animateFloat(label = "scale") {
|
||||
when (it) {
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm -> 0.5f
|
||||
else -> 0f
|
||||
}
|
||||
}
|
||||
val offset by transition.animateOffset(label = "offset") {
|
||||
when (it) {
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm -> Offset(-9f, 5f)
|
||||
else -> Offset.Zero
|
||||
}
|
||||
}
|
||||
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.bolt_24px_filled),
|
||||
null,
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
.offset(offset.x.dp, offset.y.dp)
|
||||
.scale(scale),
|
||||
tint = colors.lightningBolt
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Cloud1(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
@@ -162,64 +149,60 @@ private fun Cloud1(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
val scale by transition.animateFloat(label = "scale") {
|
||||
when (it) {
|
||||
WeatherIcon.Clear -> 0f
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Wind,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Storm,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Wind,
|
||||
WeatherIcon.Fog -> 1.4f
|
||||
WeatherIcon.MostlyCloudy,
|
||||
|
||||
WeatherIcon.PartlyCloudy -> 1f
|
||||
WeatherIcon.BrokenClouds -> 0.9f
|
||||
else -> 0f
|
||||
}
|
||||
}
|
||||
val offset by transition.animateOffset(label = "offset") {
|
||||
when (it) {
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> Offset(0f, -14f)
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Thunderstorm -> Offset(0f, -14f)
|
||||
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Wind,
|
||||
WeatherIcon.Storm,
|
||||
WeatherIcon.Fog -> Offset(0f, -5f)
|
||||
WeatherIcon.MostlyCloudy -> Offset(-5f, 0f)
|
||||
|
||||
WeatherIcon.PartlyCloudy -> Offset(-3f, 4f)
|
||||
WeatherIcon.BrokenClouds -> Offset(-5f, 7f)
|
||||
else -> Offset.Zero
|
||||
}
|
||||
}
|
||||
val color by transition.animateColor(label = "color") {
|
||||
when (it) {
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.Storm -> colors.cloudDark2
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Wind -> colors.cloudDark2
|
||||
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Wind,
|
||||
WeatherIcon.Fog -> colors.cloudDark1
|
||||
WeatherIcon.Drizzle,
|
||||
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Snow -> colors.cloudMedium2
|
||||
WeatherIcon.MostlyCloudy -> colors.cloudLight2
|
||||
WeatherIcon.PartlyCloudy,
|
||||
WeatherIcon.BrokenClouds -> colors.cloudLight1
|
||||
|
||||
WeatherIcon.PartlyCloudy -> colors.cloudLight1
|
||||
else -> colors.cloudMedium2
|
||||
}
|
||||
}
|
||||
@@ -241,61 +224,55 @@ private fun Cloud2(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
|
||||
val scale by transition.animateFloat(label = "scale") {
|
||||
when (it) {
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.MostlyCloudy,
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Wind,
|
||||
WeatherIcon.Storm,
|
||||
WeatherIcon.Fog -> 1.1f
|
||||
WeatherIcon.BrokenClouds -> 0.7f
|
||||
|
||||
else -> 0f
|
||||
}
|
||||
}
|
||||
val offset by transition.animateOffset(label = "offset") {
|
||||
when (it) {
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> Offset(-6f, -6f)
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Thunder -> Offset(-6f, -6f)
|
||||
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Wind,
|
||||
WeatherIcon.Storm,
|
||||
WeatherIcon.Fog -> Offset(-6f, 3f)
|
||||
WeatherIcon.BrokenClouds -> Offset(9f, -9f)
|
||||
WeatherIcon.MostlyCloudy -> Offset(4f, 5f)
|
||||
|
||||
else -> Offset.Zero
|
||||
}
|
||||
}
|
||||
val color by transition.animateColor(label = "color") {
|
||||
when (it) {
|
||||
WeatherIcon.BrokenClouds -> colors.cloudLight2
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.Storm -> colors.cloudMedium2
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Wind -> colors.cloudMedium2
|
||||
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Wind,
|
||||
WeatherIcon.Fog -> colors.cloudMedium1
|
||||
WeatherIcon.MostlyCloudy -> colors.cloudMedium1
|
||||
|
||||
else -> colors.cloudMedium2
|
||||
}
|
||||
}
|
||||
@@ -317,52 +294,53 @@ private fun Cloud3(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
|
||||
val scale by transition.animateFloat(label = "scale") {
|
||||
when (it) {
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Wind,
|
||||
WeatherIcon.Storm -> 1f
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Wind -> 1f
|
||||
|
||||
else -> 0f
|
||||
}
|
||||
}
|
||||
val offset by transition.animateOffset(label = "offset") {
|
||||
when (it) {
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> Offset(6f, -4f)
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Wind,
|
||||
WeatherIcon.Storm -> Offset(6f, 5f)
|
||||
WeatherIcon.Thunder -> Offset(6f, -4f)
|
||||
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Wind -> Offset(6f, 5f)
|
||||
|
||||
else -> Offset.Zero
|
||||
}
|
||||
}
|
||||
val color by transition.animateColor(label = "color") {
|
||||
when (it) {
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.Storm -> colors.cloudDark1
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Wind -> colors.cloudDark1
|
||||
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Wind -> colors.cloudMedium2
|
||||
WeatherIcon.Drizzle,
|
||||
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Snow -> colors.cloudLight2
|
||||
|
||||
else -> colors.cloudMedium2
|
||||
}
|
||||
}
|
||||
@@ -381,7 +359,7 @@ private fun Cloud3(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
@Composable
|
||||
private fun Hot(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
val scale by animateFloatAsState(
|
||||
if (icon == WeatherIcon.Hot) {
|
||||
if (icon == WeatherIcon.ExtremeHeat) {
|
||||
1f
|
||||
} else {
|
||||
0f
|
||||
@@ -400,7 +378,7 @@ private fun Hot(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
@Composable
|
||||
private fun Cold(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
val scale by animateFloatAsState(
|
||||
if (icon == WeatherIcon.Cold) {
|
||||
if (icon == WeatherIcon.ExtremeCold) {
|
||||
1f
|
||||
} else {
|
||||
0f
|
||||
@@ -419,7 +397,7 @@ private fun Cold(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
@Composable
|
||||
private fun Wind1(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
val scale by animateFloatAsState(
|
||||
if (icon == WeatherIcon.Wind || icon == WeatherIcon.Storm) {
|
||||
if (icon == WeatherIcon.Wind) {
|
||||
0.6f
|
||||
} else {
|
||||
0f
|
||||
@@ -436,38 +414,38 @@ private fun Wind1(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Wind2(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
val scale by animateFloatAsState(
|
||||
if (icon == WeatherIcon.Storm) {
|
||||
0.6f
|
||||
} else {
|
||||
0f
|
||||
}
|
||||
)
|
||||
Icon(
|
||||
painterResource(R.drawable.air_20px),
|
||||
null,
|
||||
modifier = Modifier
|
||||
.scale(scale)
|
||||
.offset(8.dp, -1.dp)
|
||||
.size(32.dp),
|
||||
tint = colors.windDark
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AnimatedWeatherIconTestPanel() {
|
||||
var icon by remember { mutableStateOf(WeatherIcon.ThunderstormWithRain) }
|
||||
var icon by remember { mutableStateOf(WeatherIcon.Thunderstorm) }
|
||||
var night by remember { mutableStateOf(false) }
|
||||
Row {
|
||||
val icons = WeatherIcon.values()
|
||||
val icons = WeatherIcon.entries
|
||||
Column(
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
AnimatedWeatherIcon(icon = icon, night = night)
|
||||
WeatherIcon(icon = icon, night = night)
|
||||
|
||||
val monochromeColors = WeatherIconDefaults.monochromeColors(
|
||||
MaterialTheme.colorScheme.secondary
|
||||
)
|
||||
|
||||
AnimatedWeatherIcon(
|
||||
modifier = Modifier.background(MaterialTheme.colorScheme.secondary),
|
||||
icon = icon,
|
||||
night = night,
|
||||
colors = monochromeColors
|
||||
)
|
||||
|
||||
WeatherIcon(
|
||||
modifier = Modifier.background(MaterialTheme.colorScheme.secondary),
|
||||
icon = icon,
|
||||
night = night,
|
||||
colors = monochromeColors
|
||||
)
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -510,7 +488,7 @@ private fun Precipitation(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
) {
|
||||
Crossfade(icon) {
|
||||
when (it) {
|
||||
WeatherIcon.Drizzle -> {
|
||||
WeatherIcon.LightRain, WeatherIcon.Rain -> {
|
||||
val anim = rememberInfiniteTransition()
|
||||
val animProgress by anim.animateFloat(
|
||||
initialValue = 0f, targetValue = 1f, animationSpec = InfiniteRepeatableSpec(
|
||||
@@ -526,6 +504,7 @@ private fun Precipitation(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
tint = colors.rain
|
||||
)
|
||||
}
|
||||
|
||||
WeatherIcon.Hail -> {
|
||||
val anim = rememberInfiniteTransition()
|
||||
val animProgress by anim.animateFloat(
|
||||
@@ -542,6 +521,7 @@ private fun Precipitation(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
tint = colors.hail,
|
||||
)
|
||||
}
|
||||
|
||||
WeatherIcon.Snow -> {
|
||||
val anim = rememberInfiniteTransition()
|
||||
val animProgress by anim.animateFloat(
|
||||
@@ -561,9 +541,9 @@ private fun Precipitation(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
tint = colors.snow,
|
||||
)
|
||||
}
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> {
|
||||
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Thunderstorm -> {
|
||||
val anim = rememberInfiniteTransition()
|
||||
val animProgress by anim.animateFloat(
|
||||
initialValue = 0f, targetValue = 1f, animationSpec = InfiniteRepeatableSpec(
|
||||
@@ -579,6 +559,7 @@ private fun Precipitation(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
tint = colors.rain,
|
||||
)
|
||||
}
|
||||
|
||||
WeatherIcon.Sleet -> {
|
||||
val anim = rememberInfiniteTransition()
|
||||
val animProgress by anim.animateFloat(
|
||||
@@ -603,6 +584,7 @@ private fun Precipitation(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
tint = colors.snow,
|
||||
)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@@ -625,25 +607,36 @@ private fun Fog(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
}
|
||||
|
||||
enum class WeatherIcon {
|
||||
None,
|
||||
Unknown,
|
||||
|
||||
Clear,
|
||||
Cloudy,
|
||||
Cold,
|
||||
Drizzle,
|
||||
Haze,
|
||||
Fog,
|
||||
Hail,
|
||||
HeavyThunderstorm,
|
||||
HeavyThunderstormWithRain,
|
||||
Hot,
|
||||
MostlyCloudy,
|
||||
PartlyCloudy,
|
||||
Showers,
|
||||
Sleet,
|
||||
Snow,
|
||||
Storm,
|
||||
Overcast,
|
||||
|
||||
LightRain,
|
||||
Rain,
|
||||
HeavyRain,
|
||||
|
||||
/**
|
||||
* Thunder and lightning without rain
|
||||
*/
|
||||
Thunder,
|
||||
|
||||
/**
|
||||
* Thunder and lightning with rain
|
||||
*/
|
||||
Thunderstorm,
|
||||
ThunderstormWithRain,
|
||||
|
||||
Snow,
|
||||
Sleet,
|
||||
Hail,
|
||||
|
||||
ExtremeHeat,
|
||||
ExtremeCold,
|
||||
|
||||
Wind,
|
||||
BrokenClouds
|
||||
|
||||
Fog,
|
||||
Haze,
|
||||
|
||||
}
|
||||
@@ -43,10 +43,7 @@ private fun SunMoon(icon: WeatherIcon, night: Boolean, colors: WeatherIconColors
|
||||
when (icon) {
|
||||
WeatherIcon.Clear,
|
||||
WeatherIcon.PartlyCloudy,
|
||||
WeatherIcon.BrokenClouds,
|
||||
WeatherIcon.Haze,
|
||||
WeatherIcon.MostlyCloudy -> {
|
||||
}
|
||||
WeatherIcon.Haze, -> {}
|
||||
|
||||
else -> return
|
||||
}
|
||||
@@ -56,15 +53,10 @@ private fun SunMoon(icon: WeatherIcon, night: Boolean, colors: WeatherIconColors
|
||||
val scale = when (icon) {
|
||||
WeatherIcon.Clear,
|
||||
WeatherIcon.PartlyCloudy,
|
||||
WeatherIcon.BrokenClouds,
|
||||
WeatherIcon.Haze -> 1f
|
||||
|
||||
WeatherIcon.MostlyCloudy -> 0.8f
|
||||
else -> 0f
|
||||
}
|
||||
|
||||
val offset = when (icon) {
|
||||
WeatherIcon.MostlyCloudy -> DpOffset(2.dp, -3.dp)
|
||||
WeatherIcon.PartlyCloudy -> DpOffset(2.dp, -2.dp)
|
||||
else -> DpOffset.Zero
|
||||
}
|
||||
@@ -85,19 +77,16 @@ private fun Cloud1(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
|
||||
when (icon) {
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Fog,
|
||||
WeatherIcon.MostlyCloudy,
|
||||
WeatherIcon.PartlyCloudy,
|
||||
WeatherIcon.BrokenClouds -> {
|
||||
WeatherIcon.PartlyCloudy -> {
|
||||
}
|
||||
|
||||
else -> return
|
||||
@@ -105,62 +94,48 @@ private fun Cloud1(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
|
||||
val scale = when (icon) {
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Fog -> 1.4f
|
||||
|
||||
WeatherIcon.MostlyCloudy,
|
||||
WeatherIcon.PartlyCloudy -> 1f
|
||||
|
||||
WeatherIcon.BrokenClouds -> 0.9f
|
||||
else -> 0f
|
||||
}
|
||||
val offset = when (icon) {
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> DpOffset(0.dp, -7.dp)
|
||||
WeatherIcon.Thunder -> DpOffset(0.dp, -7.dp)
|
||||
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Fog -> DpOffset(0.dp, -2.5.dp)
|
||||
|
||||
WeatherIcon.MostlyCloudy -> DpOffset(-2.5.dp, 0.dp)
|
||||
WeatherIcon.PartlyCloudy -> DpOffset(-1.5.dp, 2.dp)
|
||||
WeatherIcon.BrokenClouds -> DpOffset(-2.5.dp, 3.5.dp)
|
||||
else -> DpOffset.Zero
|
||||
}
|
||||
val color = when (icon) {
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> colors.cloudDark2
|
||||
WeatherIcon.Thunder -> colors.cloudDark2
|
||||
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Fog -> colors.cloudDark1
|
||||
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Snow -> colors.cloudMedium2
|
||||
|
||||
WeatherIcon.MostlyCloudy -> colors.cloudLight2
|
||||
WeatherIcon.PartlyCloudy,
|
||||
WeatherIcon.BrokenClouds -> colors.cloudLight1
|
||||
|
||||
else -> colors.cloudMedium2
|
||||
WeatherIcon.PartlyCloudy -> colors.cloudLight1
|
||||
}
|
||||
|
||||
Icon(
|
||||
@@ -179,18 +154,15 @@ private fun Cloud2(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
|
||||
when (icon) {
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.MostlyCloudy,
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Fog,
|
||||
WeatherIcon.BrokenClouds -> {
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Fog -> {
|
||||
}
|
||||
|
||||
else -> return
|
||||
@@ -198,56 +170,41 @@ private fun Cloud2(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
|
||||
val scale = when (icon) {
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.MostlyCloudy,
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Fog -> 1.1f
|
||||
|
||||
WeatherIcon.BrokenClouds -> 0.7f
|
||||
else -> 0f
|
||||
}
|
||||
val offset = when (icon) {
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> DpOffset(-3.dp, -3.dp)
|
||||
WeatherIcon.Thunder -> DpOffset(-3.dp, -3.dp)
|
||||
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Fog -> DpOffset(-3.dp, 1.5.dp)
|
||||
|
||||
WeatherIcon.BrokenClouds -> DpOffset(4.5.dp, -4.5.dp)
|
||||
WeatherIcon.MostlyCloudy -> DpOffset(2.dp, 2.5.dp)
|
||||
else -> DpOffset.Zero
|
||||
}
|
||||
val color = when (icon) {
|
||||
WeatherIcon.BrokenClouds -> colors.cloudLight2
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> colors.cloudMedium2
|
||||
WeatherIcon.Thunder -> colors.cloudMedium2
|
||||
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Overcast,
|
||||
WeatherIcon.Fog -> colors.cloudMedium1
|
||||
|
||||
WeatherIcon.MostlyCloudy -> colors.cloudMedium1
|
||||
else -> colors.cloudMedium2
|
||||
}
|
||||
|
||||
Icon(
|
||||
@@ -264,52 +221,41 @@ private fun Cloud2(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
@Composable
|
||||
private fun Cloud3(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
when (icon) {
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain,
|
||||
WeatherIcon.Cloudy -> {
|
||||
|
||||
}
|
||||
WeatherIcon.Thunder,
|
||||
WeatherIcon.Overcast -> {}
|
||||
|
||||
else -> return
|
||||
}
|
||||
val offset = when (icon) {
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> DpOffset(3.dp, -2.dp)
|
||||
|
||||
WeatherIcon.Cloudy,
|
||||
WeatherIcon.Fog -> DpOffset(3.dp, 2.5.dp)
|
||||
|
||||
else -> DpOffset.Zero
|
||||
WeatherIcon.Thunder -> DpOffset(3.dp, -2.dp)
|
||||
WeatherIcon.Overcast -> DpOffset(3.dp, 2.5.dp)
|
||||
}
|
||||
val color = when (icon) {
|
||||
WeatherIcon.Thunderstorm,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstorm,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> colors.cloudDark1
|
||||
WeatherIcon.Thunder -> colors.cloudDark1
|
||||
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Sleet,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Cloudy -> colors.cloudMedium2
|
||||
WeatherIcon.Overcast -> colors.cloudMedium2
|
||||
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Snow -> colors.cloudLight2
|
||||
|
||||
else -> colors.cloudMedium2
|
||||
}
|
||||
|
||||
Icon(
|
||||
@@ -345,30 +291,26 @@ private fun Precipitation(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
}
|
||||
|
||||
when (icon) {
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Hail,
|
||||
WeatherIcon.Snow,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> {
|
||||
WeatherIcon.Thunderstorm -> {
|
||||
}
|
||||
|
||||
else -> return
|
||||
}
|
||||
val vector = when (icon) {
|
||||
WeatherIcon.Drizzle -> WeatherLightRain
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> WeatherRain
|
||||
|
||||
WeatherIcon.LightRain, WeatherIcon.Rain -> WeatherLightRain
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Thunderstorm -> WeatherRain
|
||||
WeatherIcon.Hail, WeatherIcon.Snow -> WeatherHail
|
||||
else -> WeatherLightRain
|
||||
}
|
||||
val color = when (icon) {
|
||||
WeatherIcon.Drizzle,
|
||||
WeatherIcon.Showers,
|
||||
WeatherIcon.ThunderstormWithRain,
|
||||
WeatherIcon.HeavyThunderstormWithRain -> colors.rain
|
||||
WeatherIcon.LightRain,
|
||||
WeatherIcon.Rain,
|
||||
WeatherIcon.HeavyRain,
|
||||
WeatherIcon.Thunderstorm -> colors.rain
|
||||
|
||||
WeatherIcon.Hail -> colors.hail
|
||||
WeatherIcon.Snow -> colors.snow
|
||||
@@ -386,7 +328,7 @@ private fun Precipitation(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
|
||||
@Composable
|
||||
private fun HotCold(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
if (icon == WeatherIcon.Hot) {
|
||||
if (icon == WeatherIcon.ExtremeHeat) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(32.dp),
|
||||
@@ -395,7 +337,7 @@ private fun HotCold(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
tint = colors.hot
|
||||
)
|
||||
}
|
||||
if (icon == WeatherIcon.Cold) {
|
||||
if (icon == WeatherIcon.ExtremeCold) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(32.dp),
|
||||
@@ -408,20 +350,10 @@ private fun HotCold(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
|
||||
@Composable
|
||||
private fun Wind(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
if (icon == WeatherIcon.Storm) {
|
||||
if (icon == WeatherIcon.Wind) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.offset(x = 4.dp, y = 0.dp)
|
||||
.size(24.dp),
|
||||
painter = painterResource(R.drawable.air_24px),
|
||||
contentDescription = null,
|
||||
tint = colors.windDark
|
||||
)
|
||||
}
|
||||
if (icon == WeatherIcon.Wind || icon == WeatherIcon.Storm) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(if (icon == WeatherIcon.Wind) 32.dp else 24.dp),
|
||||
.size(32.dp),
|
||||
painter = painterResource(R.drawable.air_24px),
|
||||
contentDescription = null,
|
||||
tint = colors.wind
|
||||
@@ -449,34 +381,18 @@ private fun Fog(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
@Composable
|
||||
private fun LightningBolts(icon: WeatherIcon, colors: WeatherIconColors) {
|
||||
|
||||
if (icon != WeatherIcon.ThunderstormWithRain
|
||||
&& icon != WeatherIcon.HeavyThunderstormWithRain
|
||||
&& icon != WeatherIcon.Thunderstorm
|
||||
&& icon != WeatherIcon.HeavyThunderstorm
|
||||
if (icon != WeatherIcon.Thunderstorm
|
||||
&& icon != WeatherIcon.Thunder
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
val isHeavy =
|
||||
icon == WeatherIcon.HeavyThunderstormWithRain || icon == WeatherIcon.HeavyThunderstorm
|
||||
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(12.dp)
|
||||
.offset(x = if (isHeavy) 4.dp else 1.dp, y = 6.dp),
|
||||
.offset(x = 1.dp, y = 6.dp),
|
||||
painter = painterResource(R.drawable.bolt_24px_filled),
|
||||
contentDescription = null,
|
||||
tint = colors.lightningBolt
|
||||
)
|
||||
|
||||
if (icon == WeatherIcon.HeavyThunderstorm || icon == WeatherIcon.HeavyThunderstormWithRain) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(10.dp)
|
||||
.offset(x = -3.dp, y = 6.dp),
|
||||
painter = painterResource(R.drawable.bolt_24px_filled),
|
||||
contentDescription = null,
|
||||
tint = colors.lightningBolt
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package de.mm20.launcher2.ui.component.weather
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -10,9 +8,9 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import blend.Blend
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.ktx.atTone
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import hct.Hct
|
||||
|
||||
|
||||
data class WeatherIconColors(
|
||||
@@ -38,38 +36,138 @@ data class WeatherIconColors(
|
||||
object WeatherIconDefaults {
|
||||
@Composable
|
||||
fun colors(): WeatherIconColors {
|
||||
val darkTheme = LocalDarkTheme.current
|
||||
|
||||
if (darkTheme) {
|
||||
return darkColors()
|
||||
} else {
|
||||
return lightColors()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun invertedColors(): WeatherIconColors {
|
||||
val darkTheme = LocalDarkTheme.current
|
||||
|
||||
if (!darkTheme) {
|
||||
return darkColors()
|
||||
} else {
|
||||
return lightColors()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun darkColors(): WeatherIconColors {
|
||||
val context = LocalContext.current
|
||||
|
||||
val themeColor = MaterialTheme.colorScheme.primary
|
||||
val darkTheme = LocalDarkTheme.current
|
||||
|
||||
val neutral1 = MaterialTheme.colorScheme.outline
|
||||
val neutral2 = MaterialTheme.colorScheme.outline
|
||||
|
||||
return remember(themeColor) {
|
||||
WeatherIconColors(
|
||||
sun = harmonize(context, 0xFFFFB300.toInt(), themeColor),
|
||||
moon = harmonize(context, 0xFF9E9E9E.toInt(), themeColor),
|
||||
cloudDark1 = harmonize(context, neutral1.atTone(if (darkTheme) 40 else 30).toArgb(), themeColor),
|
||||
cloudDark2 = harmonize(context, neutral1.atTone(if (darkTheme) 30 else 20).toArgb(), themeColor),
|
||||
cloudMedium1 = harmonize(context, neutral1.atTone(if (darkTheme) 60 else 50).toArgb(), themeColor),
|
||||
cloudMedium2 = harmonize(context, neutral1.atTone(if (darkTheme) 50 else 40).toArgb(), themeColor),
|
||||
cloudLight1 = harmonize(context, neutral1.atTone(if (darkTheme) 95 else 85).toArgb(), themeColor),
|
||||
cloudLight2 = harmonize(context, neutral1.atTone(if (darkTheme) 85 else 75).toArgb(), themeColor),
|
||||
rain = harmonize(context, if (darkTheme) 0xFF64B5F6.toInt() else 0xFF1E88E5.toInt(), themeColor),
|
||||
snow = harmonize(context, if (darkTheme) 0xFFF5F5F5.toInt() else 0xFFE0E0E0.toInt(), themeColor),
|
||||
hail = harmonize(context, if (darkTheme) 0xFFF5F5F5.toInt() else 0xFFE0E0E0.toInt(), themeColor),
|
||||
fog = harmonize(context, neutral1.atTone(if (darkTheme) 95 else 85).toArgb(), themeColor),
|
||||
wind = harmonize(context, neutral2.atTone(if (darkTheme) 70 else 75).toArgb(), themeColor),
|
||||
windDark = harmonize(context, neutral2.atTone(if (darkTheme) 40 else 45).toArgb(), themeColor),
|
||||
lightningBolt = harmonize(context, 0xFFFFB300.toInt(), themeColor),
|
||||
hot = harmonize(context, if (darkTheme) 0xFFE57373.toInt() else 0xFFE53935.toInt(), themeColor),
|
||||
cold = harmonize(context, if (darkTheme) 0xFF4FC3F7.toInt() else 0xFF039BE5.toInt(), themeColor),
|
||||
sun = harmonize(0xFFFFB300.toInt(), themeColor),
|
||||
moon = harmonize(0xFF9E9E9E.toInt(), themeColor),
|
||||
cloudDark1 = harmonize(neutral1.atTone(40).toArgb(), themeColor),
|
||||
cloudDark2 = harmonize(neutral1.atTone(30).toArgb(), themeColor),
|
||||
cloudMedium1 = harmonize(neutral1.atTone(60).toArgb(), themeColor),
|
||||
cloudMedium2 = harmonize(neutral1.atTone(50).toArgb(), themeColor),
|
||||
cloudLight1 = harmonize(neutral1.atTone(95).toArgb(), themeColor),
|
||||
cloudLight2 = harmonize(neutral1.atTone(85).toArgb(), themeColor),
|
||||
rain = harmonize(0xFF64B5F6.toInt(), themeColor),
|
||||
snow = harmonize(0xFFF5F5F5.toInt(), themeColor),
|
||||
hail = harmonize(0xFFF5F5F5.toInt(), themeColor),
|
||||
fog = harmonize(neutral1.atTone(95).toArgb(), themeColor),
|
||||
wind = harmonize(neutral2.atTone(70).toArgb(), themeColor),
|
||||
windDark = harmonize(neutral2.atTone(40).toArgb(), themeColor),
|
||||
lightningBolt = harmonize(0xFFFFB300.toInt(), themeColor),
|
||||
hot = harmonize(0xFFE57373.toInt(), themeColor),
|
||||
cold = harmonize(0xFF4FC3F7.toInt(), themeColor),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun lightColors(): WeatherIconColors {
|
||||
val context = LocalContext.current
|
||||
|
||||
val themeColor = MaterialTheme.colorScheme.primary
|
||||
val neutral1 = MaterialTheme.colorScheme.outline
|
||||
val neutral2 = MaterialTheme.colorScheme.outline
|
||||
|
||||
return remember(themeColor) {
|
||||
WeatherIconColors(
|
||||
sun = harmonize(0xFFFFB300.toInt(), themeColor),
|
||||
moon = harmonize(0xFF9E9E9E.toInt(), themeColor),
|
||||
cloudDark1 = harmonize(neutral1.atTone(30).toArgb(), themeColor),
|
||||
cloudDark2 = harmonize(neutral1.atTone(20).toArgb(), themeColor),
|
||||
cloudMedium1 = harmonize(neutral1.atTone(50).toArgb(), themeColor),
|
||||
cloudMedium2 = harmonize(neutral1.atTone(40).toArgb(), themeColor),
|
||||
cloudLight1 = harmonize(neutral1.atTone(85).toArgb(), themeColor),
|
||||
cloudLight2 = harmonize(neutral1.atTone(75).toArgb(), themeColor),
|
||||
rain = harmonize(0xFF1E88E5.toInt(), themeColor),
|
||||
snow = harmonize(0xFFE0E0E0.toInt(), themeColor),
|
||||
hail = harmonize(0xFFE0E0E0.toInt(), themeColor),
|
||||
fog = harmonize(neutral1.atTone(85).toArgb(), themeColor),
|
||||
wind = harmonize(neutral2.atTone(75).toArgb(), themeColor),
|
||||
windDark = harmonize(neutral2.atTone(45).toArgb(), themeColor),
|
||||
lightningBolt = harmonize(0xFFFFB300.toInt(), themeColor),
|
||||
hot = harmonize(0xFFE53935.toInt(), themeColor),
|
||||
cold = harmonize(0xFF039BE5.toInt(), themeColor),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun monochromeColors(baseColor: Color): WeatherIconColors {
|
||||
val baseTone = Hct.fromInt(baseColor.toArgb()).tone.toInt()
|
||||
|
||||
return remember(baseColor) {
|
||||
/**
|
||||
* Adjusts the tone of a color.
|
||||
* The tone is adjusted up or down to not overlap with the base color's tone.
|
||||
*
|
||||
* @param tone The tone to adjust.
|
||||
* @return The adjusted tone.
|
||||
*/
|
||||
fun t(tone: Int): Int {
|
||||
val upper = (baseTone + 15f).coerceAtMost(100f)
|
||||
val lower = (baseTone - 15f).coerceAtLeast(0f)
|
||||
val diff = upper - lower
|
||||
val scale = (100f - diff) / 100f
|
||||
|
||||
val tn = tone * scale
|
||||
|
||||
if (tn > lower) {
|
||||
return (tn + diff).toInt()
|
||||
}
|
||||
return tn.toInt()
|
||||
}
|
||||
|
||||
WeatherIconColors(
|
||||
sun = baseColor.atTone(t(90)),
|
||||
moon = baseColor.atTone(t(90)),
|
||||
cloudDark1 = baseColor.atTone(t(25)),
|
||||
cloudDark2 = baseColor.atTone(t(15)),
|
||||
cloudMedium1 = baseColor.atTone(t(45)),
|
||||
cloudMedium2 = baseColor.atTone(t(35)),
|
||||
cloudLight1 = baseColor.atTone(t(65)),
|
||||
cloudLight2 = baseColor.atTone(t(55)),
|
||||
rain = baseColor.atTone(t(55)),
|
||||
snow = baseColor.atTone(t(100)),
|
||||
hail = baseColor.atTone(t(90)),
|
||||
fog = baseColor.atTone(t(60)),
|
||||
wind = baseColor.atTone(t(65)),
|
||||
windDark = baseColor.atTone(t(45)),
|
||||
lightningBolt = baseColor.atTone(t(90)),
|
||||
hot = baseColor.atTone(t(55)),
|
||||
cold = baseColor.atTone(t(55)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun harmonize(context: Context, @ColorInt baseColor: Int, themeColor: Color): Color {
|
||||
private fun harmonize(@ColorInt baseColor: Int, themeColor: Color): Color {
|
||||
return Color(Blend.harmonize(baseColor, themeColor.toArgb()))
|
||||
}
|
||||
@@ -6,12 +6,14 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.text.format.DateUtils
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.expandHorizontally
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkHorizontally
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.LocalIndication
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -79,6 +81,8 @@ import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||
import de.mm20.launcher2.ui.component.Tooltip
|
||||
import de.mm20.launcher2.ui.component.weather.AnimatedWeatherIcon
|
||||
import de.mm20.launcher2.ui.component.weather.WeatherIcon
|
||||
import de.mm20.launcher2.ui.component.weather.WeatherIconDefaults
|
||||
import de.mm20.launcher2.ui.ktx.animateShapeAsState
|
||||
import de.mm20.launcher2.ui.locals.LocalMeasurementSystem
|
||||
import de.mm20.launcher2.ui.locals.LocalTimeFormat
|
||||
import de.mm20.launcher2.ui.theme.transparency.transparency
|
||||
@@ -187,21 +191,32 @@ fun WeatherWidget(widget: WeatherWidget) {
|
||||
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.surfaceContainer.copy(alpha = MaterialTheme.transparency.surface),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(8.dp),
|
||||
shape = MaterialTheme.shapes.small,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)
|
||||
modifier = Modifier.padding(top = 8.dp, bottom = 8.dp)
|
||||
) {
|
||||
WeatherTimeSelector(
|
||||
forecasts = currentDayForecasts,
|
||||
selectedForecast = forecast,
|
||||
measurementSystem = measurementSystem,
|
||||
timeFormat = timeFormat,
|
||||
onTimeSelected = {
|
||||
viewModel.selectForecast(it)
|
||||
},
|
||||
modifier = Modifier.padding(bottom = 12.dp)
|
||||
)
|
||||
AnimatedContent(
|
||||
currentDayForecasts to forecast,
|
||||
contentKey = { it.first },
|
||||
transitionSpec = {
|
||||
fadeIn() togetherWith fadeOut()
|
||||
}
|
||||
) { (fcs, fc) ->
|
||||
WeatherTimeSelector(
|
||||
forecasts = fcs,
|
||||
selectedForecast = fc,
|
||||
measurementSystem = measurementSystem,
|
||||
timeFormat = timeFormat,
|
||||
onTimeSelected = {
|
||||
viewModel.selectForecast(it)
|
||||
},
|
||||
modifier = Modifier.padding(bottom = 8.dp)
|
||||
)
|
||||
}
|
||||
selectedDayForecast?.let {
|
||||
WeatherDaySelector(
|
||||
days = dailyForecasts,
|
||||
@@ -469,12 +484,16 @@ fun WeatherTimeSelector(
|
||||
val context = LocalContext.current
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
val colors = WeatherIconDefaults.colors()
|
||||
val selectedColors = WeatherIconDefaults.monochromeColors(MaterialTheme.colorScheme.secondary)
|
||||
|
||||
LazyRow(
|
||||
state = listState,
|
||||
modifier = modifier
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||
contentPadding = PaddingValues(start = 12.dp, end = 12.dp),
|
||||
contentPadding = PaddingValues(start = 8.dp, end = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
itemsIndexed(forecasts, key = { idx, _ -> idx }) { idx, fc ->
|
||||
@@ -482,22 +501,26 @@ fun WeatherTimeSelector(
|
||||
val sm = MaterialTheme.shapes.small
|
||||
val xs = MaterialTheme.shapes.extraSmall
|
||||
Surface(
|
||||
shape = when (idx) {
|
||||
0 -> xs.copy(
|
||||
topStart = sm.topStart,
|
||||
bottomStart = sm.bottomStart
|
||||
)
|
||||
shape = animateShapeAsState(
|
||||
when {
|
||||
selected -> sm
|
||||
idx == 0 -> xs.copy(
|
||||
topStart = sm.topStart,
|
||||
bottomStart = sm.bottomStart
|
||||
)
|
||||
|
||||
forecasts.lastIndex -> xs.copy(
|
||||
topEnd = sm.topEnd,
|
||||
bottomEnd = sm.bottomEnd
|
||||
)
|
||||
idx == forecasts.lastIndex -> xs.copy(
|
||||
topEnd = sm.topEnd,
|
||||
bottomEnd = sm.bottomEnd
|
||||
)
|
||||
|
||||
else -> MaterialTheme.shapes.extraSmall
|
||||
},
|
||||
else -> MaterialTheme.shapes.extraSmall
|
||||
}
|
||||
).value,
|
||||
modifier = Modifier
|
||||
.widthIn(min = 60.dp),
|
||||
color = MaterialTheme.colorScheme.surface,
|
||||
color = if (selected) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.surfaceBright,
|
||||
contentColor = if (selected) MaterialTheme.colorScheme.onSecondary else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -513,12 +536,12 @@ fun WeatherTimeSelector(
|
||||
}
|
||||
.padding(bottom = 4.dp),
|
||||
icon = weatherIconById(fc.icon),
|
||||
night = fc.night
|
||||
night = fc.night,
|
||||
colors = if (selected) selectedColors else colors
|
||||
)
|
||||
Text(
|
||||
text = formatTime(context, fc.timestamp, timeFormat),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
softWrap = false,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||
)
|
||||
@@ -536,13 +559,15 @@ fun WeatherTimeSelector(
|
||||
),
|
||||
softWrap = false,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.alpha(1f - alpha)
|
||||
.requiredSize(8.dp)
|
||||
.background(MaterialTheme.colorScheme.primary, CircleShape)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.onSecondary,
|
||||
CircleShape
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -562,6 +587,9 @@ fun WeatherDaySelector(
|
||||
val dateFormat = SimpleDateFormat("EEE")
|
||||
val context = LocalContext.current
|
||||
|
||||
val colors = WeatherIconDefaults.colors()
|
||||
val selectedColors = WeatherIconDefaults.monochromeColors(MaterialTheme.colorScheme.secondary)
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
LazyRow(
|
||||
state = listState,
|
||||
@@ -569,7 +597,7 @@ fun WeatherDaySelector(
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
contentPadding = PaddingValues(start = 12.dp, end = 12.dp),
|
||||
contentPadding = PaddingValues(start = 8.dp, end = 8.dp),
|
||||
) {
|
||||
itemsIndexed(days, key = { idx, _ -> idx }) { idx, day ->
|
||||
val selected = day == selectedDay
|
||||
@@ -577,20 +605,24 @@ fun WeatherDaySelector(
|
||||
val sm = MaterialTheme.shapes.small
|
||||
val xs = MaterialTheme.shapes.extraSmall
|
||||
Surface(
|
||||
shape = when (idx) {
|
||||
0 -> xs.copy(
|
||||
topStart = sm.topStart,
|
||||
bottomStart = sm.bottomStart
|
||||
)
|
||||
shape = animateShapeAsState(
|
||||
when {
|
||||
selected -> sm
|
||||
idx == 0 -> xs.copy(
|
||||
topStart = sm.topStart,
|
||||
bottomStart = sm.bottomStart
|
||||
)
|
||||
|
||||
days.lastIndex -> xs.copy(
|
||||
topEnd = sm.topEnd,
|
||||
bottomEnd = sm.bottomEnd
|
||||
)
|
||||
idx == days.lastIndex -> xs.copy(
|
||||
topEnd = sm.topEnd,
|
||||
bottomEnd = sm.bottomEnd
|
||||
)
|
||||
|
||||
else -> MaterialTheme.shapes.extraSmall
|
||||
},
|
||||
color = MaterialTheme.colorScheme.surface,
|
||||
else -> MaterialTheme.shapes.extraSmall
|
||||
}
|
||||
).value,
|
||||
color = if (selected) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.surfaceBright,
|
||||
contentColor = if (selected) MaterialTheme.colorScheme.onSecondary else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@@ -598,7 +630,10 @@ fun WeatherDaySelector(
|
||||
.padding(top = 4.dp, bottom = 4.dp, start = 4.dp, end = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
WeatherIcon(icon = weatherIconById(day.icon))
|
||||
WeatherIcon(
|
||||
icon = weatherIconById(day.icon),
|
||||
colors = if (selected) selectedColors else colors
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
text = "${dateFormat.format(day.timestamp)} " +
|
||||
@@ -616,7 +651,6 @@ fun WeatherDaySelector(
|
||||
),
|
||||
softWrap = false,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
val spec = MaterialTheme.motionScheme.fastSpatialSpec<IntSize>()
|
||||
AnimatedVisibility(
|
||||
@@ -628,7 +662,10 @@ fun WeatherDaySelector(
|
||||
modifier = Modifier
|
||||
.padding(start = 8.dp)
|
||||
.size(8.dp)
|
||||
.background(MaterialTheme.colorScheme.primary, CircleShape)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.onSecondary,
|
||||
CircleShape
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -678,26 +715,27 @@ private fun windDirectionAsWord(direction: Double): String {
|
||||
private fun weatherIconById(id: Int): WeatherIcon {
|
||||
return when (id) {
|
||||
Forecast.CLEAR -> WeatherIcon.Clear
|
||||
Forecast.CLOUDY -> WeatherIcon.Cloudy
|
||||
Forecast.COLD -> WeatherIcon.Cold
|
||||
Forecast.DRIZZLE -> WeatherIcon.Drizzle
|
||||
Forecast.OVERCAST -> WeatherIcon.Overcast
|
||||
Forecast.EXTREME_COLD -> WeatherIcon.ExtremeHeat
|
||||
Forecast.LIGHT_RAIN -> WeatherIcon.LightRain
|
||||
Forecast.HAZE -> WeatherIcon.Haze
|
||||
Forecast.FOG -> WeatherIcon.Fog
|
||||
Forecast.HAIL -> WeatherIcon.Hail
|
||||
Forecast.HEAVY_THUNDERSTORM -> WeatherIcon.HeavyThunderstorm
|
||||
Forecast.HEAVY_THUNDERSTORM_WITH_RAIN -> WeatherIcon.HeavyThunderstormWithRain
|
||||
Forecast.HOT -> WeatherIcon.Hot
|
||||
Forecast.MOSTLY_CLOUDY -> WeatherIcon.MostlyCloudy
|
||||
Forecast.EXTREME_HEAT -> WeatherIcon.ExtremeHeat
|
||||
Forecast.PARTLY_CLOUDY -> WeatherIcon.PartlyCloudy
|
||||
Forecast.SHOWERS -> WeatherIcon.Showers
|
||||
Forecast.RAIN -> WeatherIcon.Rain
|
||||
Forecast.HEAVY_RAIN -> WeatherIcon.HeavyRain
|
||||
Forecast.SLEET -> WeatherIcon.Sleet
|
||||
Forecast.SNOW -> WeatherIcon.Snow
|
||||
Forecast.STORM -> WeatherIcon.Storm
|
||||
Forecast.THUNDER -> WeatherIcon.Thunder
|
||||
Forecast.THUNDERSTORM -> WeatherIcon.Thunderstorm
|
||||
Forecast.THUNDERSTORM_WITH_RAIN -> WeatherIcon.ThunderstormWithRain
|
||||
Forecast.WIND -> WeatherIcon.Wind
|
||||
Forecast.BROKEN_CLOUDS -> WeatherIcon.BrokenClouds
|
||||
else -> WeatherIcon.None
|
||||
Forecast.MOSTLY_CLOUDY -> WeatherIcon.PartlyCloudy
|
||||
Forecast.STORM -> WeatherIcon.Wind
|
||||
Forecast.BROKEN_CLOUDS -> WeatherIcon.PartlyCloudy
|
||||
Forecast.HEAVY_THUNDERSTORM -> WeatherIcon.Thunder
|
||||
Forecast.HEAVY_THUNDERSTORM_WITH_RAIN -> WeatherIcon.Thunderstorm
|
||||
else -> WeatherIcon.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,23 +3,42 @@ package de.mm20.launcher2.weather
|
||||
enum class WeatherIcon(val id: Int) {
|
||||
Unknown(-1),
|
||||
Clear(0),
|
||||
Cloudy(1),
|
||||
Cold(2),
|
||||
Drizzle(3),
|
||||
Overcast(1),
|
||||
ExtremeCold(2),
|
||||
Haze(4),
|
||||
Fog(5),
|
||||
Hail(6),
|
||||
HeavyThunderstorm(7),
|
||||
HeavyThunderstormWithRain(8),
|
||||
Hot(9),
|
||||
MostlyCloudy(10),
|
||||
ExtremeHeat(9),
|
||||
PartlyCloudy(11),
|
||||
Showers(12),
|
||||
Sleet(13),
|
||||
Snow(14),
|
||||
Storm(15),
|
||||
Thunderstorm(16),
|
||||
ThunderstormWithRain(17),
|
||||
Thunder(16),
|
||||
Thunderstorm(17),
|
||||
Wind(18),
|
||||
Rain(12),
|
||||
LightRain(3),
|
||||
HeavyRain(20),
|
||||
|
||||
@Deprecated("Deprecated", ReplaceWith("WeatherIcon.PartlyCloudy"))
|
||||
BrokenClouds(19),
|
||||
@Deprecated("Deprecated", ReplaceWith("WeatherIcon.Thunder"))
|
||||
HeavyThunderstorm(7),
|
||||
@Deprecated("Deprecated", ReplaceWith("WeatherIcon.Thunderstorm"))
|
||||
HeavyThunderstormWithRain(8),
|
||||
@Deprecated("Deprecated", ReplaceWith("WeatherIcon.Thunderstorm"))
|
||||
ThunderstormWithRain(17),
|
||||
@Deprecated("Deprecated", ReplaceWith("WeatherIcon.Rain"))
|
||||
Showers(12),
|
||||
@Deprecated("Deprecated", ReplaceWith("WeatherIcon.LightRain"))
|
||||
Drizzle(3),
|
||||
@Deprecated("Deprecated", ReplaceWith("WeatherIcon.PartlyCloudy"))
|
||||
MostlyCloudy(10),
|
||||
@Deprecated("Deprecated", ReplaceWith("WeatherIcon.Overcast"))
|
||||
Cloudy(1),
|
||||
@Deprecated("Deprecated", ReplaceWith("WeatherIcon.ExtremeCold"))
|
||||
Cold(2),
|
||||
@Deprecated("Deprecated", ReplaceWith("WeatherIcon.ExtremeHeat"))
|
||||
Hot(9),
|
||||
@Deprecated("Deprecated", ReplaceWith("WeatherIcon.Wind"))
|
||||
Storm(15),
|
||||
}
|
||||
@@ -1,121 +1,128 @@
|
||||
package de.mm20.launcher2.weather
|
||||
|
||||
import kotlin.math.abs
|
||||
|
||||
data class DailyForecast(
|
||||
val timestamp: Long,
|
||||
val minTemp: Double,
|
||||
val maxTemp: Double,
|
||||
val hourlyForecasts: List<Forecast>,
|
||||
val icon: Int = getAverageIcon(hourlyForecasts)
|
||||
val timestamp: Long,
|
||||
val minTemp: Double,
|
||||
val maxTemp: Double,
|
||||
val hourlyForecasts: List<Forecast>,
|
||||
val icon: Int = getAverageIcon(hourlyForecasts)
|
||||
) {
|
||||
companion object {
|
||||
private fun getAverageIcon(forecasts: List<Forecast>): Int {
|
||||
if (forecasts.size == 1) {
|
||||
return forecasts[0].icon
|
||||
}
|
||||
|
||||
var clear = 0f
|
||||
var clouds = 0f
|
||||
var rain = 0f
|
||||
var thunder = 0f
|
||||
var wind = 0f
|
||||
var snow = 0f
|
||||
for (f in forecasts) {
|
||||
when (f.icon) {
|
||||
Forecast.SHOWERS, Forecast.HAIL -> {
|
||||
rain += 2f
|
||||
clouds += 1f
|
||||
}
|
||||
Forecast.THUNDERSTORM_WITH_RAIN -> {
|
||||
rain += 2f
|
||||
thunder += 5f
|
||||
clouds += 1f
|
||||
}
|
||||
Forecast.THUNDERSTORM -> {
|
||||
thunder += 5f
|
||||
clouds += 1f
|
||||
}
|
||||
Forecast.BROKEN_CLOUDS, Forecast.MOSTLY_CLOUDY -> {
|
||||
clouds += 0.7f
|
||||
clear += 0.3f
|
||||
}
|
||||
var hail = 0f
|
||||
var precipitation = 0f
|
||||
var total = 0f
|
||||
|
||||
for (fc in forecasts) {
|
||||
val f = if (fc.night) 0.8f else 1f
|
||||
when (fc.icon) {
|
||||
Forecast.CLEAR -> clear += f
|
||||
Forecast.OVERCAST -> clouds += f
|
||||
Forecast.PARTLY_CLOUDY -> {
|
||||
clouds += 0.3f
|
||||
clear += 0.7f
|
||||
clouds += f * 0.5f
|
||||
clear += f * 0.5f
|
||||
}
|
||||
Forecast.CLOUDY -> {
|
||||
clouds += 1f
|
||||
|
||||
Forecast.RAIN -> {
|
||||
rain += f
|
||||
clouds += f
|
||||
precipitation += f
|
||||
}
|
||||
|
||||
Forecast.HEAVY_RAIN -> {
|
||||
rain += f * 1.5f
|
||||
clouds += f
|
||||
precipitation += f
|
||||
}
|
||||
|
||||
Forecast.LIGHT_RAIN -> {
|
||||
rain += f * 0.75f
|
||||
clouds += f
|
||||
precipitation += f
|
||||
}
|
||||
|
||||
Forecast.SNOW -> {
|
||||
snow += 2f
|
||||
clouds += 1f
|
||||
}
|
||||
Forecast.DRIZZLE -> {
|
||||
rain += 1f
|
||||
}
|
||||
Forecast.HEAVY_THUNDERSTORM -> {
|
||||
thunder += 8f
|
||||
}
|
||||
Forecast.HEAVY_THUNDERSTORM_WITH_RAIN -> {
|
||||
thunder += 8f
|
||||
clouds += 1f
|
||||
snow += f
|
||||
clouds += f
|
||||
precipitation += f
|
||||
}
|
||||
|
||||
Forecast.SLEET -> {
|
||||
rain += 1f
|
||||
snow += 1f
|
||||
snow += f * 0.5f
|
||||
rain += f * 0.5f
|
||||
clouds += f
|
||||
precipitation += f
|
||||
}
|
||||
Forecast.STORM -> {
|
||||
wind += 8f
|
||||
|
||||
Forecast.HAIL -> {
|
||||
hail += f
|
||||
clouds += f
|
||||
precipitation += f
|
||||
}
|
||||
|
||||
Forecast.THUNDER -> {
|
||||
thunder += f
|
||||
clouds += f
|
||||
}
|
||||
|
||||
Forecast.THUNDERSTORM -> {
|
||||
thunder += f
|
||||
rain += f * 1.5f
|
||||
clouds += f
|
||||
precipitation += f
|
||||
}
|
||||
|
||||
Forecast.WIND -> {
|
||||
wind += 5f
|
||||
}
|
||||
Forecast.CLEAR -> {
|
||||
clear += 1f
|
||||
wind += f
|
||||
clouds += f
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
total += f
|
||||
}
|
||||
|
||||
if (wind / total >= 0.05f) {
|
||||
return Forecast.WIND
|
||||
}
|
||||
|
||||
|
||||
if (precipitation / total >= 0.3f) {
|
||||
return when {
|
||||
hail > snow && hail > rain -> Forecast.HAIL
|
||||
snow > rain && snow / rain > 2f -> Forecast.SNOW
|
||||
snow / rain <= 2f && rain / snow <= 2f -> Forecast.SLEET
|
||||
thunder > 0f -> Forecast.THUNDERSTORM
|
||||
(rain + snow + hail) / precipitation >= 1.25f -> Forecast.HEAVY_RAIN
|
||||
(rain + snow + hail) / precipitation <= 0.8725f -> Forecast.LIGHT_RAIN
|
||||
else -> Forecast.RAIN
|
||||
}
|
||||
}
|
||||
val pairs = listOf(
|
||||
"clear" to clear,
|
||||
"clouds" to clouds,
|
||||
"rain" to rain,
|
||||
"thunder" to thunder,
|
||||
"wind" to wind,
|
||||
"snow" to snow
|
||||
).sortedByDescending { it.second }
|
||||
val first = pairs[0]
|
||||
val second = pairs[1]
|
||||
when (first.first) {
|
||||
"wind" -> return if (first.second / forecasts.size > 6f) Forecast.STORM else Forecast.WIND
|
||||
"thunder" -> {
|
||||
val heavy = first.second / forecasts.size > 6f
|
||||
val withRain = second.first == "rain"
|
||||
if (heavy && withRain) return Forecast.HEAVY_THUNDERSTORM_WITH_RAIN
|
||||
if (heavy && !withRain) return Forecast.HEAVY_THUNDERSTORM
|
||||
if (!heavy && withRain) return Forecast.THUNDERSTORM_WITH_RAIN
|
||||
return Forecast.THUNDERSTORM
|
||||
}
|
||||
"rain" -> {
|
||||
val heavy = first.second / forecasts.size > 0.8f
|
||||
val withSnow = second.first == "snow" && abs(1 - (first.second / second.second)) < 0.2
|
||||
if (withSnow) return Forecast.SLEET
|
||||
if (heavy) return Forecast.SHOWERS
|
||||
return Forecast.DRIZZLE
|
||||
}
|
||||
"snow" -> {
|
||||
val withRain = second.first == "rain" && abs(1 - (first.second / second.second)) < 0.2
|
||||
if (withRain) return Forecast.SLEET
|
||||
return Forecast.SNOW
|
||||
}
|
||||
else -> {
|
||||
if (clouds == 0f) return Forecast.CLEAR
|
||||
if (clear == 0f) return Forecast.CLOUDY
|
||||
if (clouds > clear) {
|
||||
if (clear > snow && clear > rain) return Forecast.MOSTLY_CLOUDY
|
||||
if (clear < snow && clear < rain) return Forecast.SLEET
|
||||
if (clear < snow && clear > rain) return Forecast.SNOW
|
||||
if (clear > snow && clear < rain) return Forecast.DRIZZLE
|
||||
}
|
||||
return Forecast.PARTLY_CLOUDY
|
||||
}
|
||||
|
||||
if (thunder / total >= 0.05f) {
|
||||
return Forecast.THUNDER
|
||||
}
|
||||
|
||||
if (clear / clouds < 0.2f) {
|
||||
return Forecast.OVERCAST
|
||||
}
|
||||
|
||||
if (clouds / clear < 0.1f) {
|
||||
return Forecast.CLEAR
|
||||
}
|
||||
|
||||
return Forecast.PARTLY_CLOUDY
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,135 +1,143 @@
|
||||
package de.mm20.launcher2.weather
|
||||
|
||||
import de.mm20.launcher2.database.entities.ForecastEntity
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.BROKEN_CLOUDS
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.CLEAR
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.CLOUDY
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.COLD
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.DRIZZLE
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.EXTREME_COLD
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.EXTREME_HEAT
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.FOG
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.HAIL
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.HAZE
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.HEAVY_THUNDERSTORM
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.HEAVY_THUNDERSTORM_WITH_RAIN
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.HOT
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.MOSTLY_CLOUDY
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.NONE
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.HEAVY_RAIN
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.LIGHT_RAIN
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.OVERCAST
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.PARTLY_CLOUDY
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.SHOWERS
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.RAIN
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.SLEET
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.SNOW
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.STORM
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.THUNDER
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.THUNDERSTORM
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.THUNDERSTORM_WITH_RAIN
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.UNKNOWN
|
||||
import de.mm20.launcher2.weather.Forecast.Companion.WIND
|
||||
|
||||
data class Forecast(
|
||||
val timestamp: Long,
|
||||
/** The temperature, in Kelvin **/
|
||||
val temperature: Double,
|
||||
/** The min temperature, in Kelvin **/
|
||||
val minTemp: Double? = null,
|
||||
/** The max temperature, in Kelvin **/
|
||||
val maxTemp: Double? = null,
|
||||
/** The temperature, in hPa **/
|
||||
val pressure: Double? = null,
|
||||
/** The temperature, in percent **/
|
||||
val humidity: Double? = null,
|
||||
/** The icon, one of [NONE], [CLEAR], [CLOUDY], [COLD], [DRIZZLE], [HAZE], [FOG],
|
||||
* [HAIL], [HEAVY_THUNDERSTORM], [HEAVY_THUNDERSTORM_WITH_RAIN], [HOT], [MOSTLY_CLOUDY],
|
||||
* [PARTLY_CLOUDY], [SHOWERS], [SLEET], [SNOW], [STORM], [THUNDERSTORM],
|
||||
* [THUNDERSTORM_WITH_RAIN], [WIND], [BROKEN_CLOUDS]**/
|
||||
val icon: Int,
|
||||
/** A text describing the current weather condition **/
|
||||
val condition: String,
|
||||
/** The clouds, percentage **/
|
||||
val clouds: Int? = null,
|
||||
/** Wind speed, in m/s **/
|
||||
val windSpeed: Double? = null,
|
||||
/** wind direction, in degrees **/
|
||||
val windDirection: Double? = null,
|
||||
/** rain, in mm per hour **/
|
||||
val precipitation: Double? = null,
|
||||
/** whether this forecast is during night time (whether a moon icon should be used instead of sun) **/
|
||||
val night: Boolean = false,
|
||||
/** Location string **/
|
||||
val location: String,
|
||||
/** Provider name **/
|
||||
val provider: String,
|
||||
/** Url to the provider and more weather information **/
|
||||
val providerUrl: String = "",
|
||||
/** Rain probability, in percent [0..100]. null if not available **/
|
||||
val precipProbability: Int? = null,
|
||||
/** Timestamp (in millis) when when this forecast was created **/
|
||||
val updateTime: Long
|
||||
val timestamp: Long,
|
||||
/** The temperature, in Kelvin **/
|
||||
val temperature: Double,
|
||||
/** The min temperature, in Kelvin **/
|
||||
val minTemp: Double? = null,
|
||||
/** The max temperature, in Kelvin **/
|
||||
val maxTemp: Double? = null,
|
||||
/** The temperature, in hPa **/
|
||||
val pressure: Double? = null,
|
||||
/** The temperature, in percent **/
|
||||
val humidity: Double? = null,
|
||||
/** The icon, one of [UNKNOWN], [CLEAR], [OVERCAST], [EXTREME_COLD], [LIGHT_RAIN], [HAZE],
|
||||
* [FOG], [HAIL], [EXTREME_HEAT], [PARTLY_CLOUDY], [RAIN], [HEAVY_RAIN] [SLEET], [SNOW],
|
||||
* [THUNDER], [THUNDERSTORM], [WIND]**/
|
||||
val icon: Int,
|
||||
/** A text describing the current weather condition **/
|
||||
val condition: String,
|
||||
/** The clouds, percentage **/
|
||||
val clouds: Int? = null,
|
||||
/** Wind speed, in m/s **/
|
||||
val windSpeed: Double? = null,
|
||||
/** wind direction, in degrees **/
|
||||
val windDirection: Double? = null,
|
||||
/** rain, in mm per hour **/
|
||||
val precipitation: Double? = null,
|
||||
/** whether this forecast is during nighttime (whether a moon icon should be used instead of sun) **/
|
||||
val night: Boolean = false,
|
||||
/** Location string **/
|
||||
val location: String,
|
||||
/** Provider name **/
|
||||
val provider: String,
|
||||
/** Url to the provider and more weather information **/
|
||||
val providerUrl: String = "",
|
||||
/** Rain probability, in percent [0..100]. null if not available **/
|
||||
val precipProbability: Int? = null,
|
||||
/** Timestamp (in millis) when this forecast was created **/
|
||||
val updateTime: Long
|
||||
) {
|
||||
fun toDatabaseEntity(): ForecastEntity {
|
||||
return ForecastEntity(
|
||||
timestamp = timestamp,
|
||||
clouds = clouds ?: -1,
|
||||
condition = condition,
|
||||
humidity = humidity ?: -1.0,
|
||||
icon = icon,
|
||||
location = location,
|
||||
maxTemp = maxTemp ?: -1.0,
|
||||
minTemp = minTemp ?: -1.0,
|
||||
night = night,
|
||||
pressure = pressure ?: -1.0,
|
||||
provider = provider,
|
||||
providerUrl = providerUrl,
|
||||
precipitation = precipitation ?: -1.0,
|
||||
precipProbability = precipProbability ?: -1,
|
||||
temperature = temperature,
|
||||
updateTime = updateTime,
|
||||
windDirection = windDirection ?: -1.0,
|
||||
windSpeed = windSpeed ?: -1.0,
|
||||
snow = -1.0,
|
||||
snowProbability = -1
|
||||
timestamp = timestamp,
|
||||
clouds = clouds ?: -1,
|
||||
condition = condition,
|
||||
humidity = humidity ?: -1.0,
|
||||
icon = icon,
|
||||
location = location,
|
||||
maxTemp = maxTemp ?: -1.0,
|
||||
minTemp = minTemp ?: -1.0,
|
||||
night = night,
|
||||
pressure = pressure ?: -1.0,
|
||||
provider = provider,
|
||||
providerUrl = providerUrl,
|
||||
precipitation = precipitation ?: -1.0,
|
||||
precipProbability = precipProbability ?: -1,
|
||||
temperature = temperature,
|
||||
updateTime = updateTime,
|
||||
windDirection = windDirection ?: -1.0,
|
||||
windSpeed = windSpeed ?: -1.0,
|
||||
snow = -1.0,
|
||||
snowProbability = -1
|
||||
)
|
||||
}
|
||||
|
||||
constructor(entity: ForecastEntity) : this(
|
||||
timestamp = entity.timestamp,
|
||||
clouds = entity.clouds.takeIf { it >= 0 },
|
||||
condition = entity.condition,
|
||||
humidity = entity.humidity.takeIf { it >= 0.0 },
|
||||
icon = entity.icon,
|
||||
location = entity.location,
|
||||
maxTemp = entity.maxTemp.takeIf { it >= 0.0 },
|
||||
minTemp = entity.minTemp.takeIf { it >= 0.0 },
|
||||
night = entity.night,
|
||||
pressure = entity.pressure.takeIf { it >= 0.0 },
|
||||
provider = entity.provider,
|
||||
providerUrl = entity.providerUrl,
|
||||
precipitation = entity.precipitation.takeIf { it >= 0.0 },
|
||||
precipProbability = entity.precipProbability.takeIf { it >= 0 },
|
||||
temperature = entity.temperature,
|
||||
updateTime = entity.updateTime,
|
||||
windDirection = entity.windDirection.takeIf { it >= 0.0 },
|
||||
windSpeed = entity.windSpeed.takeIf { it >= 0.0 },
|
||||
timestamp = entity.timestamp,
|
||||
clouds = entity.clouds.takeIf { it >= 0 },
|
||||
condition = entity.condition,
|
||||
humidity = entity.humidity.takeIf { it >= 0.0 },
|
||||
icon = entity.icon,
|
||||
location = entity.location,
|
||||
maxTemp = entity.maxTemp.takeIf { it >= 0.0 },
|
||||
minTemp = entity.minTemp.takeIf { it >= 0.0 },
|
||||
night = entity.night,
|
||||
pressure = entity.pressure.takeIf { it >= 0.0 },
|
||||
provider = entity.provider,
|
||||
providerUrl = entity.providerUrl,
|
||||
precipitation = entity.precipitation.takeIf { it >= 0.0 },
|
||||
precipProbability = entity.precipProbability.takeIf { it >= 0 },
|
||||
temperature = entity.temperature,
|
||||
updateTime = entity.updateTime,
|
||||
windDirection = entity.windDirection.takeIf { it >= 0.0 },
|
||||
windSpeed = entity.windSpeed.takeIf { it >= 0.0 },
|
||||
)
|
||||
|
||||
companion object {
|
||||
const val NONE = -1
|
||||
const val UNKNOWN = -1
|
||||
const val CLEAR = 0
|
||||
const val CLOUDY = 1
|
||||
const val COLD = 2
|
||||
const val DRIZZLE = 3
|
||||
const val OVERCAST = 1
|
||||
const val EXTREME_COLD = 2
|
||||
const val LIGHT_RAIN = 3
|
||||
const val HAZE = 4
|
||||
const val FOG = 5
|
||||
const val HAIL = 6
|
||||
const val HEAVY_THUNDERSTORM = 7
|
||||
const val HEAVY_THUNDERSTORM_WITH_RAIN = 8
|
||||
const val HOT = 9
|
||||
const val MOSTLY_CLOUDY = 10
|
||||
const val EXTREME_HEAT = 9
|
||||
|
||||
const val PARTLY_CLOUDY = 11
|
||||
const val SHOWERS = 12
|
||||
const val RAIN = 12
|
||||
const val SLEET = 13
|
||||
const val SNOW = 14
|
||||
const val STORM = 15
|
||||
const val THUNDERSTORM = 16
|
||||
const val THUNDERSTORM_WITH_RAIN = 17
|
||||
const val THUNDER = 16
|
||||
const val THUNDERSTORM = 17
|
||||
const val WIND = 18
|
||||
const val HEAVY_RAIN = 20
|
||||
|
||||
@Deprecated("Deprecated", ReplaceWith("THUNDER"))
|
||||
const val HEAVY_THUNDERSTORM = 7
|
||||
|
||||
@Deprecated("Deprecated", ReplaceWith("THUNDERSTORM"))
|
||||
const val HEAVY_THUNDERSTORM_WITH_RAIN = 8
|
||||
|
||||
@Deprecated("Deprecated", ReplaceWith("PARTLY_CLOUDY"))
|
||||
const val MOSTLY_CLOUDY = 10
|
||||
|
||||
@Deprecated("Deprecated", ReplaceWith("WIND"))
|
||||
const val STORM = 15
|
||||
|
||||
@Deprecated("Deprecated", ReplaceWith("PARTLY_CLOUDY"))
|
||||
const val BROKEN_CLOUDS = 19
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package de.mm20.launcher2.weather
|
||||
|
||||
data class Weather2(
|
||||
val timestamp: Long,
|
||||
val temperature: Double,
|
||||
val minTemp: Double,
|
||||
val maxTemp: Double,
|
||||
val pressure: Double,
|
||||
val humidity: Double,
|
||||
val icon: Int,
|
||||
val condition: String,
|
||||
val clouds: String,
|
||||
val windSpeed: Double,
|
||||
val windDirection: Double,
|
||||
val rain: Double,
|
||||
val snow: Double,
|
||||
val night: Boolean,
|
||||
val location: String,
|
||||
val provider: String,
|
||||
val providerUrl: String
|
||||
) {
|
||||
|
||||
companion object {
|
||||
const val NONE = -1
|
||||
const val CLEAR = 0
|
||||
const val CLOUDY = 1
|
||||
const val COLD = 2
|
||||
const val DRIZZLE = 3
|
||||
const val HAZE = 4
|
||||
const val FOG = 5
|
||||
const val HAIL = 6
|
||||
const val HEAVY_THUNDERSTORM = 7
|
||||
const val HEAVY_THUNDERSTORM_WITH_RAIN = 8
|
||||
const val HOT = 9
|
||||
const val MOSTLY_CLOUDY = 10
|
||||
const val PARTLY_CLOUDY = 11
|
||||
const val SHOWERS = 12
|
||||
const val SLEET = 13
|
||||
const val SNOW = 14
|
||||
const val STORM = 15
|
||||
const val THUNDERSTORM = 16
|
||||
const val THUNDERSTORM_WITH_RAIN = 17
|
||||
const val WIND = 18
|
||||
const val BROKEN_CLOUDS = 19
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,8 +102,8 @@ class BreezyWeatherProvider(
|
||||
return when (id) {
|
||||
800 -> WeatherIcon.Clear
|
||||
801 -> WeatherIcon.PartlyCloudy
|
||||
803 -> WeatherIcon.Cloudy
|
||||
500 -> WeatherIcon.Showers
|
||||
803 -> WeatherIcon.Overcast
|
||||
500 -> WeatherIcon.Rain
|
||||
600 -> WeatherIcon.Snow
|
||||
771 -> WeatherIcon.Wind
|
||||
741 -> WeatherIcon.Fog
|
||||
@@ -111,7 +111,7 @@ class BreezyWeatherProvider(
|
||||
611 -> WeatherIcon.Sleet
|
||||
511 -> WeatherIcon.Hail
|
||||
210 -> WeatherIcon.Thunderstorm
|
||||
211 -> WeatherIcon.ThunderstormWithRain
|
||||
211 -> WeatherIcon.Thunderstorm
|
||||
else -> WeatherIcon.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,10 +87,10 @@ internal class BrightSkyProvider(
|
||||
return when (icon) {
|
||||
"clear-day", "clear-night" -> Forecast.CLEAR
|
||||
"partly-cloudy-day", "partly-cloudy-night" -> Forecast.PARTLY_CLOUDY
|
||||
"cloudy" -> Forecast.CLOUDY
|
||||
"cloudy" -> Forecast.OVERCAST
|
||||
"fog" -> Forecast.FOG
|
||||
"wind" -> Forecast.WIND
|
||||
"rain" -> Forecast.SHOWERS
|
||||
"rain" -> Forecast.RAIN
|
||||
"sleet" -> Forecast.SLEET
|
||||
"snow" -> Forecast.SNOW
|
||||
"hail" -> Forecast.HAIL
|
||||
|
||||
@@ -232,32 +232,35 @@ internal class MetNoProvider(
|
||||
|
||||
private fun iconForCode(code: String): Int {
|
||||
return when (code.substringBefore("_")) {
|
||||
"clearsky" -> Forecast.CLEAR
|
||||
"fair" -> Forecast.PARTLY_CLOUDY
|
||||
"partlycloudy" -> Forecast.MOSTLY_CLOUDY
|
||||
"cloudy" -> Forecast.CLOUDY
|
||||
"rainshowers", "rain", "lightrainshowers", "lightrain" -> Forecast.DRIZZLE
|
||||
"rainshowersandthunder", "snowandthunder", "snowshowersandthunder",
|
||||
"lightssnowshowersandthunder", "lightsleetandthunder",
|
||||
"lightsnowandthunder" -> Forecast.THUNDERSTORM
|
||||
|
||||
"sleetshowers", "sleet", "lightsleetshowers", "heavysleetshowers", "lightsleet",
|
||||
"heavysleet" -> Forecast.SLEET
|
||||
|
||||
"snowshowers", "snow", "lightsnowshowers", "heavysnowshowers", "lightsnow",
|
||||
"heavysnow" -> Forecast.SNOW
|
||||
|
||||
"heavyrain", "heavyrainshowers" -> Forecast.SHOWERS
|
||||
"heavyrainandthunder", "sleetshowersandthunder", "rainandthunder", "sleetandthunder",
|
||||
"lightrainshowersandthunder", "heavyrainshowersandthunder",
|
||||
"lightssleetshowersandthunder", "lightrainandthunder" -> Forecast.THUNDERSTORM_WITH_RAIN
|
||||
|
||||
"clearsky", "fair" -> Forecast.CLEAR
|
||||
"partlycloudy" -> Forecast.PARTLY_CLOUDY
|
||||
"cloudy" -> Forecast.OVERCAST
|
||||
"fog" -> Forecast.FOG
|
||||
"heavysleetshowersandthunder",
|
||||
"heavysleetandthunder" -> Forecast.HEAVY_THUNDERSTORM_WITH_RAIN
|
||||
|
||||
"heavysnowshowersandthunder", "heavysnowandthunder" -> Forecast.HEAVY_THUNDERSTORM
|
||||
else -> Forecast.NONE
|
||||
"lightrain", "lightrainshowers" -> Forecast.LIGHT_RAIN
|
||||
"heavyrain", "heavyrainshowers" -> Forecast.HEAVY_RAIN
|
||||
"rain" -> Forecast.RAIN
|
||||
|
||||
"lightsleet", "lightsleetshowers", "heavysleet", "heavysleetshowers", "sleet" -> Forecast.SLEET
|
||||
|
||||
"snow", "lightsnow", "lightsnowshowers", "heavysnow", "heavysnowshowers" -> Forecast.SNOW
|
||||
|
||||
"rainandthunder",
|
||||
"heavyrainandthunder",
|
||||
"heavyrainshowersandthunder",
|
||||
"lightrainshowersandthunder",
|
||||
"lightrainandthunder",
|
||||
"rainshowersandthunder",
|
||||
"lightssnowshowersandthunder",
|
||||
"lightsnowshowersandthunder",
|
||||
"snowshowersandthunder",
|
||||
"heavysnowandthunder",
|
||||
"heavysnowshowersandthunder",
|
||||
"heavysleetandthunder",
|
||||
"lightssleetshowersandthunder",
|
||||
"sleetshowersandthunder" -> Forecast.THUNDERSTORM
|
||||
|
||||
else -> Forecast.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,27 +162,20 @@ internal class OpenWeatherMapProvider(
|
||||
|
||||
private fun iconForId(id: Int): Int {
|
||||
return when (id) {
|
||||
200, 201, in 230..232 -> Forecast.THUNDERSTORM_WITH_RAIN
|
||||
202 -> Forecast.HEAVY_THUNDERSTORM_WITH_RAIN
|
||||
210, 211 -> Forecast.THUNDERSTORM
|
||||
212, 221 -> Forecast.HEAVY_THUNDERSTORM
|
||||
in 300..302, in 310..312 -> Forecast.DRIZZLE
|
||||
313, 314, 321, in 500..504, 511, in 520..522, 531 -> Forecast.SHOWERS
|
||||
200, 201, 202, in 230..232 -> Forecast.THUNDERSTORM
|
||||
210, 211, 212, 221 -> Forecast.THUNDER
|
||||
in 300..302, in 310..312, 500, 520 -> Forecast.LIGHT_RAIN
|
||||
313, 314, 321, 501, 511, 521, 531 -> Forecast.RAIN
|
||||
502, 503, 504, 522 -> Forecast.HEAVY_RAIN
|
||||
in 600..602 -> Forecast.SNOW
|
||||
611, 612, 615, 616, in 620..622 -> Forecast.SLEET
|
||||
701, 711, 731, 741, 761, 762 -> Forecast.FOG
|
||||
721 -> Forecast.HAZE
|
||||
771, 781, in 900..902, in 958..962 -> Forecast.STORM
|
||||
701, 711, 741 -> Forecast.FOG
|
||||
721, 731, 751, 761, 762 -> Forecast.HAZE
|
||||
771, 781 -> Forecast.WIND
|
||||
800 -> Forecast.CLEAR
|
||||
801 -> Forecast.PARTLY_CLOUDY
|
||||
802 -> Forecast.BROKEN_CLOUDS
|
||||
803 -> Forecast.MOSTLY_CLOUDY
|
||||
804, 951 -> Forecast.CLOUDY
|
||||
903 -> Forecast.COLD
|
||||
904 -> Forecast.HOT
|
||||
905, in 952..957 -> Forecast.WIND
|
||||
906 -> Forecast.HAIL
|
||||
else -> Forecast.NONE
|
||||
801, 802, 803 -> Forecast.PARTLY_CLOUDY
|
||||
804-> Forecast.OVERCAST
|
||||
else -> Forecast.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,9 @@ import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.os.CancellationSignal
|
||||
import android.util.Log
|
||||
import androidx.core.database.getDoubleOrNull
|
||||
import androidx.core.database.getIntOrNull
|
||||
import androidx.core.database.getLongOrNull
|
||||
import androidx.core.database.getStringOrNull
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import de.mm20.launcher2.plugin.PluginApi
|
||||
import de.mm20.launcher2.plugin.config.WeatherPluginConfig
|
||||
import de.mm20.launcher2.plugin.contracts.PluginContract
|
||||
import de.mm20.launcher2.plugin.contracts.WeatherPluginContract
|
||||
import de.mm20.launcher2.plugin.contracts.WeatherPluginContract.ForecastColumns
|
||||
import de.mm20.launcher2.plugin.contracts.WeatherPluginContract.LocationColumns
|
||||
@@ -142,26 +137,35 @@ internal class PluginWeatherProvider(
|
||||
private fun getIcon(icon: String): Int {
|
||||
return when (icon) {
|
||||
"Clear" -> Forecast.CLEAR
|
||||
"Cloudy" -> Forecast.CLOUDY
|
||||
"Cold" -> Forecast.COLD
|
||||
"Drizzle" -> Forecast.DRIZZLE
|
||||
"Haze" -> Forecast.HAZE
|
||||
"Fog" -> Forecast.FOG
|
||||
"Hail" -> Forecast.HAIL
|
||||
"HeavyThunderstorm" -> Forecast.HEAVY_THUNDERSTORM
|
||||
"HeavyThunderstormWithRain" -> Forecast.HEAVY_THUNDERSTORM_WITH_RAIN
|
||||
"Hot" -> Forecast.HOT
|
||||
"MostlyCloudy" -> Forecast.MOSTLY_CLOUDY
|
||||
"PartlyCloudy" -> Forecast.PARTLY_CLOUDY
|
||||
"Showers" -> Forecast.SHOWERS
|
||||
"Overcast" -> Forecast.OVERCAST
|
||||
"Rain" -> Forecast.RAIN
|
||||
"LightRain" -> Forecast.LIGHT_RAIN
|
||||
"HeavyRain" -> Forecast.HEAVY_RAIN
|
||||
"Sleet" -> Forecast.SLEET
|
||||
"Snow" -> Forecast.SNOW
|
||||
"Storm" -> Forecast.STORM
|
||||
"Hail" -> Forecast.HAIL
|
||||
"Thunder" -> Forecast.THUNDER
|
||||
"Thunderstorm" -> Forecast.THUNDERSTORM
|
||||
"ThunderstormWithRain" -> Forecast.THUNDERSTORM_WITH_RAIN
|
||||
"Wind" -> Forecast.WIND
|
||||
"BrokenClouds" -> Forecast.BROKEN_CLOUDS
|
||||
else -> Forecast.NONE
|
||||
"ExtremeHeat" -> Forecast.EXTREME_HEAT
|
||||
"ExtremeCold" -> Forecast.EXTREME_COLD
|
||||
|
||||
// Deprecated values
|
||||
"Cloudy" -> Forecast.OVERCAST
|
||||
"Storm" -> Forecast.WIND
|
||||
"HeavyThunderstorm" -> Forecast.THUNDER
|
||||
"HeavyThunderstormWithRain" -> Forecast.THUNDERSTORM
|
||||
"ThunderstormWithRain" -> Forecast.THUNDERSTORM
|
||||
"MostlyCloudy" -> Forecast.PARTLY_CLOUDY
|
||||
"BrokenClouds" -> Forecast.PARTLY_CLOUDY
|
||||
"Hot" -> Forecast.EXTREME_HEAT
|
||||
"Cold" -> Forecast.EXTREME_COLD
|
||||
"Showers" -> Forecast.RAIN
|
||||
"Drizzle" -> Forecast.LIGHT_RAIN
|
||||
else -> Forecast.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user