diff --git a/app/build.gradle b/app/build.gradle index d46ea751..aef9c96b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -152,7 +152,7 @@ dependencies { def OKHTTP_VERSION = "4.2.2" def OKIO_VERSION = "2.6.0" def OSMDROID_VERSION = "6.1.2" - def PERMISSIONS_DISPATCHER_VERSION = "4.7.0" + def PERMISSIONS_DISPATCHER_VERSION = "4.8.0" def PREFERENCE_VERSION = "1.1.1" def RETROFIT_VERSION = "2.9.0" def ROOM_VERSION = "2.2.5" @@ -234,8 +234,8 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${KOTLIN_STDLIB_VERSION}" implementation "org.osmdroid:osmdroid-android:${OSMDROID_VERSION}" implementation "io.github.sphrak:either:${EITHER_VERSION}" - implementation "org.permissionsdispatcher:permissionsdispatcher:${PERMISSIONS_DISPATCHER_VERSION}" - kapt "org.permissionsdispatcher:permissionsdispatcher-processor:${PERMISSIONS_DISPATCHER_VERSION}" + implementation "com.github.permissions-dispatcher:permissionsdispatcher:${PERMISSIONS_DISPATCHER_VERSION}" + kapt "com.github.permissions-dispatcher:permissionsdispatcher-processor:${PERMISSIONS_DISPATCHER_VERSION}" // Datetime implementation "com.jakewharton.threetenabp:threetenabp:${THREETEN_ABP_VERSION}" @@ -275,3 +275,12 @@ tasks.register("ktlintFormat", JavaExec) { repositories { mavenCentral() } + +// The google-services plugin is applied unconditionally but only the google +// flavor actually uses Firebase. Disable the processing task for all other +// flavors so contributors can build without a google-services.json file. +tasks.configureEach { task -> + if (task.name ==~ /process(Fdroid|Github).*GoogleServices/) { + task.enabled = false + } +} diff --git a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/Geometry.kt b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/Geometry.kt index caa8445d..bdc59a38 100644 --- a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/Geometry.kt +++ b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/Geometry.kt @@ -8,5 +8,5 @@ data class Geometry( @SerialName(value = "type") val type: String = "Point", @SerialName(value = "coordinates") - val coordinates: List> + val coordinates: List ) \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/Parameter.kt b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/Parameter.kt deleted file mode 100644 index 39096015..00000000 --- a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/Parameter.kt +++ /dev/null @@ -1,23 +0,0 @@ -package fi.kroon.vadret.data.weatherforecast.model - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class Parameter( - - @SerialName(value = "name") - val name: String, - - @SerialName(value = "levelType") - val levelType: String, - - @SerialName(value = "level") - val level: Int, - - @SerialName(value = "unit") - val unit: String, - - @SerialName(value = "values") - val values: List = emptyList() -) \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/TimeSerie.kt b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/TimeSerie.kt index 06b7b578..cb5d6c34 100644 --- a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/TimeSerie.kt +++ b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/TimeSerie.kt @@ -5,8 +5,8 @@ import kotlinx.serialization.Serializable @Serializable data class TimeSerie( - @SerialName(value = "validTime") - val validTime: String, - @SerialName(value = "parameters") - val parameters: List = emptyList() -) \ No newline at end of file + @SerialName(value = "time") + val time: String, + @SerialName(value = "data") + val data: WeatherData +) diff --git a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/Weather.kt b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/Weather.kt index 387d27c3..7508dde7 100644 --- a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/Weather.kt +++ b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/Weather.kt @@ -6,8 +6,8 @@ import kotlinx.serialization.Serializable @Serializable data class Weather( - @SerialName(value = "approvedTime") - val approvedTime: String, + @SerialName(value = "createdTime") + val createdTime: String, @SerialName(value = "referenceTime") val referenceTime: String, diff --git a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/WeatherData.kt b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/WeatherData.kt new file mode 100644 index 00000000..4f48d674 --- /dev/null +++ b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/WeatherData.kt @@ -0,0 +1,38 @@ +package fi.kroon.vadret.data.weatherforecast.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class WeatherData( + + @SerialName(value = "air_temperature") + val airTemperature: Double, + + @SerialName(value = "wind_from_direction") + val windFromDirection: Double, + + @SerialName(value = "wind_speed") + val windSpeed: Double, + + @SerialName(value = "relative_humidity") + val relativeHumidity: Int, + + @SerialName(value = "thunderstorm_probability") + val thunderstormProbability: Int, + + @SerialName(value = "predominant_precipitation_type_at_surface") + val precipitationType: Int, + + @SerialName(value = "probability_of_precipitation") + val probabilityOfPrecipitation: Int, + + @SerialName(value = "precipitation_amount_min") + val precipitationAmountMin: Double, + + @SerialName(value = "precipitation_amount_max") + val precipitationAmountMax: Double, + + @SerialName(value = "symbol_code") + val symbolCode: Int +) diff --git a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/WeatherOut.kt b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/WeatherOut.kt index a4bb60e3..e2babec7 100644 --- a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/WeatherOut.kt +++ b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/model/WeatherOut.kt @@ -1,16 +1,16 @@ package fi.kroon.vadret.data.weatherforecast.model import android.os.Parcelable -import fi.kroon.vadret.util.PMP3G_CATEGORY import fi.kroon.vadret.util.POINT_GEOTYPE -import fi.kroon.vadret.util.SMHI_BASE_API_VERSION +import fi.kroon.vadret.util.SNOW1G_API_VERSION +import fi.kroon.vadret.util.SNOW1G_CATEGORY import kotlinx.android.parcel.Parcelize @Parcelize data class WeatherOut( val localityName: String? = null, - val version: Int = SMHI_BASE_API_VERSION, - val category: String = PMP3G_CATEGORY, + val version: Int = SNOW1G_API_VERSION, + val category: String = SNOW1G_CATEGORY, val geotype: String = POINT_GEOTYPE, val longitude: Double, val latitude: Double diff --git a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastAdapter.kt b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastAdapter.kt index 12c5a427..1e826708 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastAdapter.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastAdapter.kt @@ -130,10 +130,6 @@ class WeatherForecastAdapter @Inject constructor() : RecyclerView.Adapter - itemView.precipitationCode.setText(getPrecipitationResourceId(precipitationCodeInt)) - } ?: itemView.precipitationCode.toGone() - if (item.sunriseDateTime != null && item.sunsetDateTime != null) { val format = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) itemView.sunriseDateTime.text = item.sunriseDateTime.toLocalTime().format(format) @@ -143,10 +139,9 @@ class WeatherForecastAdapter @Inject constructor() : RecyclerView.Adapter - if (intCode > 0) { - itemView.precipitationCode.setText(getPrecipitationResourceId(intCode)) - } + item.precipitationCode?.takeIf { it > 0 }?.let { intCode -> + itemView.precipitationCode.setText(getPrecipitationResourceId(intCode)) + itemView.precipitationCode.toVisible() } ?: itemView.precipitationCode.toGone() } } @@ -172,9 +167,9 @@ class WeatherForecastAdapter @Inject constructor() : RecyclerView.Adapter): WeatherForecastHeadlineModel { - var weatherDescription: Int? = null - var windDirection: Double? = null - var windSpeed: Double? = null - - parameters.forEach { parameter: Parameter -> - when (parameter.name) { - "wd" -> windDirection = parameter.values.first() - "ws" -> windSpeed = parameter.values.first() - "Wsymb2" -> weatherDescription = parameter.values.first().toInt() - } - } - return WeatherForecastHeadlineModel( - headline = weatherDescription, - windSpeed = windSpeed, - windDirection = windDirection + private fun getWeatherForecastHeadlineModel(data: WeatherData): WeatherForecastHeadlineModel = + WeatherForecastHeadlineModel( + headline = data.symbolCode, + windSpeed = data.windSpeed, + windDirection = data.windFromDirection ) - } private fun getWeatherForecastSplashItemModel(timeSerie: TimeSerie, location: Location): WeatherForecastSplashItemModel { @@ -114,62 +102,33 @@ object WeatherForecastMapper { sunsetDateTime = OffsetDateTime.ofInstant(sunsetDateTimeInstant, ZoneId.systemDefault()) } - var humidityPercent: Int = 0 - var temperature: Double = 0.0 - var windSpeed: Double = 0.0 - var windDirection: Double? = null - var feelsLikeTemperature: String? = null - var weatherIcon: Int = 0 - var weatherDescription: Int = 0 - var precipitationCode: Int? = 0 - var thunderRisk: Int = 0 - - for (param in timeSerie.parameters) { - when (param.name) { - "t" -> temperature = param.values.first() - "r" -> humidityPercent = param.values.first().toInt() - "wd" -> windDirection = param.values.first() - "ws" -> windSpeed = param.values.first() - "tstm" -> thunderRisk = param.values.first().toInt() - "pcat" -> precipitationCode = param.values.first().toInt() - "Wsymb2" -> weatherIcon = param.values.first().toInt() - } - } - weatherDescription = weatherIcon + val data: WeatherData = timeSerie.data + val temperature: Double = data.airTemperature + val windSpeed: Double = data.windSpeed + val weatherIcon: Int = data.symbolCode return WeatherForecastSplashItemModel( sunriseDateTime = sunriseDateTime, sunsetDateTime = sunsetDateTime, - humidityPercent = humidityPercent, + humidityPercent = data.relativeHumidity, temperature = temperature, windSpeed = windSpeed, - windDirection = windDirection, + windDirection = data.windFromDirection, feelsLikeTemperature = WindChill.calculate(temperature, windSpeed), weatherIcon = weatherIcon, - weatherDescription = weatherDescription, - precipitationCode = precipitationCode, - thunderRisk = thunderRisk + weatherDescription = weatherIcon, + precipitationCode = data.precipitationType, + thunderRisk = data.thunderstormProbability ) } private fun getWeatherForecastItemModel(timeSerie: TimeSerie): WeatherForecastItemModel { - var temperature: Double = 0.0 - val time: String = Instant.parse(timeSerie.validTime).atZone(ZoneId.systemDefault()).toLocalTime().toString() - var feelsLikeTemperature: String? = null - var windSpeed: Double = 0.0 + val data: WeatherData = timeSerie.data + val time: String = Instant.parse(timeSerie.time).atZone(ZoneId.systemDefault()).toLocalTime().toString() + val temperature: Double = data.airTemperature + val windSpeed: Double = data.windSpeed + val weatherIcon: Int = data.symbolCode val precipitationType: Int = 0 - var weatherIcon: Int = 0 - var weatherDescription: Int = 0 - - for (param in timeSerie.parameters) { - when (param.name) { - "t" -> temperature = param.values.first() - "ws" -> windSpeed = param.values.first() - "Wsymb2" -> weatherIcon = param.values.first().toInt() - } - } - - weatherDescription = weatherIcon return WeatherForecastItemModel( temperature = temperature, @@ -178,7 +137,7 @@ object WeatherForecastMapper { precipitationType = precipitationType, windSpeed = windSpeed, weatherIcon = weatherIcon, - weatherDescription = weatherDescription + weatherDescription = weatherIcon ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastModule.kt b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastModule.kt index 2ec32fc5..c01f14ef 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastModule.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastModule.kt @@ -33,6 +33,7 @@ import retrofit2.converter.moshi.MoshiConverterFactory object WeatherForecastModule { private val contentType: MediaType = "application/json".toMediaType() + private val json: Json = Json { ignoreUnknownKeys = true } @Provides @WeatherForecastScope @@ -52,7 +53,7 @@ object WeatherForecastModule { assertNoInitMainThread() return Retrofit.Builder() .baseUrl(SMHI_API_FORECAST_URL) - .addConverterFactory(Json.asConverterFactory(contentType)) + .addConverterFactory(json.asConverterFactory(contentType)) .delegatingCallFactory(okHttpClient) .build() } diff --git a/app/src/main/java/fi/kroon/vadret/util/Constant.kt b/app/src/main/java/fi/kroon/vadret/util/Constant.kt index 1ca23146..875fb731 100644 --- a/app/src/main/java/fi/kroon/vadret/util/Constant.kt +++ b/app/src/main/java/fi/kroon/vadret/util/Constant.kt @@ -1,10 +1,11 @@ package fi.kroon.vadret.util // SMHI API REQUEST PARAMS -const val PMP3G_CATEGORY = "pmp3g" +const val SNOW1G_CATEGORY = "snow1g" const val POINT_GEOTYPE = "point" const val DEFAULT_TIME_ZONE = "GMT" const val SMHI_BASE_API_VERSION = 2 +const val SNOW1G_API_VERSION = 1 // NOMINATIM API REQEUST PARAMS const val NOMINATIM_DATA_FORMAT = "json" diff --git a/app/src/main/java/fi/kroon/vadret/util/common/WeatherForecastUtil.kt b/app/src/main/java/fi/kroon/vadret/util/common/WeatherForecastUtil.kt index 38b18bba..fb3b9d13 100644 --- a/app/src/main/java/fi/kroon/vadret/util/common/WeatherForecastUtil.kt +++ b/app/src/main/java/fi/kroon/vadret/util/common/WeatherForecastUtil.kt @@ -21,15 +21,25 @@ object WeatherForecastUtil { const val TWELVE_HOURS_AS_MILLIS = 43_200_000L const val TWENTY_FOUR_HOURS_AS_MILLIS = 86_400_000L + /** + * predominant_precipitation_type_at_surface, ECMWF GRIB param 260015 + * https://codes.ecmwf.int/grib/param-db/260015 + */ fun getPrecipitationResourceId(prSort: Int): Int = when (prSort) { 0 -> R.string.prsort_no_precipitation - 1 -> R.string.prsort_snow - 2 -> R.string.prsort_snow_and_rain - 3 -> R.string.prsort_rain - 4 -> R.string.prsort_drizzle - 5 -> R.string.prsort_freezing_rain - 6 -> R.string.prsort_freezing_drizzle + 1 -> R.string.prsort_rain + 2 -> R.string.prsort_thunderstorm + 3 -> R.string.prsort_freezing_rain + 4 -> R.string.prsort_mixed_ice + 5 -> R.string.prsort_snow + 6 -> R.string.prsort_wet_snow + 7 -> R.string.prsort_snow_and_rain + 8 -> R.string.prsort_ice_pellets + 9 -> R.string.prsort_graupel + 10 -> R.string.prsort_hail + 11 -> R.string.prsort_drizzle + 12 -> R.string.prsort_freezing_drizzle else -> R.string.prsort_no_precipitation } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 71474664..f5003d37 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -92,6 +92,12 @@ Drizzle Freezing rain Freezing drizzle + Thunderstorm + Mixed/ice + Wet snow + Ice pellets + Graupel + Hail IOException Network Failure diff --git a/build.gradle b/build.gradle index d02dc88e..b1efa297 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext.KOTLIN_VERSION = "1.4.10" repositories { google() - jcenter() + mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:4.1.1' @@ -17,6 +17,7 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() + maven { url 'https://jitpack.io' } } }