From 0fdb62ee64fb3c795a4004d0b1732cd2e73b72f2 Mon Sep 17 00:00:00 2001 From: PranshulGG Date: Fri, 12 Jun 2026 16:29:41 +0530 Subject: [PATCH] add ECCC weather source and refactor weather source settings screen closes #875 --- .../core/di/network/ApiModule.kt | 5 + .../di/weather/WeatherRepositoryModule.kt | 10 ++ .../core/model/sources/WeatherSource.kt | 33 +++-- .../network/sources/weather/eccc/EcccApi.kt | 55 ++++++++ .../sources/weather/eccc/EcccConditionMap.kt | 22 +++ .../sources/weather/eccc/EcccRepository.kt | 80 +++++++++++ .../weather/eccc/json/EcccWeatherJson.kt | 92 ++++++++++++ .../data/local/WeatherMasterDatabase.kt | 4 - .../weather/sources/eccc/EcccJsonMapper.kt | 132 ++++++++++++++++++ .../provider/WeatherRepositoryProvider.kt | 5 +- .../settings/sources/WeatherSourcesScreen.kt | 83 ++--------- 11 files changed, 433 insertions(+), 88 deletions(-) create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccApi.kt create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccConditionMap.kt create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccRepository.kt create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/json/EcccWeatherJson.kt create mode 100644 app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/eccc/EcccJsonMapper.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 1d3397efe..b143bb828 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 @@ -7,6 +7,7 @@ import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.Ge import com.pranshulgg.weather_master_app.core.network.sources.search.geonames.timezone.GeoNamesTimezoneApi import com.pranshulgg.weather_master_app.core.network.sources.search.openmeteo.OpenMeteoSearchApi import com.pranshulgg.weather_master_app.core.network.sources.weather.dwd.DwdApi +import com.pranshulgg.weather_master_app.core.network.sources.weather.eccc.EcccApi import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofrance.MeteoFranceApi import com.pranshulgg.weather_master_app.core.network.sources.weather.metnorway.MetNorwayApi import com.pranshulgg.weather_master_app.core.network.sources.weather.nws.NwsApi @@ -69,4 +70,8 @@ object ApiModule { @Provides @Singleton fun provideMeteoFranceApi(): MeteoFranceApi = MeteoFranceApi.create() + + @Provides + @Singleton + fun provideEcccApi(): EcccApi = EcccApi.create() } \ No newline at end of file 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 b43f1cd35..96a547338 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 @@ -4,6 +4,8 @@ import com.pranshulgg.weather_master_app.core.network.sources.airquality.openmet import com.pranshulgg.weather_master_app.core.network.sources.airquality.openmeteo.OpenMeteoAqiRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.dwd.DwdApi import com.pranshulgg.weather_master_app.core.network.sources.weather.dwd.DwdRepository +import com.pranshulgg.weather_master_app.core.network.sources.weather.eccc.EcccApi +import com.pranshulgg.weather_master_app.core.network.sources.weather.eccc.EcccRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofrance.MeteoFranceApi import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofrance.MeteoFranceRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.metnorway.MetNorwayApi @@ -83,4 +85,12 @@ object WeatherRepositoryModule { api: MeteoFranceApi, weatherDao: WeatherDao ): MeteoFranceRepository = MeteoFranceRepository(dao, weatherDao, api) + + @Provides + @Singleton + fun provideEcccRepository( + dao: LocationsDao, + api: EcccApi, + weatherDao: WeatherDao + ): EcccRepository = EcccRepository(dao, weatherDao, api) } \ No newline at end of file diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/model/sources/WeatherSource.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/model/sources/WeatherSource.kt index 5d2117c9e..f256e980b 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/core/model/sources/WeatherSource.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/model/sources/WeatherSource.kt @@ -2,40 +2,47 @@ package com.pranshulgg.weather_master_app.core.model.sources enum class WeatherSource( val displayName: String, - val hourlyAggregationLimitHours: Int, // stupid - val displayLink: String + val hourlyAggregationLimitHours: Int = 24, // stupid and should be removed + val displayLink: String, + val fullName: String, ) { OPEN_METEO( displayName = "Open Meteo", - hourlyAggregationLimitHours = 24, + fullName = "Open Meteo", displayLink = "https://open-meteo.com/" ), NWS( - displayName = "National Weather Service", - hourlyAggregationLimitHours = 24, + displayName = "NWS (United States)", + fullName = "National Weather Service", displayLink = "https://www.weather.gov/documentation/services-web-api" ), SMHI( displayName = "SMHI (Sweden)", - hourlyAggregationLimitHours = 24, + fullName = "Swedish Meteorological and Hydrological Institute", displayLink = "https://opendata.smhi.se" ), DWD( - displayName = "Bright Sky DWD (Germany)", - hourlyAggregationLimitHours = 24, + displayName = "DWD (Germany)", + fullName = "Bright Sky DWD", displayLink = "https://brightsky.dev" ), METEO_FRANCE( displayName = "Météo-France", - hourlyAggregationLimitHours = 24, + fullName = "Météo-France", displayLink = "https://meteofrance.com/" ), + ECCC( + displayName = "ECCC (Canada)", + fullName = "Environment and Climate Change Canada", + displayLink = "https://app.weather.gc.ca/", + ), MET_NORWAY( displayName = "Met Norway", - hourlyAggregationLimitHours = 24, - "https://api.met.no/" + fullName = "Met Norway", + displayLink = "https://api.met.no/" ); + // Sources that provide snow/rain as precipitation fun providesSnowFall(): Boolean { return when (this) { MET_NORWAY -> false @@ -47,10 +54,12 @@ enum class WeatherSource( // WE MAP EVERY WEATHER SOURCE HERE, AS THEY GET ADDED + private val weatherSourcesByCountry = mapOf( "US" to listOf(WeatherSource.NWS), "SE" to listOf(WeatherSource.SMHI), - "DE" to listOf(WeatherSource.DWD) + "DE" to listOf(WeatherSource.DWD), + "CA" to listOf(WeatherSource.ECCC) ) fun getWeatherSourcesForCountry(countryCode: String?): List { diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccApi.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccApi.kt new file mode 100644 index 000000000..7585ce4ea --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccApi.kt @@ -0,0 +1,55 @@ +package com.pranshulgg.weather_master_app.core.network.sources.weather.eccc + +import com.pranshulgg.weather_master_app.core.network.sources.weather.eccc.json.EcccWeatherJson +import com.pranshulgg.weather_master_app.core.network.sources.weather.smhi.json.SmhiForecastJson +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Response +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.http.GET +import retrofit2.http.Path +import java.util.concurrent.TimeUnit + + +interface EcccApi { + + + @GET("v3/en/Location/{latitude},{longitude}") + suspend fun fetchWeather( + @Path("latitude") latitude: Double, + @Path("longitude") longitude: Double, + ): Response> + + + companion object { + const val BASE_URL = "https://app.weather.gc.ca/" + + fun create(): EcccApi { + + + val client = OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .addInterceptor { chain -> + val request = chain.request().newBuilder() + .header( + "User-Agent", + "WeatherMaster (com.pranshulgg.weathermaster; pranshul.devmain@gmail.com)" + ) + .build() + + chain.proceed(request) + } + .readTimeout(30, TimeUnit.SECONDS) + .build() + + return Retrofit.Builder() + .baseUrl(BASE_URL) + .client(client) + .addConverterFactory(GsonConverterFactory.create()) + .build() + .create(EcccApi::class.java) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccConditionMap.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccConditionMap.kt new file mode 100644 index 000000000..ab68fda5a --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccConditionMap.kt @@ -0,0 +1,22 @@ +package com.pranshulgg.weather_master_app.core.network.sources.weather.eccc + +import com.pranshulgg.weather_master_app.core.model.weather.WeatherCondition + +object EcccConditionMap { + fun getCondition(icon: String?): WeatherCondition { + return when (icon) { + "00", "01", "30", "31" -> WeatherCondition.CLEAR_SKY + "02", "03", "04", "05", "22", "32", "33", "34", "35" -> WeatherCondition.PARTLY_CLOUDY + "10", "20", "21" -> WeatherCondition.OVERCAST + "06", "11", "12", "13", "28", "36" -> WeatherCondition.RAIN + "14", "27" -> WeatherCondition.SNOW // SHOULD BE HAIL + "07", "15", "37" -> WeatherCondition.SNOW // SHOULD BE SLEET + "08", "16", "17", "18", "26", "38" -> WeatherCondition.SNOW + "09", "19", "39", "46", "47" -> WeatherCondition.THUNDERSTORM + "23", "44", "45", "24" -> WeatherCondition.FOG_HAZE + "25", "40", "41", "42", "43", "48" -> WeatherCondition.CLEAR_SKY // SHOULD BE WIND + else -> WeatherCondition.NO_CONDITION_FOUND + } + } + +} diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccRepository.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccRepository.kt new file mode 100644 index 000000000..60d7052a1 --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/EcccRepository.kt @@ -0,0 +1,80 @@ +package com.pranshulgg.weather_master_app.core.network.sources.weather.eccc + +import com.pranshulgg.weather_master_app.core.model.domain.location.Location +import com.pranshulgg.weather_master_app.core.model.weather.WeatherResult +import com.pranshulgg.weather_master_app.core.model.weather.WeatherResultType +import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofrance.MeteoFranceApi +import com.pranshulgg.weather_master_app.core.utils.weather.cache.isWeatherCacheSafe +import com.pranshulgg.weather_master_app.core.utils.weather.cache.shouldReturnWeatherCache +import com.pranshulgg.weather_master_app.data.local.dao.location.LocationsDao +import com.pranshulgg.weather_master_app.data.local.dao.weather.WeatherDao +import com.pranshulgg.weather_master_app.data.local.mapper.weather.sources.eccc.toDomain +import com.pranshulgg.weather_master_app.data.local.mapper.weather.sources.meteofrance.toDomain +import com.pranshulgg.weather_master_app.data.local.mapper.weather.toCurrentWeatherEntity +import com.pranshulgg.weather_master_app.data.local.mapper.weather.toDailyWeatherEntity +import com.pranshulgg.weather_master_app.data.local.mapper.weather.toDomain +import com.pranshulgg.weather_master_app.data.local.mapper.weather.toHourlyWeatherEntity +import com.pranshulgg.weather_master_app.data.repository.WeatherRepository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import java.net.UnknownHostException +import javax.inject.Inject + + +class EcccRepository @Inject constructor( + val dao: LocationsDao, + val weatherDao: WeatherDao, + val api: EcccApi +) : WeatherRepository { + + override suspend fun getWeather( + location: Location, + isManualRefresh: Boolean, + isForceRefresh: Boolean + ): WeatherResult = + withContext( + Dispatchers.IO + ) { + + val cache = dao.getWeatherDataForLocation(location.id) + + val shouldReturnCache = shouldReturnWeatherCache(cache, isManualRefresh, isForceRefresh) + + when (shouldReturnCache) { + WeatherResultType.REFRESH_TOO_EARLY -> return@withContext WeatherResult.RefreshNotAvailable + WeatherResultType.SUCCESS -> return@withContext WeatherResult.Success(cache!!.toDomain()) + else -> {} + } + + return@withContext try { + + + val response = api.fetchWeather(location.latitude, location.longitude) + + val body = + response.body()?.firstOrNull() + ?: return@withContext WeatherResult.Error(exception = UnknownHostException()) + + + val domain = body.toDomain(location) + + weatherDao.insertWeather( + domain.current.toCurrentWeatherEntity(location.id), + domain.hourly.toHourlyWeatherEntity(location.id), + domain.daily.toDailyWeatherEntity(location.id), + location.id + ) + WeatherResult.Success(domain) + + } catch (e: Exception) { + + val isCacheSafe = isWeatherCacheSafe(cache) + + WeatherResult.Error( + exception = e, + if (isCacheSafe) cache?.toDomain() else null + ) + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/json/EcccWeatherJson.kt b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/json/EcccWeatherJson.kt new file mode 100644 index 000000000..5f9cdab10 --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/core/network/sources/weather/eccc/json/EcccWeatherJson.kt @@ -0,0 +1,92 @@ +package com.pranshulgg.weather_master_app.core.network.sources.weather.eccc.json + +import com.google.gson.annotations.SerializedName + +data class EcccWeatherJson( + val observation: EcccCurrentWeatherJson, + val hourlyFcst: EcccHourlyWeatherJson, + val dailyFcst: EcccDailyWeatherJson, +) + +// CURRENT +data class EcccCurrentWeatherJson( + val iconCode: String, + val timeStamp: String, + val temperature: EcccCurrentWeatherTemperatureJson, + val dewpoint: EcccCurrentWeatherDewPointJson, + val feelsLike: EcccCurrentWeatherFeelsLikeJson, + val pressure: EcccCurrentWeatherPressureJson, + val visibility: EcccCurrentWeatherVisibilityJson, + val humidity: String?, + val windDirection: String?, + val windSpeed: EcccCurrentWeatherWindSpeedJson +) + +data class EcccCurrentWeatherTemperatureJson( + val metric: String?, +) + +data class EcccCurrentWeatherDewPointJson( + val metric: String?, +) + +data class EcccCurrentWeatherFeelsLikeJson( + val metric: String?, +) + +data class EcccCurrentWeatherPressureJson( + val imperial: String?, +) + +data class EcccCurrentWeatherVisibilityJson( + val metric: String?, +) + +data class EcccCurrentWeatherWindSpeedJson( + val metric: String?, +) + +// HOURLY + +data class EcccHourlyWeatherJson( + val hourly: List +) + +data class EcccHourlyWeatherItemJson( + val epochTime: Long, + val windDir: String?, + val temperature: EcccHourlyWeatherItemTemperatureJson, + @SerializedName("precip") val precipProbability: String?, + val iconCode: String, + val windSpeed: EcccHourlyWeatherItemWindSpeedJson + + +) + +data class EcccHourlyWeatherItemTemperatureJson( + val metric: String?, +) + +data class EcccHourlyWeatherItemWindSpeedJson( + val metric: String?, +) + +// DAILY + +data class EcccDailyWeatherJson( + val daily: List +) + +data class EcccDailyWeatherItemJson( + val date: String, + val temperature: EcccDailyWeatherItemTemperatureJson, + @SerializedName("precip") val precipProbability: String?, + val iconCode: String, + val periodLabel: String, + + ) + +data class EcccDailyWeatherItemTemperatureJson( + val metric: String?, +) + diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/data/local/WeatherMasterDatabase.kt b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/WeatherMasterDatabase.kt index 6e4bbfb71..662d97200 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/data/local/WeatherMasterDatabase.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/WeatherMasterDatabase.kt @@ -42,13 +42,9 @@ abstract class WeatherMasterDatabase : RoomDatabase() { abstract fun locationsDao(): LocationsDao abstract fun weatherDao(): WeatherDao - abstract fun weatherUnitsDao(): WeatherUnitsDao - abstract fun weatherBlocksDao(): WeatherBlocksDao - abstract fun airQualityDao(): AirQualityDao - abstract fun nwsDao(): NwsDao companion object { diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/eccc/EcccJsonMapper.kt b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/eccc/EcccJsonMapper.kt new file mode 100644 index 000000000..e8810c0c7 --- /dev/null +++ b/app/src/main/java/com/pranshulgg/weather_master_app/data/local/mapper/weather/sources/eccc/EcccJsonMapper.kt @@ -0,0 +1,132 @@ +package com.pranshulgg.weather_master_app.data.local.mapper.weather.sources.eccc + +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.DistanceUnit +import com.pranshulgg.weather_master_app.core.model.weather.PressureUnit +import com.pranshulgg.weather_master_app.core.model.weather.wind.WindDirection +import com.pranshulgg.weather_master_app.core.network.sources.weather.eccc.EcccConditionMap +import com.pranshulgg.weather_master_app.core.network.sources.weather.eccc.json.EcccWeatherJson +import com.pranshulgg.weather_master_app.core.utils.extensions.DateTimeExtensions.iso8601TimestampToMilliseconds +import com.pranshulgg.weather_master_app.core.utils.extensions.DateTimeExtensions.normalizeToDay +import com.pranshulgg.weather_master_app.core.utils.extensions.DateTimeExtensions.secondsToMilliseconds +import com.pranshulgg.weather_master_app.core.utils.formatters.safeZoneId +import com.pranshulgg.weather_master_app.core.utils.weather.astronomy.getMoonTimings +import com.pranshulgg.weather_master_app.core.utils.weather.astronomy.getSunTimings +import java.time.LocalDate +import java.time.Year +import java.time.ZoneId +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter +import java.util.Locale +import kotlin.math.roundToInt + + +fun EcccWeatherJson.toDomain(location: Location): Weather { + val current = this.observation + val hourly = this.hourlyFcst.hourly + + + val dailyNight = + this.dailyFcst.daily.filter { it.periodLabel == "Night" || it.periodLabel == "Tonight" } + + val daily = + this.dailyFcst.daily.filter { it.periodLabel != "Night" && it.periodLabel != "Tonight" } + .take(dailyNight.size) + + val sunTimings = getSunTimings( + daily.map { + dateToMillis(it.date, location.timezone) + }, + location.timezone, + location.latitude, + location.longitude + ) + + val moonTimings = getMoonTimings( + daily.map { + dateToMillis(it.date, location.timezone) + }, + location.timezone, + location.latitude, + location.longitude + ) + + + return Weather( + location = location, + current = WeatherCurrent( + temperature = current.temperature.metric?.toDoubleOrNull(), + humidity = current.humidity?.toDouble() ?: 0.0, + windSpeed = current.windSpeed.metric?.toDoubleOrNull(), + windDirection = WindDirection.toWindDirectionFromString(current.windDirection), + pressureMsl = PressureUnit.INHG.convert( + current.pressure.imperial?.toDoubleOrNull(), + PressureUnit.HPA + ), + visibility = DistanceUnit.KM.convert( + current.visibility.metric?.toDouble(), + DistanceUnit.M + )?.roundToInt(), + cloudCover = null, // NOT USED IN THE APP + uvIndex = null, + weatherCondition = EcccConditionMap.getCondition(current.iconCode), + feelsLike = current.feelsLike.metric?.toDoubleOrNull(), + time = current.timeStamp.iso8601TimestampToMilliseconds(), + dewPoint = current.dewpoint.metric?.toDoubleOrNull(), + utcOffsetSeconds = null, + lastUpdatedInMilli = System.currentTimeMillis() + ), + hourly = hourly.map { + WeatherHourly( + temperature = it.temperature.metric?.toDoubleOrNull(), + windSpeed = it.windSpeed.metric?.toDoubleOrNull(), + windDirection = WindDirection.toWindDirectionFromString(it.windDir), + rain = 0.0, // NULL + snowfall = null, + uvIndex = null, + pressureMsl = null, + visibility = null, + humidity = null, + dewPoint = null, + weatherCondition = EcccConditionMap.getCondition(it.iconCode), + time = it.epochTime.secondsToMilliseconds(), + precipitationProbability = it.precipProbability?.toIntOrNull() + ) + }, + daily = daily.mapIndexed { index, it -> + WeatherDaily( + temperatureMin = dailyNight[index].temperature.metric?.toDoubleOrNull(), + temperatureMax = it.temperature.metric?.toDoubleOrNull(), + windSpeed = null, + windDirection = null, + rainSum = 0.0, + snowfallSum = null, + uvIndexMax = null, + weatherCondition = EcccConditionMap.getCondition(it.iconCode), + time = dateToMillis(it.date, location.timezone), + precipitationProbabilityMax = it.precipProbability?.toIntOrNull(), + sunrise = sunTimings[index].sunrise ?: -0L, + sunset = sunTimings[index].sunset ?: -0L, + moonrise = moonTimings[index].moonrise ?: -0L, + moonset = moonTimings[index].moonset ?: -0L, + moonPhase = moonTimings[index].phase, + dawn = sunTimings[index].dawn ?: 0L, + dusk = sunTimings[index].dusk ?: 0L + ) + } + ) +} + +private fun dateToMillis(dateStr: String, zoneId: String): Long { + val dateWithYear = "$dateStr ${Year.now().value}" + + val formatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy", Locale.ENGLISH) + + val localDate = LocalDate.parse(dateWithYear, formatter) + + return localDate.atStartOfDay(safeZoneId(zoneId)).toInstant().toEpochMilli() +} \ No newline at end of file diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/data/provider/WeatherRepositoryProvider.kt b/app/src/main/java/com/pranshulgg/weather_master_app/data/provider/WeatherRepositoryProvider.kt index a823284dc..362fa1bb0 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/data/provider/WeatherRepositoryProvider.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/data/provider/WeatherRepositoryProvider.kt @@ -2,6 +2,7 @@ package com.pranshulgg.weather_master_app.data.provider import com.pranshulgg.weather_master_app.core.model.sources.WeatherSource import com.pranshulgg.weather_master_app.core.network.sources.weather.dwd.DwdRepository +import com.pranshulgg.weather_master_app.core.network.sources.weather.eccc.EcccRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.meteofrance.MeteoFranceRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.metnorway.MetNorwayRepository import com.pranshulgg.weather_master_app.core.network.sources.weather.nws.NwsRepository @@ -16,7 +17,8 @@ class WeatherRepositoryProvider @Inject constructor( private val metNorwayRepository: MetNorwayRepository, private val smhiRepository: SmhiRepository, private val dwdRepository: DwdRepository, - private val meteoFranceRepository: MeteoFranceRepository + private val meteoFranceRepository: MeteoFranceRepository, + private val ecccRepository: EcccRepository ) { fun getRepository(source: WeatherSource): WeatherRepository { @@ -27,6 +29,7 @@ class WeatherRepositoryProvider @Inject constructor( WeatherSource.SMHI -> smhiRepository WeatherSource.DWD -> dwdRepository WeatherSource.METEO_FRANCE -> meteoFranceRepository + WeatherSource.ECCC -> ecccRepository } } diff --git a/app/src/main/java/com/pranshulgg/weather_master_app/feature/settings/sources/WeatherSourcesScreen.kt b/app/src/main/java/com/pranshulgg/weather_master_app/feature/settings/sources/WeatherSourcesScreen.kt index bbf69d095..ef6a97187 100644 --- a/app/src/main/java/com/pranshulgg/weather_master_app/feature/settings/sources/WeatherSourcesScreen.kt +++ b/app/src/main/java/com/pranshulgg/weather_master_app/feature/settings/sources/WeatherSourcesScreen.kt @@ -47,80 +47,21 @@ fun WeatherSourcesScreen(navController: NavController) { modifier = Modifier.padding(horizontal = 16.dp) ) Gap(12.dp) - SettingSection( - title = "Open Meteo (GLOBAL)", - tiles = listOf( - SettingTile.ActionTile( - title = WeatherSource.OPEN_METEO.displayName, - description = WeatherSource.OPEN_METEO.displayLink, - onClick = { uriHandler.openUri(WeatherSource.OPEN_METEO.displayLink) }, - trailing = { SettingsTileIcon(R.drawable.open_in_new_24px) } + WeatherSource.entries.forEach { + SettingSection( + title = it.displayName, + tiles = listOf( + SettingTile.ActionTile( + title = it.fullName, + description = it.displayLink, + onClick = { uriHandler.openUri(it.displayLink) }, + trailing = { SettingsTileIcon(R.drawable.open_in_new_24px) } + ) ) ) - ) - Gap(10.dp) - SettingSection( - title = "Met Norway (GLOBAL)", - tiles = listOf( - SettingTile.ActionTile( - title = WeatherSource.MET_NORWAY.displayName, - description = WeatherSource.MET_NORWAY.displayLink, - onClick = { uriHandler.openUri(WeatherSource.MET_NORWAY.displayLink) }, - trailing = { SettingsTileIcon(R.drawable.open_in_new_24px) } - ) - ) - ) - Gap(10.dp) - SettingSection( - title = "NWS (United states)", - tiles = listOf( - SettingTile.ActionTile( - title = WeatherSource.NWS.displayName, - description = WeatherSource.NWS.displayLink, - onClick = { uriHandler.openUri(WeatherSource.NWS.displayLink) }, - trailing = { SettingsTileIcon(R.drawable.open_in_new_24px) } - ) - ) - ) - - Gap(10.dp) - SettingSection( - title = "SMHI (Sweden)", - tiles = listOf( - SettingTile.ActionTile( - title = WeatherSource.SMHI.displayName, - description = WeatherSource.SMHI.displayLink, - onClick = { uriHandler.openUri(WeatherSource.SMHI.displayLink) }, - trailing = { SettingsTileIcon(R.drawable.open_in_new_24px) } - ) - ) - ) - Gap(10.dp) - SettingSection( - title = "DWD (Germany)", - tiles = listOf( - SettingTile.ActionTile( - title = WeatherSource.DWD.displayName, - description = WeatherSource.DWD.displayLink, - onClick = { uriHandler.openUri(WeatherSource.DWD.displayLink) }, - trailing = { SettingsTileIcon(R.drawable.open_in_new_24px) } - ) - ) - ) - Gap(10.dp) - SettingSection( - title = WeatherSource.METEO_FRANCE.displayName, - tiles = listOf( - SettingTile.ActionTile( - title = WeatherSource.METEO_FRANCE.displayName, - description = WeatherSource.METEO_FRANCE.displayLink, - onClick = { uriHandler.openUri(WeatherSource.METEO_FRANCE.displayLink) }, - trailing = { SettingsTileIcon(R.drawable.open_in_new_24px) } - ) - ) - ) + Gap(10.dp) + } Gap(WindowInsets.systemBars.asPaddingValues().calculateBottomPadding() + 30.dp) - } } }