From 02ebad26eda2ae5cfef60be43052df2e3cc950db Mon Sep 17 00:00:00 2001 From: pranshulgg Date: Fri, 25 Sep 2026 21:18:41 +0530 Subject: [PATCH] add kmi closes #997 closes #381 closes #1122 --- .../core/di/network/ApiModule.kt | 5 + .../di/weather/WeatherRepositoryModule.kt | 14 ++ .../core/managers/WeatherManager.kt | 2 - .../core/model/sources/Source.kt | 8 + .../core/model/weather/WeatherResult.kt | 6 +- .../sources/weather/kmi/KmiRepository.kt | 90 ++++++++- .../weather/kmi/KmiWeatherConditionMap.kt | 21 ++ .../weather/kmi/json/KmiWeatherJson.kt | 20 +- .../weather/sources/accu/AccuJsonMapper.kt | 3 +- .../weather/sources/kmi/KmiJsonMapper.kt | 183 ++++++++++++++++++ .../sources/kmi/alerts/KmiAlertsMapper.kt | 38 ++++ .../data/provider/SourceRepositoryProvider.kt | 5 +- .../data/repository/data/BaseRepository.kt | 4 +- app/src/main/res/values/strings.xml | 2 +- 14 files changed, 384 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/KmiWeatherConditionMap.kt create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/kmi/KmiJsonMapper.kt create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/kmi/alerts/KmiAlertsMapper.kt diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/di/network/ApiModule.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/di/network/ApiModule.kt index 2fcb58368..ce1aa9eb7 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/core/di/network/ApiModule.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/di/network/ApiModule.kt @@ -25,6 +25,7 @@ import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.Inme import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.InmetForecastApi import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.InmetObservationApi import com.pranshulgg.weather_master_app.core.network.sources.weather.ipma.IpmaApi +import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.KmiApi import com.pranshulgg.weather_master_app.core.network.sources.weather.meteoam.MeteoamApi import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofrance.MeteoFranceApi import com.pranshulgg.weather_master_app.core.network.sources.weather.metnorway.MetNorwayApi @@ -189,4 +190,8 @@ object ApiModule { @Provides @Singleton fun provideMgmApi(): MgmApi = MgmApi.create() + + @Provides + @Singleton + fun provideKmiApi(): KmiApi = KmiApi.create() } diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/di/weather/WeatherRepositoryModule.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/di/weather/WeatherRepositoryModule.kt index 9a4e63764..44eb4c574 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/core/di/weather/WeatherRepositoryModule.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/di/weather/WeatherRepositoryModule.kt @@ -30,6 +30,8 @@ import com.pranshulgg.weather_master_app.core.network.sources.weather.jma.JmaApi import com.pranshulgg.weather_master_app.core.network.sources.weather.jma.JmaRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.ipma.IpmaApi import com.pranshulgg.weather_master_app.core.network.sources.weather.ipma.IpmaRepository +import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.KmiApi +import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.KmiRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.meteoam.MeteoamApi import com.pranshulgg.weather_master_app.core.network.sources.weather.meteoam.MeteoamRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofrance.MeteoFranceApi @@ -299,4 +301,16 @@ object WeatherRepositoryModule { locationKeysDao: LocationKeysDao, alertsDao: AlertsDao ): MgmRepository = MgmRepository(dao, weatherDao, api, apiKeysDao, locationKeysDao, alertsDao) + + @Provides + @Singleton + fun provideKmiRepository( + dao: WeatherContextDao, + weatherDao: WeatherDao, + api: KmiApi, + apiKeysDao: ApiKeysDao, + locationKeysDao: LocationKeysDao, + alertsDao: AlertsDao + ): KmiRepository = KmiRepository(dao, weatherDao, api, apiKeysDao, locationKeysDao, alertsDao) + } \ No newline at end of file diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/managers/WeatherManager.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/managers/WeatherManager.kt index 653013579..40b25b1af 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/core/managers/WeatherManager.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/managers/WeatherManager.kt @@ -141,9 +141,7 @@ class WeatherManager @Inject constructor( && !location.source.isSourceSupportedFor( countryCode = location.countryCode?.uppercase() ) - _errors.tryEmit(result.exception.toAppException()) - } is WeatherResult.RefreshNotAvailable -> { diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/model/sources/Source.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/model/sources/Source.kt index 6acae2446..16db1aff7 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/core/model/sources/Source.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/model/sources/Source.kt @@ -203,6 +203,13 @@ enum class Source( countryNameRes = R.string.country_turkey, capabilities = setOf(Capability.WEATHER, Capability.ALERTS) ), + KMI( + displayName = "KMI", + fullName = "Royal Meteorological Institute of Belgium", + displayLink = "https://www.meteo.be/", + countryNameRes = R.string.country_belgium, + capabilities = setOf(Capability.WEATHER, Capability.ALERTS) + ), OPEN_WEATHER( displayName = "OpenWeather", fullName = "OpenWeather", @@ -250,6 +257,7 @@ private val sourcesByCountry = buildMap { put("JP", listOf(Source.JMA)) put("BR", listOf(Source.INMET)) put("TR", listOf(Source.MGM)) + put("BE", listOf(Source.KMI)) } diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/model/weather/WeatherResult.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/model/weather/WeatherResult.kt index 3efb2c114..d737c6d30 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/core/model/weather/WeatherResult.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/model/weather/WeatherResult.kt @@ -13,7 +13,11 @@ sealed class WeatherResult( data class RefreshNotAvailable(val weather: Weather) : WeatherResult() - data class Error(val exception: Exception, val weather: Weather?) : WeatherResult() + data class Error( + val exception: Exception, + val weather: Weather?, + val rawException: Exception? = null + ) : WeatherResult() class NotSupported : WeatherResult() diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/KmiRepository.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/KmiRepository.kt index 0a1397096..d011b8656 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/KmiRepository.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/KmiRepository.kt @@ -1,18 +1,29 @@ package com.pranshulgg.weather_master_app.core.network.sources.weather.kmi +import com.pranshulgg.weather_master_app.core.model.domain.alerts.Alert import com.pranshulgg.weather_master_app.core.model.domain.location.Location import com.pranshulgg.weather_master_app.core.model.domain.weather.Weather import com.pranshulgg.weather_master_app.core.model.sources.Source import com.pranshulgg.weather_master_app.core.model.weather.FinishedWeatherResult import com.pranshulgg.weather_master_app.core.model.weather.WeatherDataPack +import com.pranshulgg.weather_master_app.core.model.weather.alerts.AlertsDataPack +import com.pranshulgg.weather_master_app.core.model.weather.alerts.FinishedAlertsResult +import com.pranshulgg.weather_master_app.core.network.calls.safeApiCall import com.pranshulgg.weather_master_app.core.network.sources.weather.mgm.MgmApi import com.pranshulgg.weather_master_app.data.local.dao.alerts.AlertsDao import com.pranshulgg.weather_master_app.data.local.dao.location.LocationKeysDao import com.pranshulgg.weather_master_app.data.local.dao.weather.ApiKeysDao import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherContextDao import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherDao +import com.pranshulgg.weather_master_app.data.local.mapper.weather.sources.kmi.alerts.toAlertsDomain +import com.pranshulgg.weather_master_app.data.local.mapper.weather.sources.kmi.toDomain +import com.pranshulgg.weather_master_app.data.local.mapper.weather.sources.pirateweather.alerts.toDomain +import com.pranshulgg.weather_master_app.data.repository.alerts.AlertCacheModel +import com.pranshulgg.weather_master_app.data.repository.capability.AirQualityCapability +import com.pranshulgg.weather_master_app.data.repository.capability.AlertCapability import com.pranshulgg.weather_master_app.data.repository.capability.WeatherCapability import com.pranshulgg.weather_master_app.data.repository.data.BaseRepository +import com.pranshulgg.weather_master_app.data.repository.data.WeatherAdditionalData import com.pranshulgg.weather_master_app.data.repository.weather.CacheModel import java.security.MessageDigest import java.time.LocalDate @@ -45,25 +56,90 @@ class KmiRepository @Inject constructor( isForceRefresh: Boolean, cacheModel: CacheModel ): WeatherDataPack { - val response = api.fetchWeather( - lat = location.latitude, - lon = location.longitude, - key = generateIrmKmiKey() - ) + val response = safeApiCall { + api.fetchWeather( + lat = location.latitude, + lon = location.longitude, + key = generateIrmKmiKey() + ) + }.getOrThrow() + return WeatherDataPack( + weather = response.toDomain(location), + additionalData = WeatherAdditionalData( + alerts = AlertsDataPack( + alerts = response.toAlertsDomain(locationId = location.id), + location + ) + ) + ) } override suspend fun saveToDb(data: WeatherDataPack, cacheModel: CacheModel) { - TODO("Not yet implemented") + useGenericSaveImplementationForWeather( + existingHourly = cacheModel.cachedHourly, + data = data.weather, + weatherDao = weatherDao + ) + } + + override suspend fun saveAdditionalDataToDb(pack: WeatherDataPack) { + useGenericSaveImplementationForAlerts( + pack.additionalData?.alerts!!, + alertsDao, + dao + ) + } override fun finishedResult(data: Weather): FinishedWeatherResult { - TODO("Not yet implemented") + return FinishedWeatherResult(weather = data) } } } + override fun alertCapability(): AlertCapability? { + return object : AlertCapability { + override suspend fun fetchAndProcess( + location: Location, + isManualRefresh: Boolean, + isForceRefresh: Boolean, + alertCacheModel: AlertCacheModel + ): AlertsDataPack { + if (location.source == location.alertSource) { + return AlertsDataPack(alertCacheModel.cachedAlerts, location) + } else { + + val response = safeApiCall { + api.fetchWeather( + lat = location.latitude, + lon = location.longitude, + key = generateIrmKmiKey() + ) + }.getOrThrow() + + return AlertsDataPack( + alerts = response.toAlertsDomain(location.id), location + ) + } + } + + override suspend fun saveToDb( + data: AlertsDataPack, + alertCacheModel: AlertCacheModel + ) { + useGenericSaveImplementationForAlerts(data, alertsDao, dao) + } + + override fun finishedResult(data: List): FinishedAlertsResult { + return FinishedAlertsResult(alerts = data) + } + } + } + + override fun airQualityCapability(): AirQualityCapability? = null + } private fun generateIrmKmiKey(): String { diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/KmiWeatherConditionMap.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/KmiWeatherConditionMap.kt new file mode 100644 index 000000000..0cc704c4b --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/KmiWeatherConditionMap.kt @@ -0,0 +1,21 @@ +package com.pranshulgg.weather_master_app.core.network.sources.weather.kmi + +import com.pranshulgg.weather_master_app.core.model.weather.WeatherCondition + + +// Source - https://github.com/jdejaegh/irm-kmi-api/blob/a66c94a649885be3afd3081cb8cf595899b46ede/irm_kmi_api/const.py#L60 +object KmiWeatherConditionMap { + fun getCondition(id: Int?): WeatherCondition { + return when (id) { + 0, 1 -> WeatherCondition.CLEAR_SKY + 2, 5, 7, 10, 13, 17, 18, 21 -> WeatherCondition.RAIN + 3 -> WeatherCondition.PARTLY_CLOUDY + 4, 6, 16, 19 -> WeatherCondition.LIGHT_RAIN + 8, 9, 20 -> WeatherCondition.MIXED_PRECIPITATION + 11, 12, 22, 23 -> WeatherCondition.SNOW + 14, 15 -> WeatherCondition.OVERCAST + 24, 25, 26, 27 -> WeatherCondition.FOG_HAZE + else -> WeatherCondition.NO_CONDITION_FOUND + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/json/KmiWeatherJson.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/json/KmiWeatherJson.kt index ad775dd5b..d33611747 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/json/KmiWeatherJson.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/kmi/json/KmiWeatherJson.kt @@ -4,11 +4,22 @@ import com.google.gson.annotations.SerializedName data class KmiWeatherJson( val obs: KmiCurrentWeatherJson, - @SerializedName("for") val forecast: KmiForecastJson + @SerializedName("for") val forecast: KmiForecastJson, + val module: List +) + +data class KmiModuleJson( + val type: String, + val data: KmiModuleDataJson +) + +data class KmiModuleDataJson( + val levelValue: Double?, ) data class KmiCurrentWeatherJson( val temp: Double?, + val timestamp: String, val ww: Double?, ) @@ -27,7 +38,12 @@ data class KmiDayJson( @SerializedName("ddText") val windDirectionText: KmiDayWindDirectionJson, val wind: KmiDayWindJson, val precipChance: Double?, - val precipQuantity: String? + val precipQuantity: String?, + val dayName: KmiDayNameJson?, +) + +data class KmiDayNameJson( + val en: String? ) data class KmiDayWindDirectionJson( diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/accu/AccuJsonMapper.kt b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/accu/AccuJsonMapper.kt index b38cb0681..85b0da8a7 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/accu/AccuJsonMapper.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/accu/AccuJsonMapper.kt @@ -98,8 +98,7 @@ fun AccuWeatherBundle.toDomain(location: Location): Weather { val condition = computeDailyWeatherCondition(List(12) { AccuWeatherConditionMap.getCondition(item.day.icon) } + AccuWeatherConditionMap.getCondition( item.night.icon - ), - WeatherCondition.NO_CONDITION_FOUND) + ), WeatherCondition.NO_CONDITION_FOUND) val precipitationProbabilityMax = listOf( diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/kmi/KmiJsonMapper.kt b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/kmi/KmiJsonMapper.kt new file mode 100644 index 000000000..f38c77f80 --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/kmi/KmiJsonMapper.kt @@ -0,0 +1,183 @@ +package com.pranshulgg.weather_master_app.data.local.mapper.weather.sources.kmi + +import com.pranshulgg.weather_master_app.core.model.astro.MoonPhase +import com.pranshulgg.weather_master_app.core.model.domain.location.Location +import com.pranshulgg.weather_master_app.core.model.domain.weather.Weather +import com.pranshulgg.weather_master_app.core.model.domain.weather.WeatherCurrent +import com.pranshulgg.weather_master_app.core.model.domain.weather.WeatherDaily +import com.pranshulgg.weather_master_app.core.model.domain.weather.WeatherHourly +import com.pranshulgg.weather_master_app.core.model.weather.WeatherCondition +import com.pranshulgg.weather_master_app.core.model.weather.wind.WindDirection +import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.KmiWeatherConditionMap +import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.json.KmiDayJson +import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.json.KmiHourJson +import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.json.KmiWeatherJson +import com.pranshulgg.weather_master_app.core.utils.extensions.DateTimeExtensions.iso8601TimestampToMilliseconds +import com.pranshulgg.weather_master_app.core.utils.formatters.getCurrentTimeFor +import com.pranshulgg.weather_master_app.core.utils.formatters.safeZoneId +import com.pranshulgg.weather_master_app.core.utils.formatters.toSafeDouble +import com.pranshulgg.weather_master_app.core.utils.weather.astronomy.getMoonTimings +import com.pranshulgg.weather_master_app.core.utils.weather.astronomy.getSunTimings +import com.pranshulgg.weather_master_app.core.utils.weather.computing.computeDailyWeatherCondition +import com.pranshulgg.weather_master_app.core.utils.weather.forecast.findHourlyIndexForTime +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.OffsetDateTime +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter +import kotlin.math.roundToInt + +private fun getFixedHourlyTimings(data: List, zoneId: String): List { + var day = LocalDate.now(safeZoneId(zoneId)) + + return data.mapIndexed { index, hour -> + if (index > 0 && hour.dateShow != null) { + day = day.plusDays(1) + } + + val iso = LocalDateTime + .of( + day, + LocalTime.of(hour.hour.toSafeDouble()!!.toInt(), 0) + ) + .atZone(safeZoneId(zoneId)) + .withZoneSameInstant(ZoneOffset.UTC) + .format(DateTimeFormatter.ISO_INSTANT) + + iso.iso8601TimestampToMilliseconds() + } +} + + +fun KmiWeatherJson.toDomain(location: Location): Weather { + val zoneId = location.timezone + + val currentTime = getCurrentTimeFor(zoneId) + + val hourlyTimes = getFixedHourlyTimings(data = forecast.hourly, zoneId) + + val currentHourlyIndex = forecast.hourly[findHourlyIndexForTime( + hourlyTimes, + startMilli = currentTime + )] + + val obsTimestamp = OffsetDateTime.parse(obs.timestamp).toLocalDateTime() + + val resolvedDailyList = mutableListOf() + val day1 = forecast.daily.getOrNull(0) + val tonight = forecast.daily.find { it.dayName?.en == "Tonight" } + + // Merge today and tonight into 1 day + forecast.daily.forEach { + + if (it.period == "1" && tonight != null) { + return@forEach + } + if (it.dayName?.en == "Tonight" && day1 != null) { + val day = KmiDayJson( + period = "1", + tempMin = it.tempMin, + tempMax = day1.tempMax, + ww1 = day1.ww1, + ww2 = it.ww1, + windDirectionText = it.windDirectionText, // BOTH are usually same + wind = it.wind, // BOTH are usually same, + precipChance = listOf(it.precipChance ?: 0.0, day1.precipChance ?: 0.0).max(), + precipQuantity = it.precipQuantity.plus(day1.precipQuantity), + dayName = day1.dayName + ) + + resolvedDailyList.add(day) + } else { + resolvedDailyList.add(it) + } + } + + val dailyTimings = List(resolvedDailyList.size) { index -> + obsTimestamp.plusDays(index.toLong()).atZone(safeZoneId(zoneId)) + .withZoneSameInstant(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT) + .iso8601TimestampToMilliseconds() + } + + val sunTimings = + getSunTimings(dailyTimings, location.timezone, location.latitude, location.longitude) + val moonTimings = + getMoonTimings(dailyTimings, location.timezone, location.latitude, location.longitude) + + return Weather( + location = location, + current = WeatherCurrent( + temperature = obs.temp ?: currentHourlyIndex.temp, + humidity = null, + windSpeed = currentHourlyIndex.windSpeedKm, + windDirection = WindDirection.toWindDirectionFromString(currentHourlyIndex.windDirectionText.en), + pressureMsl = currentHourlyIndex.pressure, + visibility = null, + cloudCover = null, + uvIndex = module.firstOrNull { it.type == "uv" }?.data?.levelValue, + weatherCondition = KmiWeatherConditionMap.getCondition(currentHourlyIndex.ww?.toInt()), + feelsLike = null, + dewPoint = null, + utcOffsetSeconds = null, + lastUpdatedInMilli = System.currentTimeMillis() + ), + hourly = forecast.hourly.mapIndexed { index, item -> + + val time = hourlyTimes[index] + + WeatherHourly( + temperature = item.temp, + windSpeed = item.windSpeedKm, + windDirection = WindDirection.toWindDirectionFromString(item.windDirectionText.en), + rain = item.precipQuantity ?: 0.0, + snowfall = null, + uvIndex = null, + pressureMsl = item.pressure, + visibility = null, + humidity = null, + dewPoint = null, + weatherCondition = KmiWeatherConditionMap.getCondition(item.ww?.toInt()), + time = time, + precipitationProbability = item.precipChance.toSafeDouble()?.roundToInt() + ) + }, + daily = resolvedDailyList.mapIndexed { index, day -> + + val time = obsTimestamp.plusDays(index.toLong()).atZone(safeZoneId(zoneId)) + .withZoneSameInstant(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT) + .iso8601TimestampToMilliseconds() + + val condition = + computeDailyWeatherCondition(List(12) { KmiWeatherConditionMap.getCondition(day.ww1?.toInt()) } + + KmiWeatherConditionMap.getCondition(day.ww2?.toInt()), + WeatherCondition.NO_CONDITION_FOUND) + + + WeatherDaily( + temperatureMin = day.tempMin, + temperatureMax = day.tempMax, + windSpeed = day.wind.speed, + windDirection = WindDirection.toWindDirectionFromString(day.windDirectionText.en), + rainSum = day.precipQuantity.toSafeDouble() ?: 0.0, + snowfallSum = null, + uvIndexMax = null, + weatherCondition = condition, + time = time, + precipitationProbabilityMax = day.precipChance?.roundToInt() ?: 0, + pressureMsl = null, + visibility = null, + humidity = null, + dewPoint = null, + sunrise = sunTimings.getOrNull(index)?.sunrise, + sunset = sunTimings.getOrNull(index)?.sunset, + dawn = sunTimings.getOrNull(index)?.dawn, + dusk = sunTimings.getOrNull(index)?.dusk, + moonrise = moonTimings.getOrNull(index)?.moonrise, + moonset = moonTimings.getOrNull(index)?.moonset, + moonPhase = moonTimings.getOrNull(index)?.phase ?: MoonPhase.UNKNOWN, + ) + } + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/kmi/alerts/KmiAlertsMapper.kt b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/kmi/alerts/KmiAlertsMapper.kt new file mode 100644 index 000000000..bafd7f6a5 --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/kmi/alerts/KmiAlertsMapper.kt @@ -0,0 +1,38 @@ +package com.pranshulgg.weather_master_app.data.local.mapper.weather.sources.kmi.alerts + +import com.pranshulgg.weather_master_app.core.model.domain.alerts.Alert +import com.pranshulgg.weather_master_app.core.model.weather.alerts.AlertSeverity +import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.json.KmiWeatherJson +import com.pranshulgg.weather_master_app.core.utils.extensions.DateTimeExtensions.iso8601TimestampToMilliseconds + + +fun KmiWeatherJson.toAlertsDomain(locationId: String): List { + + val alerts = forecast.warning + + return alerts.mapIndexed { index, alert -> + Alert( + locationId = locationId, + event = alert.warningType.en ?: "", + severity = getSeverity(alert.warningLevel), + effective = alert.fromTimestamp?.iso8601TimestampToMilliseconds(), + expires = alert.toTimestamp?.iso8601TimestampToMilliseconds(), + description = alert.text.en ?: "", + source = "Royal Meteorological Institute of Belgium", + lastUpdatedInMilli = System.currentTimeMillis() + ) + } + +} + + +// Not tested if the severity is correct or not +private fun getSeverity(waringLevel: Double?): AlertSeverity { + return when (waringLevel) { + 3.0 -> AlertSeverity.CRITICAL + 2.0 -> AlertSeverity.HIGH + 1.0 -> AlertSeverity.MODERATE + 0.0 -> AlertSeverity.LOW + else -> AlertSeverity.UNKNOWN + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/data/provider/SourceRepositoryProvider.kt b/app/src/main/java/com/pranshulgg/weather_master_app/data/provider/SourceRepositoryProvider.kt index 72da7e06c..9d4954386 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/data/provider/SourceRepositoryProvider.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/data/provider/SourceRepositoryProvider.kt @@ -17,6 +17,7 @@ import com.pranshulgg.weather_master_app.core.network.sources.weather.imd.ImdRep import com.pranshulgg.weather_master_app.core.network.sources.weather.inmet.InmetRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.ipma.IpmaRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.jma.JmaRepository +import com.pranshulgg.weather_master_app.core.network.sources.weather.kmi.KmiRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.meteoam.MeteoamRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofrance.MeteoFranceRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.metnorway.MetNorwayRepository @@ -56,6 +57,7 @@ class SourceRepositoryProvider @Inject constructor( private val inmetRepository: InmetRepository, private val openWeatherRepository: OpenWeatherRepository, private val mgmRepository: MgmRepository, + private val kmiRepository: KmiRepository, // ALERTS private val alertsWeatherApiRepository: AlertsWeatherApiRepository, @@ -90,7 +92,8 @@ class SourceRepositoryProvider @Inject constructor( wmoSevereWeatherRepository, fpasRepository, openWeatherRepository, - mgmRepository + mgmRepository, + kmiRepository ) fun getWeatherRepository(source: Source): WeatherRepository { diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/data/repository/data/BaseRepository.kt b/app/src/main/java/com/pranshulgg/weather_master_app/data/repository/data/BaseRepository.kt index 43a33558b..8b65a6515 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/data/repository/data/BaseRepository.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/data/repository/data/BaseRepository.kt @@ -100,7 +100,8 @@ abstract class BaseRepository : WeatherRepository, AlertRepository, AirQualityRe } catch (e: Exception) { return@withContext WeatherResult.Error( exception = e.toAppException(), - weather = cache + weather = cache, + rawException = e ) } @@ -152,6 +153,7 @@ abstract class BaseRepository : WeatherRepository, AlertRepository, AirQualityRe } else AlertsDataPack(alerts = cache, location = location) } catch (e: Exception) { + return@withContext AlertResult.Error( exception = e.toAppException(), alerts = cache diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fa3864c7f..e734697a0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -551,7 +551,7 @@ Please wait 15 minutes before refreshing Turkey - + Belgium