mirror of
https://github.com/PranshulGG/WeatherMaster.git
synced 2026-10-23 03:24:11 -05:00
add ECCC weather source and refactor weather source settings screen closes #875
This commit is contained in:
1 parent
cc026da135
commit
0fdb62ee64
11 files changed
+433
-88
No files matched your search
@@ -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()
|
||||
}
|
||||
+10
@@ -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)
|
||||
}
|
||||
+21
-12
@@ -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<WeatherSource> {
|
||||
|
||||
+55
@@ -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<List<EcccWeatherJson>>
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+80
@@ -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
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+92
@@ -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<EcccHourlyWeatherItemJson>
|
||||
)
|
||||
|
||||
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<EcccDailyWeatherItemJson>
|
||||
)
|
||||
|
||||
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?,
|
||||
)
|
||||
|
||||
-4
@@ -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 {
|
||||
|
||||
+132
@@ -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()
|
||||
}
|
||||
+4
-1
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-71
@@ -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)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user