Weather widget: launch weather app on tap if installed

This commit is contained in:
MM20 2025-04-28 21:48:33 +02:00
parent c217c346b2
commit a711b39b9c
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
2 changed files with 205 additions and 148 deletions

View File

@ -1,13 +1,18 @@
package de.mm20.launcher2.ui.launcher.widgets.weather package de.mm20.launcher2.ui.launcher.widgets.weather
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.text.format.DateUtils import android.text.format.DateUtils
import android.util.Log
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
@ -48,13 +53,18 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.app.ActivityOptionsCompat
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@ -208,7 +218,52 @@ fun WeatherWidget(widget: WeatherWidget) {
@Composable @Composable
fun CurrentWeather(forecast: Forecast, imperialUnits: Boolean) { fun CurrentWeather(forecast: Forecast, imperialUnits: Boolean) {
val context = LocalContext.current val context = LocalContext.current
Column { val weatherApp = remember {
context.packageManager.resolveActivity(
Intent(Intent.ACTION_MAIN).also {
it.addCategory(Intent.CATEGORY_APP_WEATHER)
}, 0
)
}
var bounds by remember { mutableStateOf(Rect.Zero) }
val view = LocalView.current
Column(
modifier = Modifier
.onPlaced {
val size = it.size
val offset = it.localToRoot(Offset.Zero)
bounds = Rect(
offset.x,
offset.y,
offset.x + size.width,
offset.y + size.height
)
}
.clickable(
enabled = weatherApp != null,
onClick = {
context.tryStartActivity(
Intent().also {
it.component = weatherApp?.activityInfo?.let {
ComponentName(it.packageName, it.name)
}
},
ActivityOptionsCompat.makeClipRevealAnimation(
view,
bounds.left.toInt(),
bounds.top.toInt(),
bounds.width.toInt(),
bounds.height.toInt()
).toBundle()
)
},
interactionSource = MutableInteractionSource(),
indication = LocalIndication.current,
)
) {
Column(
) {
Row( Row(
verticalAlignment = Alignment.Top, verticalAlignment = Alignment.Top,
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
@ -380,6 +435,7 @@ fun CurrentWeather(forecast: Forecast, imperialUnits: Boolean) {
} }
} }
} }
}
@Composable @Composable
fun WeatherTimeSelector( fun WeatherTimeSelector(

View File

@ -12,6 +12,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
import kotlin.time.Duration.Companion.days
class BreezyWeatherProvider( class BreezyWeatherProvider(
private val context: Context, private val context: Context,
@ -38,7 +39,7 @@ class BreezyWeatherProvider(
override suspend fun getUpdateInterval(): Long { override suspend fun getUpdateInterval(): Long {
// Updates are pushed, no need to pull // Updates are pushed, no need to pull
return Long.MAX_VALUE return 365.days.inWholeMilliseconds
} }
internal suspend fun pushWeatherData(data: BreezyWeatherData) { internal suspend fun pushWeatherData(data: BreezyWeatherData) {