mirror of
https://github.com/PranshulGG/WeatherMaster.git
synced 2026-10-22 11:02:53 -05:00
add new hourly widget
This commit is contained in:
1 parent
1e150e287b
commit
343c3d4bc2
10 files changed
+221
-9
No files matched your search
+5
-1
@@ -74,10 +74,14 @@ fun widgetWeatherMapper(
|
||||
)
|
||||
|
||||
val icon = it.weatherCondition.toIcon(matchingDaily, it.time)
|
||||
|
||||
val precipitationProbability = it.precipitationProbability
|
||||
|
||||
WidgetHourlyItem(
|
||||
time = formattedTime,
|
||||
temp = "${temperature}°",
|
||||
conditionIcon = icon
|
||||
conditionIcon = icon,
|
||||
precipitationProbability = precipitationProbability
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -10,6 +10,7 @@ import androidx.glance.appwidget.updateAll
|
||||
import com.pranshulgg.weather_master_app.widgets.WeatherWidgetStateDefinition
|
||||
import com.pranshulgg.weather_master_app.widgets.config.WidgetConfig
|
||||
import com.pranshulgg.weather_master_app.widgets.glance.GlanceWidget
|
||||
import com.pranshulgg.weather_master_app.widgets.hourly.WidgetHourly
|
||||
import com.pranshulgg.weather_master_app.widgets.pill.WidgetPill
|
||||
import com.pranshulgg.weather_master_app.widgets.summary.SummaryWidget
|
||||
import com.pranshulgg.weather_master_app.widgets.weather.WeatherWidget
|
||||
@@ -31,6 +32,8 @@ class WeatherWidgetUpdater(
|
||||
|
||||
private val widgetWeather4 = Weather4Widget()
|
||||
|
||||
private val widgetHourly = WidgetHourly()
|
||||
|
||||
suspend fun update(json: String) {
|
||||
val manager = GlanceAppWidgetManager(context)
|
||||
suspend fun <T : GlanceAppWidget> updateWidgets(
|
||||
@@ -54,6 +57,7 @@ class WeatherWidgetUpdater(
|
||||
updateWidgets(widgetGlance, manager.getGlanceIds(GlanceWidget::class.java))
|
||||
updateWidgets(widgetClockDaily, manager.getGlanceIds(ClockDailyWidget::class.java))
|
||||
updateWidgets(widgetWeather4, manager.getGlanceIds(Weather4Widget::class.java))
|
||||
updateWidgets(widgetHourly, manager.getGlanceIds(WidgetHourly::class.java))
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ data class WidgetConfig(
|
||||
val dailyCount: Int = 4,
|
||||
val showDailyInsteadOfCurrent: Boolean = false,
|
||||
val isWeatherBackground: Boolean = false,
|
||||
val isDisplayHourly: Boolean = false
|
||||
val isDisplayHourly: Boolean = false,
|
||||
val showPrecipitationProbability: Boolean = false,
|
||||
|
||||
)
|
||||
)
|
||||
+6
@@ -20,6 +20,8 @@ import com.pranshulgg.weather_master_app.core.ui.theme.isThemeDark
|
||||
import com.pranshulgg.weather_master_app.data.worker.widgets.WeatherWidgetUpdater
|
||||
import com.pranshulgg.weather_master_app.widgets.glance.GlanceWidgetReceiver
|
||||
import com.pranshulgg.weather_master_app.widgets.glance.ui.GlanceWidgetConfig
|
||||
import com.pranshulgg.weather_master_app.widgets.hourly.WidgetHourlyReceiver
|
||||
import com.pranshulgg.weather_master_app.widgets.hourly.ui.HourlyWidgetConfig
|
||||
import com.pranshulgg.weather_master_app.widgets.weather.WeatherWidgetReceiver
|
||||
import com.pranshulgg.weather_master_app.widgets.weather.ui.WeatherWidgetConfig
|
||||
import com.pranshulgg.weather_master_app.widgets.weather4.Weather4WidgerReceiver
|
||||
@@ -126,6 +128,10 @@ class WidgetConfigActivity : ComponentActivity() {
|
||||
Weather4WidgerReceiver::class.java.name -> {
|
||||
Weather4Config { onDone(it) }
|
||||
}
|
||||
|
||||
WidgetHourlyReceiver::class.java.name -> {
|
||||
HourlyWidgetConfig { onDone(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
package com.pranshulgg.weather_master_app.widgets.hourly
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.glance.ColorFilter
|
||||
import androidx.glance.GlanceId
|
||||
import androidx.glance.GlanceModifier
|
||||
import androidx.glance.GlanceTheme
|
||||
import androidx.glance.ImageProvider
|
||||
import androidx.glance.action.actionStartActivity
|
||||
import androidx.glance.action.clickable
|
||||
import androidx.glance.appwidget.GlanceAppWidget
|
||||
import androidx.glance.appwidget.SizeMode
|
||||
import androidx.glance.appwidget.cornerRadius
|
||||
import androidx.glance.appwidget.provideContent
|
||||
import androidx.glance.background
|
||||
import androidx.glance.currentState
|
||||
import androidx.glance.layout.Alignment
|
||||
import androidx.glance.layout.Box
|
||||
import androidx.glance.layout.Row
|
||||
import androidx.glance.layout.fillMaxHeight
|
||||
import androidx.glance.layout.fillMaxSize
|
||||
import androidx.glance.layout.fillMaxWidth
|
||||
import com.pranshulgg.weather_master_app.MainActivity
|
||||
import com.pranshulgg.weather_master_app.R
|
||||
import com.pranshulgg.weather_master_app.widgets.WeatherWidgetStateDefinition
|
||||
import com.pranshulgg.weather_master_app.widgets.WeatherWidgetStateJson
|
||||
import com.pranshulgg.weather_master_app.widgets.model.WidgetWeather
|
||||
import com.pranshulgg.weather_master_app.widgets.ui.ReloadButton
|
||||
import com.pranshulgg.weather_master_app.widgets.ui.colors.WidgetColors
|
||||
import com.pranshulgg.weather_master_app.widgets.ui.colors.WidgetTheme
|
||||
import com.pranshulgg.weather_master_app.widgets.weather.components.WidgetHourlyItem
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
|
||||
class WidgetHourly : GlanceAppWidget() {
|
||||
|
||||
override val sizeMode = SizeMode.Exact
|
||||
override val stateDefinition =
|
||||
WeatherWidgetStateDefinition
|
||||
|
||||
override suspend fun provideGlance(
|
||||
context: Context,
|
||||
id: GlanceId
|
||||
) {
|
||||
|
||||
|
||||
provideContent {
|
||||
val widgetState =
|
||||
currentState<WeatherWidgetStateJson>()
|
||||
val widgetColors = WidgetColors()
|
||||
|
||||
val json = widgetState.json
|
||||
val state = json?.let {
|
||||
Json.decodeFromString<WidgetWeather>(it)
|
||||
}
|
||||
val config = widgetState.config
|
||||
|
||||
if (state != null) {
|
||||
val modifier = when (config.widgetTheme) {
|
||||
WidgetTheme.TRANSPARENT -> GlanceModifier.fillMaxSize()
|
||||
else -> GlanceModifier.fillMaxSize()
|
||||
.appWidgetBackgroundShape(
|
||||
config.widgetTheme,
|
||||
widgetColors
|
||||
)
|
||||
}
|
||||
|
||||
val textColor = widgetColors
|
||||
.getTextColor(config.widgetTextTheme, config.widgetTheme)
|
||||
?: Pair(GlanceTheme.colors.onSurface, null)
|
||||
|
||||
val textColorVariant = widgetColors
|
||||
.getTextVariantColor(config.widgetTextTheme, config.widgetTheme)
|
||||
?: GlanceTheme.colors.onSurfaceVariant
|
||||
Box(
|
||||
modifier.clickable(actionStartActivity<MainActivity>())
|
||||
) {
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = GlanceModifier.fillMaxWidth().fillMaxHeight()
|
||||
) {
|
||||
val hourlyIconSize = 22 * config.iconSize
|
||||
val hourlyTextSize = 14 * config.fontSize
|
||||
state.hourly.take(config.hourlyCount).forEach {
|
||||
WidgetHourlyItem(
|
||||
it.time,
|
||||
it.temp,
|
||||
it.conditionIcon,
|
||||
hourlyTextSize,
|
||||
hourlyIconSize,
|
||||
textColor.first,
|
||||
textColorVariant,
|
||||
verticalPadding = 10.dp,
|
||||
precipitationProbability = if (config.showPrecipitationProbability)
|
||||
it.precipitationProbability else null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
ReloadButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun GlanceModifier.appWidgetBackgroundShape(
|
||||
theme: WidgetTheme,
|
||||
widgetColors: WidgetColors
|
||||
): GlanceModifier {
|
||||
|
||||
|
||||
val color = widgetColors.getBackgroundColor(
|
||||
theme
|
||||
)
|
||||
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= 31) {
|
||||
this
|
||||
.cornerRadius(android.R.dimen.system_app_widget_background_radius)
|
||||
.background(color ?: GlanceTheme.colors.widgetBackground)
|
||||
} else {
|
||||
this
|
||||
.background(
|
||||
ImageProvider(R.drawable.weather_widget_background),
|
||||
colorFilter = ColorFilter.tint(color ?: GlanceTheme.colors.widgetBackground)
|
||||
)
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.pranshulgg.weather_master_app.widgets.hourly
|
||||
|
||||
import androidx.glance.appwidget.GlanceAppWidgetReceiver
|
||||
import com.pranshulgg.weather_master_app.widgets.pill.WidgetPill
|
||||
|
||||
|
||||
class WidgetHourlyReceiver : GlanceAppWidgetReceiver() {
|
||||
override val glanceAppWidget = WidgetHourly()
|
||||
|
||||
}
|
||||
+16
-2
@@ -2,6 +2,7 @@ package com.pranshulgg.weather_master_app.widgets.weather.components
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.glance.GlanceModifier
|
||||
@@ -28,12 +29,14 @@ fun WidgetHourlyItem(
|
||||
fontSize: Float,
|
||||
iconSize: Float,
|
||||
textColor: ColorProvider,
|
||||
textColorVariant: ColorProvider
|
||||
textColorVariant: ColorProvider,
|
||||
verticalPadding: Dp = 5.dp,
|
||||
precipitationProbability: Int? = null
|
||||
) {
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = GlanceModifier.padding(horizontal = 5.dp, vertical = 5.dp)
|
||||
modifier = GlanceModifier.padding(horizontal = 5.dp, vertical = verticalPadding)
|
||||
) {
|
||||
Text(
|
||||
temp,
|
||||
@@ -43,6 +46,17 @@ fun WidgetHourlyItem(
|
||||
fontSize = fontSize.sp
|
||||
)
|
||||
)
|
||||
|
||||
if (precipitationProbability != null) {
|
||||
Text(
|
||||
"${precipitationProbability}%",
|
||||
style = TextStyle(
|
||||
color = textColorVariant,
|
||||
fontSize = (fontSize * 0.9).sp
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(GlanceModifier.height(3.dp))
|
||||
Image(
|
||||
provider = ImageProvider(icon),
|
||||
|
||||
+27
-4
@@ -72,6 +72,8 @@ fun WeatherWidgetConfig(onDone: (WidgetConfig) -> Unit = {}) {
|
||||
var widgetTextTheme by remember { mutableStateOf(WidgetTextTheme.AUTO) }
|
||||
var selectedIconSize by remember { mutableFloatStateOf(1f) }
|
||||
|
||||
var showPrecipitationProbability by remember { mutableStateOf(false) }
|
||||
|
||||
val widgetThemeOptions =
|
||||
WidgetTheme.entries.filter { it != WidgetTheme.TRANSPARENT }
|
||||
.map { DialogOption(it.toString(), stringResource(it.label)) }
|
||||
@@ -106,7 +108,8 @@ fun WeatherWidgetConfig(onDone: (WidgetConfig) -> Unit = {}) {
|
||||
selectedFontSize,
|
||||
selectedIconSize,
|
||||
widgetTextTheme,
|
||||
widgetTheme
|
||||
widgetTheme,
|
||||
showPrecipitationProbability
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -210,6 +213,15 @@ fun WeatherWidgetConfig(onDone: (WidgetConfig) -> Unit = {}) {
|
||||
widgetTheme = selected
|
||||
}
|
||||
),
|
||||
SettingTile.SwitchTile(
|
||||
leading = { SettingsTileIcon(R.drawable.rainy_light_24px) },
|
||||
title = stringResource(R.string.settings_widget_show_precip_probability),
|
||||
description = stringResource(R.string.settings_widget_show_precip_probability_secondary),
|
||||
checked = showPrecipitationProbability,
|
||||
onCheckedChange = {
|
||||
showPrecipitationProbability = it
|
||||
}
|
||||
),
|
||||
SettingTile.DialogOptionTile(
|
||||
leading = { SettingsTileIcon(R.drawable.format_paint_24px) },
|
||||
title = stringResource(R.string.settings_widget_text_color),
|
||||
@@ -240,7 +252,8 @@ fun WeatherWidgetConfig(onDone: (WidgetConfig) -> Unit = {}) {
|
||||
fontSize = selectedFontSize,
|
||||
iconSize = selectedIconSize,
|
||||
widgetTheme = widgetTheme,
|
||||
widgetTextTheme = widgetTextTheme
|
||||
widgetTextTheme = widgetTextTheme,
|
||||
showPrecipitationProbability = showPrecipitationProbability
|
||||
)
|
||||
)
|
||||
},
|
||||
@@ -269,6 +282,7 @@ private fun GlanceWidgetPreview(
|
||||
iconSize: Float,
|
||||
textTheme: WidgetTextTheme,
|
||||
widgetTheme: WidgetTheme,
|
||||
showPrecipitationProbability: Boolean
|
||||
) {
|
||||
|
||||
val textColor = when (textTheme) {
|
||||
@@ -313,7 +327,8 @@ private fun GlanceWidgetPreview(
|
||||
widgetColor,
|
||||
textColor,
|
||||
textColorSecondary,
|
||||
hourlyContainerColor
|
||||
hourlyContainerColor,
|
||||
showPrecipitationProbability
|
||||
)
|
||||
|
||||
WidgetVariant.COMPACT -> CompactWidgetPreview(
|
||||
@@ -335,7 +350,8 @@ private fun LargeWidgetPreview(
|
||||
widgetColor: Color,
|
||||
textColor: Color,
|
||||
textColorSecondary: Color,
|
||||
hourlyContainerColor: Color
|
||||
hourlyContainerColor: Color,
|
||||
showPrecipitationProbability: Boolean
|
||||
) {
|
||||
|
||||
|
||||
@@ -386,6 +402,13 @@ private fun LargeWidgetPreview(
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = textColor
|
||||
)
|
||||
if (showPrecipitationProbability) {
|
||||
Text(
|
||||
"${temp * 2}%",
|
||||
fontSize = (hourlyTextSize * 0.9).sp,
|
||||
color = textColorSecondary
|
||||
)
|
||||
}
|
||||
Gap(3.dp)
|
||||
WeatherIconBox(icon, hourlyIconSize.dp)
|
||||
Gap(3.dp)
|
||||
|
||||
@@ -463,6 +463,8 @@
|
||||
<string name="unit_precipitation_inch_short">in</string>
|
||||
<string name="unit_precipitation_cm_short">cm</string>
|
||||
|
||||
<string name="settings_widget_show_precip_probability">Show precipitation probability</string>
|
||||
<string name="settings_widget_show_precip_probability_secondary">Displays the precipitation probability only when the selected source provides it</string>
|
||||
</resources>
|
||||
|
||||
<!--<string name=""></string>-->
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:minWidth="400dp"
|
||||
android:minHeight="40dp"
|
||||
android:minResizeWidth="100dp"
|
||||
android:minResizeHeight="40dp"
|
||||
android:resizeMode="horizontal|vertical"
|
||||
android:widgetCategory="home_screen"
|
||||
android:configure="com.pranshulgg.weather_master_app.widgets.config.WidgetConfigActivity"
|
||||
/>
|
||||
Reference in new issue
Block a user