Refactor preferences module

This commit is contained in:
MM20
2024-01-19 22:29:37 +01:00
parent 94aee6baba
commit 92ddc75060
171 changed files with 3202 additions and 2962 deletions
@@ -4,6 +4,7 @@ import android.content.Context
import android.location.Geocoder
import de.mm20.launcher2.crashreporter.CrashReporter
import de.mm20.launcher2.ktx.formatToString
import de.mm20.launcher2.preferences.weather.WeatherLocation
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.IOException
@@ -1,20 +1,16 @@
package de.mm20.launcher2.weather
import de.mm20.launcher2.backup.Backupable
import de.mm20.launcher2.weather.brightsky.BrightSkyProvider
import de.mm20.launcher2.weather.here.HereProvider
import de.mm20.launcher2.weather.metno.MetNoProvider
import de.mm20.launcher2.weather.openweathermap.OpenWeatherMapProvider
import de.mm20.launcher2.weather.plugin.PluginWeatherProvider
import de.mm20.launcher2.weather.settings.WeatherSettings
import org.koin.android.ext.koin.androidContext
import org.koin.core.qualifier.named
import org.koin.dsl.module
val weatherModule = module {
single<WeatherRepository> { WeatherRepositoryImpl(androidContext(), get(), get(), get()) }
single<WeatherSettings> { WeatherSettings(androidContext()) }
factory<Backupable>(named<WeatherSettings>()) { get<WeatherSettings>() }
factory<WeatherProvider> { (providerId: String) ->
when (providerId) {
OpenWeatherMapProvider.Id -> OpenWeatherMapProvider(androidContext())
@@ -1,16 +1,2 @@
package de.mm20.launcher2.weather
sealed interface WeatherLocation {
val name: String
data class LatLon(
override val name: String,
val lat: Double,
val lon: Double,
) : WeatherLocation
data class Id(
override val name: String,
val locationId: String,
) : WeatherLocation
}
@@ -1,5 +1,6 @@
package de.mm20.launcher2.weather
import de.mm20.launcher2.preferences.weather.WeatherLocation
import org.koin.core.component.KoinComponent
import org.koin.core.component.get
import org.koin.core.parameter.parametersOf
@@ -13,13 +13,13 @@ import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.plugin.PluginRepository
import de.mm20.launcher2.plugin.PluginType
import de.mm20.launcher2.preferences.LatLon
import de.mm20.launcher2.preferences.weather.WeatherLocation
import de.mm20.launcher2.preferences.weather.WeatherSettings
import de.mm20.launcher2.weather.brightsky.BrightSkyProvider
import de.mm20.launcher2.weather.here.HereProvider
import de.mm20.launcher2.weather.metno.MetNoProvider
import de.mm20.launcher2.weather.openweathermap.OpenWeatherMapProvider
import de.mm20.launcher2.weather.settings.LatLon
import de.mm20.launcher2.weather.settings.ProviderSettings
import de.mm20.launcher2.weather.settings.WeatherSettings
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import org.koin.core.component.KoinComponent
@@ -65,7 +65,7 @@ internal class WeatherRepositoryImpl(
}
override fun searchLocations(query: String): Flow<List<WeatherLocation>> {
return settings.data.map {
return settings.map {
val provider = WeatherProvider.getInstance(it.provider)
provider.findLocation(query)
}
@@ -86,7 +86,7 @@ internal class WeatherRepositoryImpl(
}
}
scope.launch {
settings.data.collectLatest {
settings.collectLatest {
requestUpdate()
}
}
@@ -178,7 +178,7 @@ class WeatherUpdateWorker(val context: Context, params: WorkerParameters) :
override suspend fun doWork(): Result {
Log.d("WeatherUpdateWorker", "Requesting weather data")
val settingsData = settings.data.first()
val settingsData = settings.first()
val provider = WeatherProvider.getInstance(settingsData.provider)
val updateInterval = provider.getUpdateInterval()
@@ -5,10 +5,10 @@ import android.icu.text.SimpleDateFormat
import android.icu.util.Calendar
import android.util.Log
import de.mm20.launcher2.crashreporter.CrashReporter
import de.mm20.launcher2.preferences.weather.WeatherLocation
import de.mm20.launcher2.weather.Forecast
import de.mm20.launcher2.weather.GeocoderWeatherProvider
import de.mm20.launcher2.weather.R
import de.mm20.launcher2.weather.WeatherLocation
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.create
@@ -3,9 +3,9 @@ package de.mm20.launcher2.weather.here
import android.content.Context
import android.util.Log
import de.mm20.launcher2.crashreporter.CrashReporter
import de.mm20.launcher2.preferences.weather.WeatherLocation
import de.mm20.launcher2.weather.Forecast
import de.mm20.launcher2.weather.R
import de.mm20.launcher2.weather.WeatherLocation
import de.mm20.launcher2.weather.WeatherProvider
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
@@ -7,13 +7,11 @@ import android.util.Base64
import android.util.Log
import androidx.annotation.WorkerThread
import de.mm20.launcher2.crashreporter.CrashReporter
import de.mm20.launcher2.preferences.weather.WeatherLocation
import de.mm20.launcher2.preferences.weather.WeatherSettings
import de.mm20.launcher2.weather.Forecast
import de.mm20.launcher2.weather.GeocoderWeatherProvider
import de.mm20.launcher2.weather.R
import de.mm20.launcher2.weather.WeatherLocation
import de.mm20.launcher2.weather.WeatherProvider
import de.mm20.launcher2.weather.settings.ProviderSettings
import de.mm20.launcher2.weather.settings.WeatherSettings
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
@@ -3,9 +3,9 @@ package de.mm20.launcher2.weather.openweathermap
import android.content.Context
import android.util.Log
import de.mm20.launcher2.crashreporter.CrashReporter
import de.mm20.launcher2.preferences.weather.WeatherLocation
import de.mm20.launcher2.weather.Forecast
import de.mm20.launcher2.weather.R
import de.mm20.launcher2.weather.WeatherLocation
import de.mm20.launcher2.weather.WeatherProvider
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
@@ -13,8 +13,8 @@ import de.mm20.launcher2.crashreporter.CrashReporter
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.preferences.weather.WeatherLocation
import de.mm20.launcher2.weather.Forecast
import de.mm20.launcher2.weather.WeatherLocation
import de.mm20.launcher2.weather.WeatherProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.suspendCancellableCoroutine
@@ -1,119 +0,0 @@
package de.mm20.launcher2.weather.settings
import android.content.Context
import de.mm20.launcher2.settings.BaseSettings
import de.mm20.launcher2.weather.WeatherLocation
import de.mm20.launcher2.weather.WeatherProviderInfo
import kotlinx.coroutines.flow.map
class WeatherSettings(
private val context: Context,
) : BaseSettings<WeatherSettingsData>(
context,
"weather_settings.json",
WeatherSettingsSerializer,
emptyList(),
) {
internal val data
get() = context.dataStore.data
val location = data.map {
val providerSettings = it.providerSettings[it.provider]
val id = providerSettings?.locationId
val name = providerSettings?.locationName
if (id != null && name != null) {
WeatherLocation.Id(name, id)
} else if (it.location != null && it.locationName != null) {
WeatherLocation.LatLon(it.locationName, it.location.lat, it.location.lon)
} else {
null
}
}
val autoLocation = data.map { it.autoLocation }
fun setLocation(location: WeatherLocation) {
updateData {
val providerSettings =
it.providerSettings.getOrDefault(it.provider, ProviderSettings())
when (location) {
is WeatherLocation.LatLon -> {
it.copy(
location = LatLon(lat = location.lat, lon = location.lon),
locationName = location.name,
lastUpdate = 0L,
autoLocation = false,
providerSettings = it.providerSettings.toMutableMap().apply {
put(
it.provider,
providerSettings.copy(
locationId = null,
locationName = null,
)
)
}
)
}
is WeatherLocation.Id -> {
it.copy(
location = null,
locationName = null,
autoLocation = false,
lastUpdate = 0L,
providerSettings = it.providerSettings.toMutableMap().apply {
put(
it.provider,
providerSettings.copy(
locationId = location.locationId,
locationName = location.name
)
)
}
)
}
}
}
}
fun setLastLocation(location: LatLon) {
updateData {
it.copy(
lastLocation = location,
)
}
}
val lastUpdate = data.map { it.lastUpdate }
fun setLastUpdate(lastUpdate: Long) {
updateData {
it.copy(lastUpdate = lastUpdate)
}
}
val providerId = data.map { it.provider }
fun setProvider(provider: WeatherProviderInfo) {
setProviderId(provider.id)
}
fun setAutoLocation(autoLocation: Boolean) {
updateData {
it.copy(
autoLocation = autoLocation,
lastUpdate = 0L,
)
}
}
fun setProviderId(providerId: String) {
updateData {
it.copy(
provider = providerId,
lastUpdate = 0L,
)
}
}
}
@@ -1,63 +0,0 @@
package de.mm20.launcher2.weather.settings
import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.encodeToStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
@Serializable
data class LatLon(
val lat: Double,
val lon: Double,
)
@Serializable
data class ProviderSettings(
val locationId: String? = null,
val locationName: String? = null,
)
@Serializable
data class WeatherSettingsData(
val schemaVersion: Int = 1,
val provider: String = "metno",
val autoLocation: Boolean = true,
val location: LatLon? = null,
val locationName: String? = null,
val lastLocation: LatLon? = null,
val lastUpdate: Long = 0L,
val providerSettings: Map<String, ProviderSettings> = emptyMap(),
)
internal object WeatherSettingsSerializer : Serializer<WeatherSettingsData>{
internal val json = Json {
ignoreUnknownKeys = true
encodeDefaults = true
}
override val defaultValue: WeatherSettingsData
get() = WeatherSettingsData()
override suspend fun readFrom(input: InputStream): WeatherSettingsData {
try {
return json.decodeFromStream(input)
} catch (e: IllegalArgumentException) {
throw (CorruptionException("Cannot read json.", e))
} catch (e: SerializationException) {
throw (CorruptionException("Cannot read json.", e))
} catch (e: IOException) {
throw (CorruptionException("Cannot read json.", e))
}
}
override suspend fun writeTo(t: WeatherSettingsData, output: OutputStream) {
json.encodeToStream(t, output)
}
}