Refactor weather module
This commit is contained in:
@@ -4,12 +4,15 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import de.mm20.launcher2.weather.WeatherLocation
|
||||
import de.mm20.launcher2.weather.WeatherRepository
|
||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.first
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
class WeatherLocationSearchDialogVM: ViewModel(), KoinComponent {
|
||||
private val weatherSettings: WeatherSettings by inject()
|
||||
private val repository: WeatherRepository by inject()
|
||||
|
||||
val isSearchingLocation = mutableStateOf(false)
|
||||
@@ -27,7 +30,7 @@ class WeatherLocationSearchDialogVM: ViewModel(), KoinComponent {
|
||||
debounceSearchJob = launch {
|
||||
delay(1000)
|
||||
isSearchingLocation.value = true
|
||||
locationResults.value = repository.lookupLocation(query)
|
||||
locationResults.value = repository.searchLocations(query).first()
|
||||
isSearchingLocation.value = false
|
||||
}
|
||||
}
|
||||
@@ -35,7 +38,6 @@ class WeatherLocationSearchDialogVM: ViewModel(), KoinComponent {
|
||||
|
||||
fun setLocation(location: WeatherLocation) {
|
||||
locationResults.value = emptyList()
|
||||
repository.setAutoLocation(false)
|
||||
repository.setLocation(location)
|
||||
weatherSettings.setLocation(location)
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -9,6 +9,7 @@ import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.weather.DailyForecast
|
||||
import de.mm20.launcher2.weather.Forecast
|
||||
import de.mm20.launcher2.weather.WeatherRepository
|
||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -21,6 +22,7 @@ import kotlin.math.min
|
||||
|
||||
class WeatherWidgetVM : ViewModel(), KoinComponent {
|
||||
private val weatherRepository: WeatherRepository by inject()
|
||||
private val weatherSettings: WeatherSettings by inject()
|
||||
|
||||
private val permissionsManager: PermissionsManager by inject()
|
||||
|
||||
@@ -58,7 +60,7 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
||||
currentForecast.value = getCurrentlySelectedForecast()
|
||||
}
|
||||
|
||||
private val forecastsFlow = weatherRepository.forecasts
|
||||
private val forecastsFlow = weatherRepository.getDailyForecasts()
|
||||
|
||||
/**
|
||||
* All available forecasts, grouped by day
|
||||
@@ -106,7 +108,7 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
||||
fun requestLocationPermission(context: AppCompatActivity) {
|
||||
permissionsManager.requestPermission(context, PermissionGroup.Location)
|
||||
}
|
||||
val autoLocation = weatherRepository.autoLocation
|
||||
val autoLocation = weatherSettings.autoLocation
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val imperialUnits = dataStore.data.map { it.weather.imperialUnits }
|
||||
|
||||
+2
-1
@@ -18,6 +18,7 @@ import java.security.MessageDigest
|
||||
fun BuildInfoSettingsScreen() {
|
||||
val viewModel: BuildInfoSettingsScreenVM = viewModel()
|
||||
val context = LocalContext.current
|
||||
val buildFeatures by viewModel.buildFeatures.collectAsState(emptyMap())
|
||||
PreferenceScreen(title = stringResource(R.string.preference_screen_buildinfo)) {
|
||||
item {
|
||||
Preference(title = "Build type", summary = BuildConfig.BUILD_TYPE)
|
||||
@@ -47,7 +48,7 @@ fun BuildInfoSettingsScreen() {
|
||||
}
|
||||
item {
|
||||
PreferenceCategory(title = "Features") {
|
||||
for (feature in viewModel.buildFeatures) {
|
||||
for (feature in buildFeatures) {
|
||||
Preference(
|
||||
title = feature.key,
|
||||
summary = if (feature.value) "YES" else "NO"
|
||||
|
||||
+10
-7
@@ -5,6 +5,7 @@ import de.mm20.launcher2.accounts.AccountType
|
||||
import de.mm20.launcher2.accounts.AccountsRepository
|
||||
import de.mm20.launcher2.preferences.Settings.WeatherSettings.WeatherProvider
|
||||
import de.mm20.launcher2.weather.WeatherRepository
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
@@ -12,12 +13,14 @@ class BuildInfoSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val accountsRepository: AccountsRepository by inject()
|
||||
private val weatherRepository: WeatherRepository by inject()
|
||||
|
||||
private val availableWeatherProviders = weatherRepository.getAvailableProviders()
|
||||
private val availableWeatherProviders = weatherRepository.getProviders()
|
||||
|
||||
val buildFeatures = mapOf(
|
||||
"Accounts: Google" to accountsRepository.isSupported(AccountType.Google),
|
||||
"Weather providers: HERE" to availableWeatherProviders.contains(WeatherProvider.Here),
|
||||
"Weather providers: Met No" to availableWeatherProviders.contains(WeatherProvider.MetNo),
|
||||
"Weather providers: OpenWeatherMap" to availableWeatherProviders.contains(WeatherProvider.OpenWeatherMap),
|
||||
)
|
||||
val buildFeatures = availableWeatherProviders.map {
|
||||
mapOf(
|
||||
"Accounts: Google" to accountsRepository.isSupported(AccountType.Google),
|
||||
"Weather providers: HERE" to it.any { it.id == "here" },
|
||||
"Weather providers: Met No" to it.any { it.id == "metno" },
|
||||
"Weather providers: OpenWeatherMap" to it.any { it.id == "owm" },
|
||||
)
|
||||
}
|
||||
}
|
||||
+9
-12
@@ -8,20 +8,23 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
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.preferences.Settings.WeatherSettings.WeatherProvider
|
||||
import de.mm20.launcher2.ui.BuildConfig
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.common.WeatherLocationSearchDialog
|
||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||
import de.mm20.launcher2.ui.component.preferences.*
|
||||
import de.mm20.launcher2.weather.WeatherLocation
|
||||
import de.mm20.launcher2.weather.WeatherProviderInfo
|
||||
|
||||
@Composable
|
||||
fun WeatherIntegrationSettingsScreen() {
|
||||
val viewModel: WeatherIntegrationSettingsScreenVM = viewModel()
|
||||
val context = LocalContext.current
|
||||
|
||||
val availableProviders by viewModel.availableProviders.collectAsState(emptyList())
|
||||
|
||||
PreferenceScreen(
|
||||
title = stringResource(R.string.preference_screen_weatherwidget),
|
||||
helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/integrations/weather"
|
||||
@@ -31,14 +34,8 @@ fun WeatherIntegrationSettingsScreen() {
|
||||
val weatherProvider by viewModel.weatherProvider.collectAsState()
|
||||
ListPreference(
|
||||
title = stringResource(R.string.preference_weather_provider),
|
||||
items = viewModel.availableProviders.map {
|
||||
when (it) {
|
||||
WeatherProvider.MetNo -> stringResource(R.string.provider_metno)
|
||||
WeatherProvider.OpenWeatherMap -> stringResource(R.string.provider_openweathermap)
|
||||
WeatherProvider.Here -> stringResource(R.string.provider_here)
|
||||
WeatherProvider.BrightSky -> stringResource(R.string.provider_brightsky)
|
||||
else -> "Unknown provider"
|
||||
} to it
|
||||
items = availableProviders.map{
|
||||
it.name to it.id
|
||||
},
|
||||
onValueChanged = {
|
||||
if (it != null) viewModel.setWeatherProvider(it)
|
||||
@@ -78,7 +75,7 @@ fun WeatherIntegrationSettingsScreen() {
|
||||
viewModel.setAutoLocation(it)
|
||||
}
|
||||
)
|
||||
val location by viewModel.location
|
||||
val location by viewModel.location.collectAsStateWithLifecycle()
|
||||
LocationPreference(
|
||||
title = stringResource(R.string.preference_location),
|
||||
value = location,
|
||||
@@ -104,13 +101,13 @@ fun WeatherIntegrationSettingsScreen() {
|
||||
@Composable
|
||||
fun LocationPreference(
|
||||
title: String,
|
||||
value: WeatherLocation?,
|
||||
value: String?,
|
||||
enabled: Boolean = true
|
||||
) {
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
Preference(
|
||||
title = title,
|
||||
summary = value?.name,
|
||||
summary = value,
|
||||
enabled = enabled,
|
||||
onClick = {
|
||||
showDialog = true
|
||||
|
||||
+19
-23
@@ -7,13 +7,16 @@ import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.WeatherSettings
|
||||
import de.mm20.launcher2.weather.WeatherLocation
|
||||
import de.mm20.launcher2.weather.WeatherProviderInfo
|
||||
import de.mm20.launcher2.weather.WeatherRepository
|
||||
import de.mm20.launcher2.weather.settings.WeatherSettings
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.koin.core.component.KoinComponent
|
||||
@@ -21,15 +24,16 @@ import org.koin.core.component.inject
|
||||
|
||||
class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val repository: WeatherRepository by inject()
|
||||
private val weatherSettings: WeatherSettings by inject()
|
||||
private val permissionsManager: PermissionsManager by inject()
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val availableProviders = repository.getAvailableProviders()
|
||||
val availableProviders = repository.getProviders()
|
||||
|
||||
val weatherProvider = repository.selectedProvider
|
||||
val weatherProvider = weatherSettings.providerId
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setWeatherProvider(provider: WeatherSettings.WeatherProvider) {
|
||||
repository.selectProvider(provider)
|
||||
fun setWeatherProvider(provider: String) {
|
||||
weatherSettings.setProviderId(provider)
|
||||
}
|
||||
|
||||
val imperialUnits = dataStore.data.map { it.weather.imperialUnits }
|
||||
@@ -43,13 +47,19 @@ class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val autoLocation = repository.autoLocation
|
||||
val autoLocation = weatherSettings.autoLocation
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
fun setAutoLocation(autoLocation: Boolean) {
|
||||
repository.setAutoLocation(autoLocation)
|
||||
weatherSettings.setAutoLocation(autoLocation)
|
||||
}
|
||||
|
||||
val location = mutableStateOf<WeatherLocation?>(null)
|
||||
val location = weatherSettings.autoLocation.flatMapLatest {
|
||||
if (it) {
|
||||
repository.getForecasts(limit = 1).map { it.firstOrNull()?.location }
|
||||
} else {
|
||||
weatherSettings.location.map { it?.name }
|
||||
}
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val hasLocationPermission = permissionsManager.hasPermission(PermissionGroup.Location)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
@@ -59,22 +69,8 @@ class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
val autoLocation = repository.autoLocation
|
||||
val location = repository.location
|
||||
val lastLocation = repository.lastLocation
|
||||
combine(autoLocation, lastLocation, location) { autoLoc, lastLoc, loc ->
|
||||
if (autoLoc) lastLoc
|
||||
else loc
|
||||
}.collectLatest {
|
||||
this@WeatherIntegrationSettingsScreenVM.location.value = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun clearWeatherData() {
|
||||
repository.clearForecasts()
|
||||
repository.deleteForecasts()
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user