Add Breezy Weather integration

This commit is contained in:
MM20
2025-04-28 20:58:59 +02:00
parent 4e2fbf965f
commit 5e59bf171a
14 changed files with 645 additions and 66 deletions
@@ -37,6 +37,7 @@ import de.mm20.launcher2.ui.overlays.OverlayHost
import de.mm20.launcher2.ui.settings.about.AboutSettingsScreen
import de.mm20.launcher2.ui.settings.appearance.AppearanceSettingsScreen
import de.mm20.launcher2.ui.settings.backup.BackupSettingsScreen
import de.mm20.launcher2.ui.settings.breezyweather.BreezyWeatherSettingsScreen
import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
import de.mm20.launcher2.ui.settings.calendarsearch.CalendarProviderSettingsScreen
import de.mm20.launcher2.ui.settings.calendarsearch.CalendarSearchSettingsScreen
@@ -244,6 +245,9 @@ class SettingsActivity : BaseActivity() {
composable("settings/integrations/tasks") {
TasksIntegrationSettingsScreen()
}
composable("settings/integrations/breezyweather") {
BreezyWeatherSettingsScreen()
}
composable("settings/plugins") {
PluginsSettingsScreen()
}
@@ -0,0 +1,89 @@
package de.mm20.launcher2.ui.settings.breezyweather
import androidx.activity.compose.LocalActivity
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.OpenInNew
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.Banner
import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
@Composable
fun BreezyWeatherSettingsScreen() {
val activity = LocalActivity.current as AppCompatActivity
val viewModel: BreezyWeatherSettingsScreenVM = viewModel()
val isBreezyInstalled by viewModel.isBreezyInstalled.collectAsStateWithLifecycle(null)
val isWeatherProvider by viewModel.isBreezySetAsWeatherProvider.collectAsStateWithLifecycle(null)
PreferenceScreen(
title = stringResource(R.string.preference_breezyweather_integration)
) {
if (isBreezyInstalled == false) {
item {
Banner(
text = stringResource(
R.string.preference_breezyweather_integration_description,
stringResource(R.string.app_name),
),
icon = Icons.Rounded.Info,
modifier = Modifier.padding(16.dp),
primaryAction = {
Button(onClick = {
viewModel.downloadBreezyApp(activity)
}) {
Text(stringResource(R.string.action_install))
}
}
)
}
}
if (isBreezyInstalled == true) {
item {
Banner(
text = stringResource(
R.string.preference_breezyweather_integration_instructions,
stringResource(R.string.app_name),
),
icon = Icons.Rounded.Info,
modifier = Modifier.padding(16.dp),
)
}
item {
PreferenceCategory {
Preference(
title = stringResource(R.string.preference_breezyweather_integration),
summary = stringResource(
if (isWeatherProvider == true) R.string.plugin_weather_provider_enabled
else R.string.plugin_weather_provider_enable
),
enabled = isWeatherProvider == false,
onClick = {
viewModel.setBreezyAsWeatherProvider()
}
)
Preference(
title = stringResource(R.string.preference_launch_breezyweather_app),
icon = Icons.AutoMirrored.Rounded.OpenInNew,
onClick = {
viewModel.launchBreezyApp(activity)
}
)
}
}
}
}
}
@@ -0,0 +1,53 @@
package de.mm20.launcher2.ui.settings.breezyweather
import android.content.Intent
import android.os.Process
import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.applications.AppRepository
import de.mm20.launcher2.preferences.weather.WeatherSettings
import de.mm20.launcher2.weather.WeatherRepository
import de.mm20.launcher2.weather.breezy.BreezyWeatherProvider
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class BreezyWeatherSettingsScreenVM: ViewModel(), KoinComponent {
private val appRepository: AppRepository by inject()
private val weatherSettings: WeatherSettings by inject()
private val breezyWeatherApp = appRepository.findOne("org.breezyweather", Process.myUserHandle())
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
val isBreezyInstalled = breezyWeatherApp
.map { it != null }
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
val isBreezySetAsWeatherProvider = weatherSettings.providerId
.map { it == BreezyWeatherProvider.Id }
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
fun setBreezyAsWeatherProvider() {
weatherSettings.setProvider(BreezyWeatherProvider.Id)
}
fun launchBreezyApp(activity: AppCompatActivity) {
viewModelScope.launch {
breezyWeatherApp.first()?.launch(activity, null)
}
}
fun downloadBreezyApp(activity: AppCompatActivity) {
activity.startActivity(
Intent(Intent.ACTION_VIEW).apply {
data = "https://github.com/breezy-weather/breezy-weather/blob/main/INSTALL.md".toUri()
}
)
}
}
@@ -7,11 +7,13 @@ import androidx.compose.material.icons.rounded.PlayCircleOutline
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.icons.BreezyWeather
import de.mm20.launcher2.icons.Google
import de.mm20.launcher2.icons.Nextcloud
import de.mm20.launcher2.icons.Owncloud
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.locals.LocalNavController
@@ -22,41 +24,54 @@ fun IntegrationsSettingsScreen() {
PreferenceScreen(title = stringResource(R.string.preference_screen_integrations)) {
item {
Preference(
title = stringResource(R.string.preference_weather_integration),
icon = Icons.Rounded.LightMode,
onClick = {
navController?.navigate("settings/integrations/weather")
}
)
Preference(
title = stringResource(R.string.preference_media_integration),
icon = Icons.Rounded.PlayCircleOutline,
onClick = {
navController?.navigate("settings/integrations/media")
}
)
Preference(
title = stringResource(R.string.preference_nextcloud),
icon = Icons.Rounded.Nextcloud,
onClick = {
navController?.navigate("settings/integrations/nextcloud")
}
)
Preference(
title = stringResource(R.string.preference_owncloud),
icon = Icons.Rounded.Owncloud,
onClick = {
navController?.navigate("settings/integrations/owncloud")
}
)
Preference(
title = stringResource(R.string.preference_tasks_integration),
icon = Icons.Default.Check,
onClick = {
navController?.navigate("settings/integrations/tasks")
}
)
PreferenceCategory {
Preference(
title = stringResource(R.string.preference_weather_integration),
icon = Icons.Rounded.LightMode,
onClick = {
navController?.navigate("settings/integrations/weather")
}
)
Preference(
title = stringResource(R.string.preference_media_integration),
icon = Icons.Rounded.PlayCircleOutline,
onClick = {
navController?.navigate("settings/integrations/media")
}
)
}
}
item {
PreferenceCategory {
Preference(
title = stringResource(R.string.preference_nextcloud),
icon = Icons.Rounded.Nextcloud,
onClick = {
navController?.navigate("settings/integrations/nextcloud")
}
)
Preference(
title = stringResource(R.string.preference_owncloud),
icon = Icons.Rounded.Owncloud,
onClick = {
navController?.navigate("settings/integrations/owncloud")
}
)
Preference(
title = stringResource(R.string.preference_tasks_integration),
icon = Icons.Default.Check,
onClick = {
navController?.navigate("settings/integrations/tasks")
}
)
Preference(
title = stringResource(R.string.preference_breezyweather_integration),
icon = Icons.Rounded.BreezyWeather,
onClick = {
navController?.navigate("settings/integrations/breezyweather")
}
)
}
}
}
}
@@ -1,6 +1,7 @@
package de.mm20.launcher2.ui.settings.weather
import android.app.PendingIntent
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.padding
@@ -18,6 +19,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.crashreporter.CrashReporter
import de.mm20.launcher2.ktx.sendWithBackgroundPermission
import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.plugin.PluginState
import de.mm20.launcher2.ui.BuildConfig
import de.mm20.launcher2.ui.R
@@ -26,6 +28,7 @@ import de.mm20.launcher2.ui.component.Banner
import de.mm20.launcher2.ui.component.MissingPermissionBanner
import de.mm20.launcher2.ui.component.preferences.*
import de.mm20.launcher2.weather.WeatherProviderInfo
import de.mm20.launcher2.weather.breezy.BreezyWeatherProvider
@Composable
fun WeatherIntegrationSettingsScreen() {
@@ -93,7 +96,16 @@ fun WeatherIntegrationSettingsScreen() {
}
item {
PreferenceCategory(title = stringResource(R.string.preference_category_location)) {
if (selectedProviderInfo?.managedLocation == true) {
if (selectedProviderInfo?.id == BreezyWeatherProvider.Id) {
Preference(
title = stringResource(R.string.preference_location),
summary = stringResource(R.string.preference_location_breezy),
onClick = {
val intent = context.packageManager.getLaunchIntentForPackage("org.breezyweather") ?: return@Preference
context.tryStartActivity(intent)
}
)
} else if (selectedProviderInfo?.managedLocation == true) {
Preference(
title = stringResource(R.string.preference_location_managed),
summary = stringResource(R.string.preference_location_managed_summary),