Repo created
This commit is contained in:
parent
d6b5d53060
commit
d90a1dc8df
2145 changed files with 210227 additions and 2 deletions
1
domain/.gitignore
vendored
Normal file
1
domain/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
21
domain/build.gradle.kts
Normal file
21
domain/build.gradle.kts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
plugins {
|
||||
id("breezy.library")
|
||||
kotlin("android")
|
||||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "breezyweather.domain"
|
||||
|
||||
defaultConfig {
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.weatherUnit)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
|
||||
api(libs.sqldelight.android.paging)
|
||||
}
|
||||
0
domain/consumer-rules.pro
Normal file
0
domain/consumer-rules.pro
Normal file
21
domain/proguard-rules.pro
vendored
Normal file
21
domain/proguard-rules.pro
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
2
domain/src/main/AndroidManifest.xml
Normal file
2
domain/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest />
|
||||
|
|
@ -0,0 +1,385 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.location.model
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import breezyweather.domain.weather.model.Weather
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
data class Location(
|
||||
val latitude: Double = 0.0,
|
||||
val longitude: Double = 0.0,
|
||||
val timeZone: TimeZone = TimeZone.getTimeZone("GMT"),
|
||||
|
||||
val country: String = "",
|
||||
val countryCode: String? = null,
|
||||
val admin1: String? = null,
|
||||
val admin1Code: String? = null,
|
||||
val admin2: String? = null,
|
||||
val admin2Code: String? = null,
|
||||
val admin3: String? = null,
|
||||
val admin3Code: String? = null,
|
||||
val admin4: String? = null,
|
||||
val admin4Code: String? = null,
|
||||
val city: String = "",
|
||||
val cityId: String? = null,
|
||||
val district: String? = null,
|
||||
|
||||
val needsGeocodeRefresh: Boolean = false,
|
||||
|
||||
val customName: String? = null,
|
||||
|
||||
val weather: Weather? = null,
|
||||
|
||||
val forecastSource: String = "openmeteo",
|
||||
val currentSource: String? = null,
|
||||
val airQualitySource: String? = null,
|
||||
val pollenSource: String? = null,
|
||||
val minutelySource: String? = null,
|
||||
val alertSource: String? = null,
|
||||
val normalsSource: String? = null,
|
||||
val reverseGeocodingSource: String? = null,
|
||||
|
||||
val isCurrentPosition: Boolean = false,
|
||||
|
||||
/**
|
||||
* "accu": {"cityId": "230"}
|
||||
* "nws": {"gridId": "8", "gridX": "20", "gridY": "30"}
|
||||
* etc
|
||||
*/
|
||||
val parameters: Map<String, Map<String, String>> = emptyMap(),
|
||||
) : Parcelable {
|
||||
|
||||
val formattedId: String
|
||||
get() = if (isCurrentPosition) {
|
||||
CURRENT_POSITION_ID
|
||||
} else {
|
||||
String.format(Locale.US, "%f", latitude) +
|
||||
"&" +
|
||||
String.format(Locale.US, "%f", longitude) +
|
||||
"&" +
|
||||
forecastSource
|
||||
}
|
||||
|
||||
val isUsable: Boolean
|
||||
// Sorry people living exactly at 0,0
|
||||
get() = latitude != 0.0 || longitude != 0.0
|
||||
|
||||
val isTimeZoneInvalid: Boolean
|
||||
get() = timeZone.id == "GMT"
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(cityId)
|
||||
parcel.writeDouble(latitude)
|
||||
parcel.writeDouble(longitude)
|
||||
parcel.writeString(timeZone.id)
|
||||
parcel.writeString(customName)
|
||||
parcel.writeString(country)
|
||||
parcel.writeString(countryCode)
|
||||
parcel.writeString(admin1)
|
||||
parcel.writeString(admin1Code)
|
||||
parcel.writeString(admin2)
|
||||
parcel.writeString(admin2Code)
|
||||
parcel.writeString(admin3)
|
||||
parcel.writeString(admin3Code)
|
||||
parcel.writeString(admin4)
|
||||
parcel.writeString(admin4Code)
|
||||
parcel.writeString(city)
|
||||
parcel.writeString(district)
|
||||
parcel.writeString(forecastSource)
|
||||
parcel.writeString(currentSource)
|
||||
parcel.writeString(airQualitySource)
|
||||
parcel.writeString(pollenSource)
|
||||
parcel.writeString(minutelySource)
|
||||
parcel.writeString(alertSource)
|
||||
parcel.writeString(normalsSource)
|
||||
parcel.writeString(reverseGeocodingSource)
|
||||
parcel.writeByte(if (isCurrentPosition) 1 else 0)
|
||||
parcel.writeByte(if (needsGeocodeRefresh) 1 else 0)
|
||||
}
|
||||
|
||||
override fun describeContents() = 0
|
||||
|
||||
constructor(parcel: Parcel) : this(
|
||||
cityId = parcel.readString(),
|
||||
latitude = parcel.readDouble(),
|
||||
longitude = parcel.readDouble(),
|
||||
timeZone = TimeZone.getTimeZone(parcel.readString()!!),
|
||||
customName = parcel.readString(),
|
||||
country = parcel.readString()!!,
|
||||
countryCode = parcel.readString(),
|
||||
admin1 = parcel.readString(),
|
||||
admin1Code = parcel.readString(),
|
||||
admin2 = parcel.readString(),
|
||||
admin2Code = parcel.readString(),
|
||||
admin3 = parcel.readString(),
|
||||
admin3Code = parcel.readString(),
|
||||
admin4 = parcel.readString(),
|
||||
admin4Code = parcel.readString(),
|
||||
city = parcel.readString()!!,
|
||||
district = parcel.readString(),
|
||||
forecastSource = parcel.readString()!!,
|
||||
currentSource = parcel.readString(),
|
||||
airQualitySource = parcel.readString(),
|
||||
pollenSource = parcel.readString(),
|
||||
minutelySource = parcel.readString(),
|
||||
alertSource = parcel.readString(),
|
||||
normalsSource = parcel.readString(),
|
||||
reverseGeocodingSource = parcel.readString(),
|
||||
isCurrentPosition = parcel.readByte() != 0.toByte(),
|
||||
needsGeocodeRefresh = parcel.readByte() != 0.toByte()
|
||||
)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) {
|
||||
return true
|
||||
}
|
||||
if (other == null || other !is Location) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (formattedId != other.formattedId) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (customName != other.customName) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (forecastSource != other.forecastSource) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (currentSource != other.currentSource) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (airQualitySource != other.airQualitySource) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (pollenSource != other.pollenSource) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (minutelySource != other.minutelySource) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (alertSource != other.alertSource) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (normalsSource != other.normalsSource) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (needsGeocodeRefresh != other.needsGeocodeRefresh) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (parameters != other.parameters) {
|
||||
return false
|
||||
}
|
||||
|
||||
val thisWeather = weather
|
||||
val otherWeather = other.weather
|
||||
if (thisWeather == null && otherWeather == null) {
|
||||
return true
|
||||
}
|
||||
return if (thisWeather != null && otherWeather != null) {
|
||||
thisWeather.base.refreshTime?.time == otherWeather.base.refreshTime?.time
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return formattedId.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val builder = StringBuilder("$country $admin1 $admin2 $admin3 $admin4")
|
||||
if (admin4 != city && city.isNotEmpty()) {
|
||||
builder.append(" ").append(city)
|
||||
}
|
||||
if (city != district && !district.isNullOrEmpty()) {
|
||||
builder.append(" ").append(district)
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
fun administrationLevels(): String {
|
||||
val builder = StringBuilder()
|
||||
if (country.isNotEmpty()) {
|
||||
builder.append(country)
|
||||
}
|
||||
if (!admin1.isNullOrEmpty()) {
|
||||
if (builder.toString().isNotEmpty()) {
|
||||
builder.append(", ")
|
||||
}
|
||||
builder.append(admin1)
|
||||
}
|
||||
if (!admin2.isNullOrEmpty()) {
|
||||
if (builder.toString().isNotEmpty()) {
|
||||
builder.append(", ")
|
||||
}
|
||||
builder.append(admin2)
|
||||
}
|
||||
if (!admin3.isNullOrEmpty() && (!admin4.isNullOrEmpty() || admin3 != city)) {
|
||||
if (builder.toString().isNotEmpty()) {
|
||||
builder.append(", ")
|
||||
}
|
||||
builder.append(admin3)
|
||||
}
|
||||
if (!admin4.isNullOrEmpty() && admin4 != city) {
|
||||
if (builder.toString().isNotEmpty()) {
|
||||
builder.append(", ")
|
||||
}
|
||||
builder.append(admin4)
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
val cityAndDistrict: String
|
||||
get() {
|
||||
val builder = StringBuilder()
|
||||
if (city.isNotEmpty()) {
|
||||
builder.append(city)
|
||||
}
|
||||
if (!district.isNullOrEmpty() && district != city) {
|
||||
if (builder.toString().isNotEmpty()) {
|
||||
builder.append(", ")
|
||||
}
|
||||
builder.append(district)
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
fun toLocationWithAddressInfo(
|
||||
currentLocale: Locale,
|
||||
locationAddressInfo: LocationAddressInfo,
|
||||
overwriteCoordinates: Boolean,
|
||||
): Location {
|
||||
return copy(
|
||||
latitude = if (overwriteCoordinates &&
|
||||
locationAddressInfo.latitude != null &&
|
||||
locationAddressInfo.longitude != null
|
||||
) {
|
||||
locationAddressInfo.latitude
|
||||
} else {
|
||||
latitude
|
||||
},
|
||||
longitude = if (overwriteCoordinates &&
|
||||
locationAddressInfo.latitude != null &&
|
||||
locationAddressInfo.longitude != null
|
||||
) {
|
||||
locationAddressInfo.longitude
|
||||
} else {
|
||||
longitude
|
||||
},
|
||||
timeZone = TimeZone.getTimeZone(locationAddressInfo.timeZoneId ?: "GMT"),
|
||||
country = if (locationAddressInfo.country.isNullOrEmpty() && !locationAddressInfo.country.isNullOrEmpty()) {
|
||||
Locale.Builder()
|
||||
.setLanguage(currentLocale.language)
|
||||
.setRegion(countryCode)
|
||||
.build()
|
||||
.displayCountry
|
||||
} else {
|
||||
locationAddressInfo.country ?: ""
|
||||
},
|
||||
countryCode = locationAddressInfo.countryCode,
|
||||
admin1 = locationAddressInfo.admin1 ?: "",
|
||||
admin1Code = locationAddressInfo.admin1Code ?: "",
|
||||
admin2 = locationAddressInfo.admin2 ?: "",
|
||||
admin2Code = locationAddressInfo.admin2Code ?: "",
|
||||
admin3 = locationAddressInfo.admin3 ?: "",
|
||||
admin3Code = locationAddressInfo.admin3Code ?: "",
|
||||
admin4 = locationAddressInfo.admin4 ?: "",
|
||||
admin4Code = locationAddressInfo.admin4Code ?: "",
|
||||
city = locationAddressInfo.city ?: "",
|
||||
cityId = locationAddressInfo.cityCode ?: "",
|
||||
district = locationAddressInfo.district ?: "",
|
||||
needsGeocodeRefresh = false
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* It is not intended to be used by the reverse geocoding source
|
||||
* You're supposed to call the LocationAddressInfo constructor
|
||||
*
|
||||
* Currently only used by Natural Earth Service for a very special case
|
||||
* Use with precaution!
|
||||
*/
|
||||
// @Delicate
|
||||
fun toAddressInfo(): LocationAddressInfo {
|
||||
return LocationAddressInfo(
|
||||
latitude = latitude,
|
||||
longitude = longitude,
|
||||
timeZoneId = timeZone.id,
|
||||
country = country,
|
||||
countryCode = countryCode ?: "",
|
||||
admin1 = admin1,
|
||||
admin1Code = admin1Code,
|
||||
admin2 = admin2,
|
||||
admin2Code = admin2Code,
|
||||
admin3 = admin3,
|
||||
admin3Code = admin3Code,
|
||||
admin4 = admin4,
|
||||
admin4Code = admin4Code,
|
||||
city = city,
|
||||
cityCode = cityId,
|
||||
district = district
|
||||
)
|
||||
}
|
||||
|
||||
val hasValidCountryCode: Boolean
|
||||
get() {
|
||||
return !countryCode.isNullOrEmpty() && countryCode.matches(Regex("[A-Za-z]{2}"))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val CURRENT_POSITION_ID = "CURRENT_POSITION"
|
||||
const val CLOSE_DISTANCE = 5000 // 5 km
|
||||
|
||||
fun isEquals(a: String?, b: String?): Boolean {
|
||||
return if (a.isNullOrEmpty() && b.isNullOrEmpty()) {
|
||||
true
|
||||
} else if (!a.isNullOrEmpty() && !b.isNullOrEmpty()) {
|
||||
a == b
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val CREATOR = object : Parcelable.Creator<Location> {
|
||||
|
||||
override fun createFromParcel(parcel: Parcel): Location {
|
||||
return Location(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<Location?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.location.model
|
||||
|
||||
data class LocationAddressInfo(
|
||||
/**
|
||||
* Mandatory when used in the location search process
|
||||
* In the reverse geocoding process, if provided, will throw an error if the returned location is too far away
|
||||
* from the originally provided coordinates
|
||||
*/
|
||||
val latitude: Double? = null,
|
||||
/**
|
||||
* Mandatory when used in the location search process
|
||||
* In the reverse geocoding process, if provided, will throw an error if the returned location is too far away
|
||||
* from the originally provided coordinates
|
||||
*/
|
||||
val longitude: Double? = null,
|
||||
/**
|
||||
* Time zone of the location in the TZ identifier format
|
||||
* Examples: America/New_York, Europe/Paris
|
||||
*
|
||||
* The list of accepted time zones can be found here:
|
||||
* https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
*/
|
||||
val timeZoneId: String? = null,
|
||||
|
||||
/**
|
||||
* Leave null or empty to let the system translates the country name from the countryCode
|
||||
*/
|
||||
val country: String? = null,
|
||||
/**
|
||||
* Contrary to its name, this code represents not just countries, but also dependent territories, and special areas
|
||||
* of geographical interest
|
||||
* Must be a valid ISO 3166-1 alpha-2 code
|
||||
* https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
|
||||
*
|
||||
* We don't support locations in the middle of the ocean, so ensure this is non empty.
|
||||
*
|
||||
* Will throw an error if it is not a valid 2 alpha letter code
|
||||
*/
|
||||
val countryCode: String,
|
||||
val admin1: String? = null,
|
||||
/**
|
||||
* Can be an ISO 3166-2 code, or the internal code used by the country
|
||||
*/
|
||||
val admin1Code: String? = null,
|
||||
val admin2: String? = null,
|
||||
/**
|
||||
* Can be an ISO 3166-2 code, or the internal code used by the country
|
||||
*/
|
||||
val admin2Code: String? = null,
|
||||
val admin3: String? = null,
|
||||
/**
|
||||
* Can be an ISO 3166-2 code, or the internal code used by the country
|
||||
*/
|
||||
val admin3Code: String? = null,
|
||||
val admin4: String? = null,
|
||||
/**
|
||||
* Can be an ISO 3166-2 code, or the internal code used by the country
|
||||
*/
|
||||
val admin4Code: String? = null,
|
||||
val city: String? = null,
|
||||
val cityCode: String? = null,
|
||||
val district: String? = null,
|
||||
)
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.source
|
||||
|
||||
enum class SourceContinent(
|
||||
val id: String,
|
||||
) {
|
||||
WORLDWIDE("worldwide"),
|
||||
AFRICA("africa"),
|
||||
ASIA("asia"),
|
||||
EUROPE("europe"),
|
||||
NORTH_AMERICA("north_america"),
|
||||
OCEANIA("oceania"),
|
||||
SOUTH_AMERICA("south_america"),
|
||||
;
|
||||
|
||||
companion object {
|
||||
|
||||
fun getInstance(
|
||||
value: String,
|
||||
) = SourceContinent.entries.firstOrNull {
|
||||
it.id == value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.source
|
||||
|
||||
enum class SourceFeature(
|
||||
val id: String,
|
||||
) {
|
||||
FORECAST("forecast"),
|
||||
CURRENT("current"),
|
||||
AIR_QUALITY("airQuality"),
|
||||
POLLEN("pollen"),
|
||||
MINUTELY("minutely"),
|
||||
ALERT("alert"),
|
||||
NORMALS("normals"),
|
||||
REVERSE_GEOCODING("reverseGeocoding"),
|
||||
;
|
||||
|
||||
companion object {
|
||||
|
||||
fun getInstance(
|
||||
value: String,
|
||||
) = SourceFeature.entries.firstOrNull {
|
||||
it.id == value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.pollutant.PollutantConcentration
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Air Quality.
|
||||
* AQI uses 2023 update of Plume AQI
|
||||
* https://plumelabs.files.wordpress.com/2023/06/plume_aqi_2023.pdf
|
||||
* For missing information, it uses WHO recommandations
|
||||
* https://www.who.int/news-room/fact-sheets/detail/ambient-(outdoor)-air-quality-and-health
|
||||
*/
|
||||
class AirQuality(
|
||||
val pM25: PollutantConcentration? = null,
|
||||
val pM10: PollutantConcentration? = null,
|
||||
val sO2: PollutantConcentration? = null,
|
||||
val nO2: PollutantConcentration? = null,
|
||||
val o3: PollutantConcentration? = null,
|
||||
val cO: PollutantConcentration? = null,
|
||||
) : Serializable {
|
||||
|
||||
val isValid: Boolean
|
||||
get() = pM25 != null || pM10 != null || sO2 != null || nO2 != null || o3 != null || cO != null
|
||||
|
||||
val isIndexValid: Boolean
|
||||
get() = pM25 != null || pM10 != null || nO2 != null || o3 != null
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.ColorInt
|
||||
import breezyweather.domain.weather.reference.AlertSeverity
|
||||
import java.io.Serializable
|
||||
import java.util.Date
|
||||
|
||||
/**
|
||||
* Alert.
|
||||
*
|
||||
* All properties are [androidx.annotation.NonNull].
|
||||
*/
|
||||
data class Alert(
|
||||
/**
|
||||
* If not provided by the source, can be created from Objects.hash().toString()
|
||||
* Usually, you will use three parameters: alert type or title, alert level, alert start time
|
||||
*/
|
||||
val alertId: String,
|
||||
val startDate: Date? = null,
|
||||
val endDate: Date? = null,
|
||||
val headline: String? = null,
|
||||
/**
|
||||
* HTML accepted. For compatibility with non-HTML fields, line breaks (\n) will be replaced with <br />.
|
||||
*/
|
||||
val description: String? = null,
|
||||
val instruction: String? = null,
|
||||
val source: String? = null,
|
||||
val severity: AlertSeverity = AlertSeverity.UNKNOWN,
|
||||
@ColorInt val color: Int,
|
||||
) : Serializable {
|
||||
|
||||
companion object {
|
||||
@ColorInt
|
||||
fun colorFromSeverity(severity: AlertSeverity): Int {
|
||||
return when (severity) {
|
||||
AlertSeverity.EXTREME -> Color.rgb(212, 45, 65)
|
||||
AlertSeverity.SEVERE -> Color.rgb(240, 140, 17)
|
||||
AlertSeverity.MODERATE -> Color.rgb(244, 207, 0)
|
||||
AlertSeverity.MINOR -> Color.rgb(57, 156, 199)
|
||||
else -> Color.rgb(130, 168, 223)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import java.io.Serializable
|
||||
import java.util.Date
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
class Astro(
|
||||
val riseDate: Date? = null,
|
||||
val setDate: Date? = null,
|
||||
) : Serializable {
|
||||
|
||||
// Not made to be used for moon astro, only sun
|
||||
val duration: Duration?
|
||||
get() = if (riseDate == null || setDate == null) {
|
||||
// Polar night
|
||||
0.milliseconds
|
||||
} else if (riseDate.after(setDate)) {
|
||||
null
|
||||
} else {
|
||||
(setDate.time - riseDate.time).milliseconds
|
||||
}
|
||||
|
||||
val isValid: Boolean
|
||||
get() = riseDate != null && setDate != null
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import java.io.Serializable
|
||||
import java.util.Date
|
||||
|
||||
/**
|
||||
* Base.
|
||||
*/
|
||||
data class Base(
|
||||
// val publishDate: Date = Date(),
|
||||
val refreshTime: Date? = null,
|
||||
val forecastUpdateTime: Date? = null,
|
||||
val currentUpdateTime: Date? = null,
|
||||
val airQualityUpdateTime: Date? = null,
|
||||
val pollenUpdateTime: Date? = null,
|
||||
val minutelyUpdateTime: Date? = null,
|
||||
val alertsUpdateTime: Date? = null,
|
||||
val normalsUpdateTime: Date? = null,
|
||||
val normalsUpdateLatitude: Double = 0.0,
|
||||
val normalsUpdateLongitude: Double = 0.0,
|
||||
) : Serializable
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import breezyweather.domain.weather.reference.WeatherCode
|
||||
import breezyweather.domain.weather.wrappers.CurrentWrapper
|
||||
import org.breezyweather.unit.distance.Distance
|
||||
import org.breezyweather.unit.pressure.Pressure
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Current.
|
||||
*/
|
||||
data class Current(
|
||||
val weatherText: String? = null,
|
||||
val weatherCode: WeatherCode? = null,
|
||||
val temperature: Temperature? = null,
|
||||
val wind: Wind? = null,
|
||||
val uV: UV? = null,
|
||||
val airQuality: AirQuality? = null,
|
||||
val relativeHumidity: Ratio? = null,
|
||||
val dewPoint: org.breezyweather.unit.temperature.Temperature? = null,
|
||||
/**
|
||||
* Pressure at sea level
|
||||
* Use Kotlin extensions to initialize this value, like 1013.25.hectopascals
|
||||
*/
|
||||
val pressure: Pressure? = null,
|
||||
val cloudCover: Ratio? = null,
|
||||
val visibility: Distance? = null,
|
||||
val ceiling: Distance? = null,
|
||||
val dailyForecast: String? = null,
|
||||
// Is actually a description of the nowcast
|
||||
val hourlyForecast: String? = null,
|
||||
) : Serializable {
|
||||
|
||||
fun toCurrentWrapper() = CurrentWrapper(
|
||||
weatherText = this.weatherText,
|
||||
weatherCode = this.weatherCode,
|
||||
temperature = this.temperature?.toTemperatureWrapper(),
|
||||
wind = this.wind,
|
||||
uV = uV ?: this.uV,
|
||||
relativeHumidity = this.relativeHumidity,
|
||||
dewPoint = this.dewPoint,
|
||||
pressure = this.pressure,
|
||||
cloudCover = this.cloudCover,
|
||||
visibility = this.visibility,
|
||||
ceiling = this.ceiling,
|
||||
dailyForecast = this.dailyForecast,
|
||||
hourlyForecast = this.hourlyForecast
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import breezyweather.domain.weather.wrappers.DailyWrapper
|
||||
import java.io.Serializable
|
||||
import java.util.Date
|
||||
import kotlin.time.Duration
|
||||
|
||||
/**
|
||||
* Daily.
|
||||
*/
|
||||
data class Daily(
|
||||
/**
|
||||
* Daily date initialized at 00:00 in the TimeZone of the location
|
||||
*/
|
||||
val date: Date,
|
||||
val day: HalfDay? = null,
|
||||
val night: HalfDay? = null,
|
||||
val degreeDay: DegreeDay? = null,
|
||||
val sun: Astro? = null,
|
||||
val twilight: Astro? = null,
|
||||
val moon: Astro? = null,
|
||||
val moonPhase: MoonPhase? = null,
|
||||
val airQuality: AirQuality? = null,
|
||||
val pollen: Pollen? = null,
|
||||
val uV: UV? = null,
|
||||
val sunshineDuration: Duration? = null,
|
||||
val relativeHumidity: DailyRelativeHumidity? = null,
|
||||
val dewPoint: DailyDewPoint? = null,
|
||||
val pressure: DailyPressure? = null,
|
||||
val cloudCover: DailyCloudCover? = null,
|
||||
val visibility: DailyVisibility? = null,
|
||||
) : Serializable {
|
||||
|
||||
fun toDailyWrapper() = DailyWrapper(
|
||||
date = this.date,
|
||||
day = this.day?.toHalfDayWrapper(),
|
||||
night = this.night?.toHalfDayWrapper(),
|
||||
degreeDay = this.degreeDay,
|
||||
uV = this.uV,
|
||||
sunshineDuration = this.sunshineDuration
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
interface DailyAvgMinMax<T> {
|
||||
val average: T?
|
||||
val max: T?
|
||||
val min: T?
|
||||
val summary: String?
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
|
||||
data class DailyCloudCover(
|
||||
override val average: Ratio? = null,
|
||||
override val max: Ratio? = null,
|
||||
override val min: Ratio? = null,
|
||||
override val summary: String? = null,
|
||||
) : DailyAvgMinMax<Ratio>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
|
||||
data class DailyDewPoint(
|
||||
override val average: Temperature? = null,
|
||||
override val max: Temperature? = null,
|
||||
override val min: Temperature? = null,
|
||||
override val summary: String? = null,
|
||||
) : DailyAvgMinMax<Temperature>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.pressure.Pressure
|
||||
|
||||
data class DailyPressure(
|
||||
override val average: Pressure? = null,
|
||||
override val max: Pressure? = null,
|
||||
override val min: Pressure? = null,
|
||||
override val summary: String? = null,
|
||||
) : DailyAvgMinMax<Pressure>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
|
||||
data class DailyRelativeHumidity(
|
||||
override val average: Ratio? = null,
|
||||
override val max: Ratio? = null,
|
||||
override val min: Ratio? = null,
|
||||
override val summary: String? = null,
|
||||
) : DailyAvgMinMax<Ratio>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.distance.Distance
|
||||
|
||||
data class DailyVisibility(
|
||||
override val average: Distance? = null,
|
||||
override val max: Distance? = null,
|
||||
override val min: Distance? = null,
|
||||
override val summary: String? = null,
|
||||
) : DailyAvgMinMax<Distance>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Degree Day
|
||||
*/
|
||||
class DegreeDay(
|
||||
val heating: org.breezyweather.unit.temperature.Temperature? = null,
|
||||
val cooling: org.breezyweather.unit.temperature.Temperature? = null,
|
||||
) : Serializable {
|
||||
|
||||
val isValid = (heating != null && heating.value > 0L) || (cooling != null && cooling.value > 0L)
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import breezyweather.domain.weather.reference.WeatherCode
|
||||
import breezyweather.domain.weather.wrappers.HalfDayWrapper
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Half day.
|
||||
*/
|
||||
data class HalfDay(
|
||||
/**
|
||||
* A short description of the weather condition
|
||||
*/
|
||||
val weatherText: String? = null,
|
||||
|
||||
/**
|
||||
* A long description of the weather condition. Used as a half-day summary
|
||||
*/
|
||||
val weatherSummary: String? = null,
|
||||
val weatherCode: WeatherCode? = null,
|
||||
val temperature: Temperature? = null,
|
||||
val precipitation: Precipitation? = null,
|
||||
val precipitationProbability: PrecipitationProbability? = null,
|
||||
val precipitationDuration: PrecipitationDuration? = null,
|
||||
val wind: Wind? = null,
|
||||
) : Serializable {
|
||||
|
||||
fun toHalfDayWrapper() = HalfDayWrapper(
|
||||
weatherText = this.weatherText,
|
||||
weatherSummary = this.weatherSummary,
|
||||
weatherCode = this.weatherCode,
|
||||
temperature = this.temperature?.toTemperatureWrapper(),
|
||||
precipitation = this.precipitation,
|
||||
precipitationProbability = this.precipitationProbability,
|
||||
precipitationDuration = this.precipitationDuration,
|
||||
wind = this.wind
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import breezyweather.domain.weather.reference.WeatherCode
|
||||
import breezyweather.domain.weather.wrappers.HourlyWrapper
|
||||
import org.breezyweather.unit.distance.Distance
|
||||
import org.breezyweather.unit.pressure.Pressure
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import java.io.Serializable
|
||||
import java.util.Date
|
||||
|
||||
/**
|
||||
* Hourly.
|
||||
*/
|
||||
data class Hourly(
|
||||
val date: Date,
|
||||
val isDaylight: Boolean = true,
|
||||
val weatherText: String? = null,
|
||||
val weatherCode: WeatherCode? = null,
|
||||
val temperature: Temperature? = null,
|
||||
val precipitation: Precipitation? = null,
|
||||
val precipitationProbability: PrecipitationProbability? = null,
|
||||
val wind: Wind? = null,
|
||||
val airQuality: AirQuality? = null,
|
||||
val uV: UV? = null,
|
||||
val relativeHumidity: Ratio? = null,
|
||||
val dewPoint: org.breezyweather.unit.temperature.Temperature? = null,
|
||||
/**
|
||||
* Pressure at sea level
|
||||
* Use Kotlin extensions to initialize this value, like 1013.25.hectopascals
|
||||
*/
|
||||
val pressure: Pressure? = null,
|
||||
val cloudCover: Ratio? = null,
|
||||
val visibility: Distance? = null,
|
||||
) : Serializable {
|
||||
|
||||
fun toHourlyWrapper() = HourlyWrapper(
|
||||
date = this.date,
|
||||
isDaylight = this.isDaylight,
|
||||
weatherText = this.weatherText,
|
||||
weatherCode = this.weatherCode,
|
||||
temperature = this.temperature?.toTemperatureWrapper(),
|
||||
precipitation = this.precipitation,
|
||||
precipitationProbability = this.precipitationProbability,
|
||||
wind = this.wind,
|
||||
uV = this.uV,
|
||||
relativeHumidity = this.relativeHumidity,
|
||||
dewPoint = this.dewPoint,
|
||||
pressure = this.pressure,
|
||||
cloudCover = this.cloudCover,
|
||||
visibility = this.visibility
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.precipitation.Precipitation
|
||||
import java.io.Serializable
|
||||
import java.util.Date
|
||||
import kotlin.math.log10
|
||||
import kotlin.math.pow
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
|
||||
/**
|
||||
* Minutely.
|
||||
*/
|
||||
data class Minutely(
|
||||
val date: Date,
|
||||
val minuteInterval: Int,
|
||||
val precipitationIntensity: Precipitation? = null,
|
||||
) : Serializable {
|
||||
|
||||
val dbz: Int?
|
||||
get() = precipitationIntensityToDBZ(precipitationIntensity?.inMillimeters)
|
||||
|
||||
val endingDate: Date
|
||||
get() = Date(date.time + minuteInterval.minutes.inWholeMilliseconds)
|
||||
|
||||
fun toValidOrNull(): Minutely? {
|
||||
return copy(
|
||||
precipitationIntensity = precipitationIntensity?.toValidHourlyOrNull()
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private fun precipitationIntensityToDBZ(intensity: Double?): Int? {
|
||||
return intensity?.let {
|
||||
(10.0 * log10(200.0 * Math.pow(intensity, 8.0 / 5.0))).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
fun dbzToPrecipitationIntensity(dbz: Double?): Double? {
|
||||
return if (dbz == null) {
|
||||
null
|
||||
} else {
|
||||
if (dbz <= 5) 0.0 else (10.0.pow(dbz / 10.0) / 200.0).pow(5.0 / 8.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Moon phase.
|
||||
*/
|
||||
class MoonPhase(
|
||||
/**
|
||||
* Angle between 0 to 360 (no negative! Add 180 if you have negative numbers)
|
||||
*/
|
||||
val angle: Int? = null,
|
||||
) : Serializable {
|
||||
|
||||
val isValid: Boolean
|
||||
get() = angle != null
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Normals
|
||||
*/
|
||||
class Normals(
|
||||
val daytimeTemperature: Temperature? = null,
|
||||
val nighttimeTemperature: Temperature? = null,
|
||||
) : Serializable {
|
||||
|
||||
val isValid: Boolean
|
||||
get() = daytimeTemperature != null && nighttimeTemperature != null
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.pollen.PollenConcentration
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Pollen (tree, grass, weed) and mold
|
||||
*/
|
||||
class Pollen(
|
||||
val alder: PollenConcentration? = null,
|
||||
val ash: PollenConcentration? = null,
|
||||
val birch: PollenConcentration? = null,
|
||||
val chestnut: PollenConcentration? = null,
|
||||
val cypress: PollenConcentration? = null,
|
||||
val grass: PollenConcentration? = null,
|
||||
val hazel: PollenConcentration? = null,
|
||||
val hornbeam: PollenConcentration? = null,
|
||||
val linden: PollenConcentration? = null,
|
||||
val mold: PollenConcentration? = null, // Not a pollen, but probably relevant to put with them
|
||||
val mugwort: PollenConcentration? = null,
|
||||
val oak: PollenConcentration? = null,
|
||||
val olive: PollenConcentration? = null,
|
||||
val plane: PollenConcentration? = null,
|
||||
val plantain: PollenConcentration? = null,
|
||||
val poplar: PollenConcentration? = null,
|
||||
val ragweed: PollenConcentration? = null,
|
||||
val sorrel: PollenConcentration? = null,
|
||||
val tree: PollenConcentration? = null,
|
||||
val urticaceae: PollenConcentration? = null,
|
||||
val willow: PollenConcentration? = null,
|
||||
) : Serializable {
|
||||
|
||||
val isMoldValid: Boolean
|
||||
get() = mold != null
|
||||
|
||||
val isValid: Boolean
|
||||
get() = alder != null ||
|
||||
ash != null ||
|
||||
birch != null ||
|
||||
chestnut != null ||
|
||||
cypress != null ||
|
||||
grass != null ||
|
||||
hazel != null ||
|
||||
hornbeam != null ||
|
||||
linden != null ||
|
||||
mold != null ||
|
||||
mugwort != null ||
|
||||
oak != null ||
|
||||
olive != null ||
|
||||
plane != null ||
|
||||
plantain != null ||
|
||||
poplar != null ||
|
||||
ragweed != null ||
|
||||
sorrel != null ||
|
||||
tree != null ||
|
||||
urticaceae != null ||
|
||||
willow != null
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Precipitation.
|
||||
*/
|
||||
data class Precipitation(
|
||||
val total: org.breezyweather.unit.precipitation.Precipitation? = null,
|
||||
val thunderstorm: org.breezyweather.unit.precipitation.Precipitation? = null,
|
||||
val rain: org.breezyweather.unit.precipitation.Precipitation? = null,
|
||||
val snow: org.breezyweather.unit.precipitation.Precipitation? = null,
|
||||
val ice: org.breezyweather.unit.precipitation.Precipitation? = null,
|
||||
) : Serializable {
|
||||
|
||||
companion object {
|
||||
// Based on India Meteorological Department day values (divided by two for half days)
|
||||
// https://mausam.imd.gov.in/imd_latest/contents/pdf/forecasting_sop.pdf
|
||||
const val PRECIPITATION_HALF_DAY_VERY_LIGHT = 1.25
|
||||
const val PRECIPITATION_HALF_DAY_LIGHT = 7.75
|
||||
const val PRECIPITATION_HALF_DAY_MEDIUM = 32.25
|
||||
const val PRECIPITATION_HALF_DAY_HEAVY = 57.75
|
||||
const val PRECIPITATION_HALF_DAY_RAINSTORM = 102.25
|
||||
|
||||
// Chapter 9.3.1 - Nowcasting
|
||||
const val PRECIPITATION_HOURLY_LIGHT = 5.0
|
||||
const val PRECIPITATION_HOURLY_MEDIUM = 10.0
|
||||
const val PRECIPITATION_HOURLY_HEAVY = 15.0
|
||||
const val PRECIPITATION_HOURLY_RAINSTORM = 20.0
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import java.io.Serializable
|
||||
import kotlin.time.Duration
|
||||
|
||||
/**
|
||||
* Precipitation duration.
|
||||
*/
|
||||
data class PrecipitationDuration(
|
||||
val total: Duration? = null,
|
||||
val thunderstorm: Duration? = null,
|
||||
val rain: Duration? = null,
|
||||
val snow: Duration? = null,
|
||||
val ice: Duration? = null,
|
||||
) : Serializable
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Precipitation duration.
|
||||
*/
|
||||
data class PrecipitationProbability(
|
||||
val total: Ratio? = null,
|
||||
val thunderstorm: Ratio? = null,
|
||||
val rain: Ratio? = null,
|
||||
val snow: Ratio? = null,
|
||||
val ice: Ratio? = null,
|
||||
) : Serializable {
|
||||
|
||||
val isValid: Boolean
|
||||
get() = total != null && total.value > 0
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import breezyweather.domain.weather.wrappers.TemperatureWrapper
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Temperature.
|
||||
*/
|
||||
data class Temperature(
|
||||
val temperature: org.breezyweather.unit.temperature.Temperature? = null,
|
||||
val sourceFeelsLike: org.breezyweather.unit.temperature.Temperature? = null,
|
||||
val computedApparent: org.breezyweather.unit.temperature.Temperature? = null,
|
||||
val computedWindChill: org.breezyweather.unit.temperature.Temperature? = null,
|
||||
val computedHumidex: org.breezyweather.unit.temperature.Temperature? = null,
|
||||
) : Serializable {
|
||||
|
||||
val feelsLikeTemperature: org.breezyweather.unit.temperature.Temperature? = sourceFeelsLike
|
||||
?: computedApparent
|
||||
?: computedWindChill
|
||||
?: computedHumidex
|
||||
|
||||
fun toTemperatureWrapper() = TemperatureWrapper(
|
||||
temperature = this.temperature,
|
||||
feelsLike = this.sourceFeelsLike
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import java.io.Serializable
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* UV.
|
||||
*/
|
||||
class UV(
|
||||
val index: Double? = null,
|
||||
) : Serializable {
|
||||
|
||||
val isValid: Boolean
|
||||
get() = index != null
|
||||
|
||||
companion object {
|
||||
const val UV_INDEX_LOW = 3.0
|
||||
const val UV_INDEX_MIDDLE = 6.0
|
||||
const val UV_INDEX_HIGH = 8.0
|
||||
const val UV_INDEX_EXCESSIVE = 11.0
|
||||
|
||||
val uvThresholds = listOf(
|
||||
0,
|
||||
UV_INDEX_LOW.roundToInt(),
|
||||
UV_INDEX_MIDDLE.roundToInt(),
|
||||
UV_INDEX_HIGH.roundToInt(),
|
||||
UV_INDEX_EXCESSIVE.roundToInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import breezyweather.domain.weather.reference.Month
|
||||
import breezyweather.domain.weather.wrappers.AirQualityWrapper
|
||||
import breezyweather.domain.weather.wrappers.DailyWrapper
|
||||
import breezyweather.domain.weather.wrappers.HourlyWrapper
|
||||
import breezyweather.domain.weather.wrappers.PollenWrapper
|
||||
import breezyweather.domain.weather.wrappers.WeatherWrapper
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.micrometers
|
||||
import java.io.Serializable
|
||||
import java.util.Date
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.days
|
||||
import kotlin.time.Duration.Companion.hours
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
|
||||
data class Weather(
|
||||
val base: Base = Base(),
|
||||
val current: Current? = null,
|
||||
val dailyForecast: List<Daily> = emptyList(),
|
||||
val hourlyForecast: List<Hourly> = emptyList(),
|
||||
val minutelyForecast: List<Minutely> = emptyList(),
|
||||
val alertList: List<Alert> = emptyList(),
|
||||
val normals: Map<Month, Normals> = emptyMap(),
|
||||
) : Serializable {
|
||||
|
||||
// Only hourly in the future, starting from current hour until the next 24 hours
|
||||
val nextHourlyForecast = hourlyForecast.filter {
|
||||
// Example: 15:01 -> starts at 15:00, 15:59 -> starts at 15:00
|
||||
it.date.time >= System.currentTimeMillis() - 1.hours.inWholeMilliseconds &&
|
||||
it.date.time < System.currentTimeMillis() + 24.hours.inWholeMilliseconds
|
||||
}
|
||||
|
||||
// Only hourly in the future, starting from current hour until the end
|
||||
val fullNextHourlyForecast = hourlyForecast.filter {
|
||||
// Example: 15:01 -> starts at 15:00, 15:59 -> starts at 15:00
|
||||
it.date.time >= System.currentTimeMillis() - 1.hours.inWholeMilliseconds
|
||||
}
|
||||
|
||||
val todayIndex = dailyForecast.indexOfFirst {
|
||||
it.date.time > Date().time - 1.days.inWholeMilliseconds
|
||||
}.let { if (it == -1) null else it }
|
||||
val today
|
||||
get() = todayIndex?.let { dailyForecast.getOrNull(it) }
|
||||
val tomorrow
|
||||
get() = dailyForecast.firstOrNull {
|
||||
it.date.time > Date().time
|
||||
}
|
||||
|
||||
val dailyForecastStartingToday = if (todayIndex != null) {
|
||||
dailyForecast.subList(todayIndex, dailyForecast.size)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
fun isValid(pollingIntervalHours: Duration?): Boolean {
|
||||
val updateTime = base.refreshTime?.time ?: 0
|
||||
val currentTime = System.currentTimeMillis()
|
||||
return pollingIntervalHours == null ||
|
||||
(currentTime >= updateTime && currentTime - updateTime < pollingIntervalHours.inWholeMilliseconds)
|
||||
}
|
||||
|
||||
val currentAlertList: List<Alert> = alertList
|
||||
.filter {
|
||||
(it.startDate == null && it.endDate == null) ||
|
||||
(it.startDate != null && it.endDate != null && Date() in it.startDate..it.endDate) ||
|
||||
(it.startDate == null && it.endDate != null && Date() < it.endDate) ||
|
||||
(it.startDate != null && it.endDate == null && Date() > it.startDate)
|
||||
}
|
||||
|
||||
val minutelyForecastBy5Minutes: List<Minutely>
|
||||
get() {
|
||||
return if (minutelyForecast.any { it.minuteInterval != 5 }) {
|
||||
val newMinutelyList = mutableListOf<Minutely>()
|
||||
|
||||
if (minutelyForecast.any { it.minuteInterval == 1 }) {
|
||||
// Let’s assume 1-minute by 1-minute forecast are always 1-minute all along
|
||||
for (i in minutelyForecast.indices step 5) {
|
||||
newMinutelyList.add(
|
||||
minutelyForecast[i].copy(
|
||||
precipitationIntensity = doubleArrayOf(
|
||||
minutelyForecast[i].precipitationIntensity?.inMicrometers ?: 0.0,
|
||||
minutelyForecast.getOrNull(i + 1)?.precipitationIntensity?.inMicrometers ?: 0.0,
|
||||
minutelyForecast.getOrNull(i + 2)?.precipitationIntensity?.inMicrometers ?: 0.0,
|
||||
minutelyForecast.getOrNull(i + 3)?.precipitationIntensity?.inMicrometers ?: 0.0,
|
||||
minutelyForecast.getOrNull(i + 4)?.precipitationIntensity?.inMicrometers ?: 0.0
|
||||
).average().micrometers,
|
||||
minuteInterval = 5
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// Let’s assume the other cases are divisible by 5
|
||||
for (i in minutelyForecast.indices) {
|
||||
if (minutelyForecast[i].minuteInterval == 5) {
|
||||
newMinutelyList.add(minutelyForecast[i])
|
||||
} else {
|
||||
for (j in 0..<minutelyForecast[i].minuteInterval.div(5)) {
|
||||
newMinutelyList.add(
|
||||
minutelyForecast[i].copy(
|
||||
date = Date(
|
||||
minutelyForecast[i].date.time + (j.times(5)).minutes.inWholeMilliseconds
|
||||
),
|
||||
minuteInterval = 5
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return newMinutelyList
|
||||
} else {
|
||||
minutelyForecast
|
||||
}
|
||||
}
|
||||
|
||||
fun toWeatherWrapper() = WeatherWrapper(
|
||||
current = this.current?.toCurrentWrapper(),
|
||||
dailyForecast = this.dailyForecast.map { it.toDailyWrapper() },
|
||||
hourlyForecast = this.hourlyForecast.map { it.toHourlyWrapper() },
|
||||
minutelyForecast = this.minutelyForecast,
|
||||
alertList = this.alertList,
|
||||
normals = this.normals
|
||||
)
|
||||
|
||||
fun toDailyWrapperList(startDate: Date): List<DailyWrapper> {
|
||||
return this.dailyForecast
|
||||
.filter { it.date >= startDate }
|
||||
.map { it.toDailyWrapper() }
|
||||
}
|
||||
|
||||
fun toHourlyWrapperList(startDate: Date): List<HourlyWrapper> {
|
||||
return this.hourlyForecast
|
||||
.filter { it.date >= startDate }
|
||||
.map { it.toHourlyWrapper() }
|
||||
}
|
||||
|
||||
fun toAirQualityWrapperList(startDate: Date): AirQualityWrapper? {
|
||||
val hourlyAirQuality = hourlyForecast.filter { it.date >= startDate && it.airQuality?.isValid == true }
|
||||
val dailyAirQuality = dailyForecast.filter { it.date >= startDate && it.airQuality?.isValid == true }
|
||||
val currentAirQuality = current?.airQuality
|
||||
if (hourlyAirQuality.isEmpty() && dailyAirQuality.isEmpty()) return null
|
||||
|
||||
return AirQualityWrapper(
|
||||
current = currentAirQuality,
|
||||
dailyForecast = dailyAirQuality.associate { it.date to it.airQuality!! },
|
||||
hourlyForecast = hourlyAirQuality.associate { it.date to it.airQuality!! }
|
||||
)
|
||||
}
|
||||
|
||||
fun toPollenWrapperList(startDate: Date): PollenWrapper? {
|
||||
val dailyPollen = dailyForecast.filter { it.date >= startDate && it.pollen?.isValid == true }
|
||||
if (dailyPollen.isEmpty()) return null
|
||||
|
||||
return PollenWrapper(
|
||||
dailyForecast = dailyPollen.associate { it.date to it.pollen!! }
|
||||
)
|
||||
}
|
||||
|
||||
fun toMinutelyWrapper(): List<Minutely>? {
|
||||
val now = Date()
|
||||
return minutelyForecast
|
||||
.filter { it.date >= now }
|
||||
.let { if (it.size > 3) it else null }
|
||||
}
|
||||
|
||||
fun toAlertsWrapper(): List<Alert> {
|
||||
val now = Date()
|
||||
return alertList.filter {
|
||||
it.endDate == null || it.endDate.time > now.time
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.speed.Speed
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Wind
|
||||
*/
|
||||
data class Wind(
|
||||
/**
|
||||
* Between 0 and 360, or -1 if variable
|
||||
*/
|
||||
val degree: Double? = null,
|
||||
/**
|
||||
* In m/s
|
||||
*/
|
||||
val speed: Speed? = null,
|
||||
/**
|
||||
* In m/s
|
||||
*/
|
||||
val gusts: Speed? = null,
|
||||
) : Serializable {
|
||||
|
||||
val isValid: Boolean
|
||||
get() = speed != null && speed.value > 0
|
||||
|
||||
val arrow: String?
|
||||
get() = when (degree) {
|
||||
null -> null
|
||||
-1.0 -> "⟳"
|
||||
in 22.5..67.5 -> "↙"
|
||||
in 67.5..112.5 -> "←"
|
||||
in 112.5..157.5 -> "↖"
|
||||
in 157.5..202.5 -> "↑"
|
||||
in 202.5..247.5 -> "↗"
|
||||
in 247.5..292.5 -> "→"
|
||||
in 292.5..337.5 -> "↘"
|
||||
else -> "↓"
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun validateDegree(degree: Double?): Double? {
|
||||
return degree?.let { if (it == -1.0 || it in 0.0..360.0) it else null }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.reference
|
||||
|
||||
enum class AlertSeverity(val id: Int) {
|
||||
EXTREME(4),
|
||||
SEVERE(3),
|
||||
MODERATE(2),
|
||||
MINOR(1),
|
||||
UNKNOWN(0),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun getInstance(
|
||||
value: Int?,
|
||||
): AlertSeverity = AlertSeverity.entries.firstOrNull {
|
||||
it.id == value
|
||||
} ?: UNKNOWN
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.reference
|
||||
|
||||
import java.text.DateFormatSymbols
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Lightweight reimplementation of java.time.Month only available in SDK >= 26
|
||||
*
|
||||
* A month-of-year, such as 'July'.
|
||||
* <p>
|
||||
* {@code Month} is an enum representing the 12 months of the year -
|
||||
* January, February, March, April, May, June, July, August, September, October,
|
||||
* November and December.
|
||||
* <p>
|
||||
* In addition to the textual enum name, each month-of-year has an {@code int} value.
|
||||
* The {@code int} value follows normal usage and the ISO-8601 standard,
|
||||
* from 1 (January) to 12 (December). It is recommended that applications use the enum
|
||||
* rather than the {@code int} value to ensure code clarity.
|
||||
* <p>
|
||||
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code Month}.
|
||||
* Use {@code getValue()} instead.</b>
|
||||
* <p>
|
||||
* This enum represents a common concept that is found in many calendar systems.
|
||||
* As such, this enum may be used by any calendar system that has the month-of-year
|
||||
* concept defined exactly equivalent to the ISO-8601 calendar system.
|
||||
*/
|
||||
enum class Month {
|
||||
/**
|
||||
* The singleton instance for the month of January.
|
||||
* This has the numeric value of {@code 1}.
|
||||
*/
|
||||
JANUARY,
|
||||
|
||||
/**
|
||||
* The singleton instance for the month of February.
|
||||
* This has the numeric value of {@code 2}.
|
||||
*/
|
||||
FEBRUARY,
|
||||
|
||||
/**
|
||||
* The singleton instance for the month of March.
|
||||
* This has the numeric value of {@code 3}.
|
||||
*/
|
||||
MARCH,
|
||||
|
||||
/**
|
||||
* The singleton instance for the month of April.
|
||||
* This has the numeric value of {@code 4}.
|
||||
*/
|
||||
APRIL,
|
||||
|
||||
/**
|
||||
* The singleton instance for the month of May.
|
||||
* This has the numeric value of {@code 5}.
|
||||
*/
|
||||
MAY,
|
||||
|
||||
/**
|
||||
* The singleton instance for the month of June.
|
||||
* This has the numeric value of {@code 6}.
|
||||
*/
|
||||
JUNE,
|
||||
|
||||
/**
|
||||
* The singleton instance for the month of July.
|
||||
* This has the numeric value of {@code 7}.
|
||||
*/
|
||||
JULY,
|
||||
|
||||
/**
|
||||
* The singleton instance for the month of August.
|
||||
* This has the numeric value of {@code 8}.
|
||||
*/
|
||||
AUGUST,
|
||||
|
||||
/**
|
||||
* The singleton instance for the month of September.
|
||||
* This has the numeric value of {@code 9}.
|
||||
*/
|
||||
SEPTEMBER,
|
||||
|
||||
/**
|
||||
* The singleton instance for the month of October.
|
||||
* This has the numeric value of {@code 10}.
|
||||
*/
|
||||
OCTOBER,
|
||||
|
||||
/**
|
||||
* The singleton instance for the month of November.
|
||||
* This has the numeric value of {@code 11}.
|
||||
*/
|
||||
NOVEMBER,
|
||||
|
||||
/**
|
||||
* The singleton instance for the month of December.
|
||||
* This has the numeric value of {@code 12}.
|
||||
*/
|
||||
DECEMBER,
|
||||
;
|
||||
|
||||
val value: Int = ordinal + 1
|
||||
|
||||
/**
|
||||
* Gets the textual representation, such as 'January' or 'December'.
|
||||
*
|
||||
* This returns the textual name used to identify the month-of-year,
|
||||
* suitable for presentation to the user.
|
||||
*
|
||||
* @param locale the locale to use, not null
|
||||
* @return the text value of the month-of-year, not null
|
||||
*/
|
||||
fun getDisplayName(locale: Locale): String {
|
||||
return DateFormatSymbols.getInstance(locale).months[ordinal]
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the month-of-year that is the specified number of months after this one.
|
||||
* <p>
|
||||
* The calculation rolls around the end of the year from December to January.
|
||||
* The specified period may be negative.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param months the months to add, positive or negative
|
||||
* @return the resulting month, not null
|
||||
*/
|
||||
operator fun plus(months: Int): Month {
|
||||
val amount = (months % 12)
|
||||
return entries[(ordinal + (amount + 12)) % 12]
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the month-of-year that is the specified number of months before this one.
|
||||
* <p>
|
||||
* The calculation rolls around the start of the year from January to December.
|
||||
* The specified period may be negative.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param months the months to subtract, positive or negative
|
||||
* @return the resulting month, not null
|
||||
*/
|
||||
operator fun minus(months: Int): Month {
|
||||
return plus(-(months % 12))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum length of this month in days.
|
||||
*
|
||||
* February has a maximum length of 29 days.
|
||||
* April, June, September and November have 30 days.
|
||||
* All other months have 31 days.
|
||||
*
|
||||
* @return the maximum length of this month in days, from 29 to 31
|
||||
*/
|
||||
fun maxLength(): Int {
|
||||
return when (this) {
|
||||
FEBRUARY -> 29
|
||||
APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30
|
||||
else -> 31
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Obtains an instance of {@code Month} from an {@code int} value.
|
||||
* <p>
|
||||
* {@code Month} is an enum representing the 12 months of the year.
|
||||
* This factory allows the enum to be obtained from the {@code int} value.
|
||||
* The {@code int} value follows the ISO-8601 standard, from 1 (January) to 12 (December).
|
||||
*
|
||||
* @param month the month-of-year to represent, from 1 (January) to 12 (December)
|
||||
* @return the month-of-year, not null
|
||||
* @throws Exception if the month-of-year is invalid
|
||||
*/
|
||||
fun of(month: Int): Month {
|
||||
if (month !in 1..12) {
|
||||
throw Exception("Invalid value for MonthOfYear: $month")
|
||||
}
|
||||
return entries[month - 1]
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code Month} from a Calendar.MONTH {@code int} value.
|
||||
* <p>
|
||||
* {@code Month} is an enum representing the 12 months of the year.
|
||||
* This factory allows the enum to be obtained from the Calendar.MONTH {@code int} value.
|
||||
* The Calendar.MONTH {@code int} value follows the Calendar.MONTH, from 0 (January) to 11 (December).
|
||||
*
|
||||
* @param month the month-of-year to represent, from 0 (January) to 11 (December)
|
||||
* @return the month-of-year, not null
|
||||
* @throws Exception if the month-of-year is invalid
|
||||
*/
|
||||
fun fromCalendarMonth(month: Int): Month {
|
||||
if (month !in 0..11) {
|
||||
throw Exception("Invalid value for MonthOfYear: $month")
|
||||
}
|
||||
return entries[month]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.reference
|
||||
|
||||
enum class WeatherCode(val id: String) {
|
||||
|
||||
CLEAR("clear"),
|
||||
PARTLY_CLOUDY("partly_cloudy"),
|
||||
CLOUDY("cloudy"),
|
||||
RAIN("rain"),
|
||||
SNOW("snow"),
|
||||
WIND("wind"),
|
||||
FOG("fog"),
|
||||
HAZE("haze"),
|
||||
SLEET("sleet"),
|
||||
HAIL("hail"),
|
||||
THUNDER("thunder"),
|
||||
THUNDERSTORM("thunderstorm"),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun getInstance(
|
||||
value: String?,
|
||||
): WeatherCode? = WeatherCode.entries.firstOrNull {
|
||||
it.id.equals(value, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.wrappers
|
||||
|
||||
import breezyweather.domain.weather.model.AirQuality
|
||||
import java.util.Date
|
||||
|
||||
data class AirQualityWrapper(
|
||||
val current: AirQuality? = null,
|
||||
val dailyForecast: Map<Date, AirQuality>? = null,
|
||||
val hourlyForecast: Map<Date, AirQuality>? = null,
|
||||
)
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.wrappers
|
||||
|
||||
import breezyweather.domain.weather.model.Current
|
||||
import breezyweather.domain.weather.model.UV
|
||||
import breezyweather.domain.weather.model.Wind
|
||||
import breezyweather.domain.weather.reference.WeatherCode
|
||||
import org.breezyweather.unit.distance.Distance
|
||||
import org.breezyweather.unit.pressure.Pressure
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
|
||||
/**
|
||||
* Current wrapper
|
||||
*/
|
||||
data class CurrentWrapper(
|
||||
val weatherText: String? = null,
|
||||
val weatherCode: WeatherCode? = null,
|
||||
val temperature: TemperatureWrapper? = null,
|
||||
val wind: Wind? = null,
|
||||
val uV: UV? = null,
|
||||
val relativeHumidity: Ratio? = null,
|
||||
val dewPoint: Temperature? = null,
|
||||
/**
|
||||
* Pressure at sea level
|
||||
* Use Kotlin extensions to initialize this value, like 1013.25.hectopascals
|
||||
*/
|
||||
val pressure: Pressure? = null,
|
||||
val cloudCover: Ratio? = null,
|
||||
val visibility: Distance? = null,
|
||||
val ceiling: Distance? = null,
|
||||
val dailyForecast: String? = null,
|
||||
// Is actually a description of the nowcast
|
||||
val hourlyForecast: String? = null,
|
||||
) {
|
||||
fun toCurrent(
|
||||
uV: UV? = null,
|
||||
) = Current(
|
||||
weatherText = this.weatherText,
|
||||
weatherCode = this.weatherCode,
|
||||
temperature = this.temperature?.toTemperature(),
|
||||
wind = this.wind,
|
||||
uV = uV ?: this.uV,
|
||||
relativeHumidity = this.relativeHumidity,
|
||||
dewPoint = this.dewPoint,
|
||||
pressure = this.pressure,
|
||||
cloudCover = this.cloudCover,
|
||||
visibility = this.visibility,
|
||||
ceiling = this.ceiling,
|
||||
dailyForecast = this.dailyForecast,
|
||||
hourlyForecast = this.hourlyForecast
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.wrappers
|
||||
|
||||
import breezyweather.domain.weather.model.AirQuality
|
||||
import breezyweather.domain.weather.model.Daily
|
||||
import breezyweather.domain.weather.model.DailyCloudCover
|
||||
import breezyweather.domain.weather.model.DailyDewPoint
|
||||
import breezyweather.domain.weather.model.DailyPressure
|
||||
import breezyweather.domain.weather.model.DailyRelativeHumidity
|
||||
import breezyweather.domain.weather.model.DailyVisibility
|
||||
import breezyweather.domain.weather.model.DegreeDay
|
||||
import breezyweather.domain.weather.model.Pollen
|
||||
import breezyweather.domain.weather.model.UV
|
||||
import java.util.Date
|
||||
import kotlin.time.Duration
|
||||
|
||||
/**
|
||||
* Daily wrapper
|
||||
*/
|
||||
data class DailyWrapper(
|
||||
val date: Date,
|
||||
val day: HalfDayWrapper? = null,
|
||||
val night: HalfDayWrapper? = null,
|
||||
val degreeDay: DegreeDay? = null,
|
||||
val uV: UV? = null,
|
||||
val sunshineDuration: Duration? = null,
|
||||
val relativeHumidity: DailyRelativeHumidity? = null,
|
||||
val dewPoint: DailyDewPoint? = null,
|
||||
val pressure: DailyPressure? = null,
|
||||
val cloudCover: DailyCloudCover? = null,
|
||||
val visibility: DailyVisibility? = null,
|
||||
) {
|
||||
fun toDaily(
|
||||
airQuality: AirQuality? = null,
|
||||
pollen: Pollen? = null,
|
||||
) = Daily(
|
||||
date = this.date,
|
||||
day = this.day?.toHalfDay(),
|
||||
night = this.night?.toHalfDay(),
|
||||
degreeDay = this.degreeDay,
|
||||
airQuality = airQuality,
|
||||
pollen = pollen,
|
||||
uV = this.uV,
|
||||
sunshineDuration = this.sunshineDuration,
|
||||
relativeHumidity = this.relativeHumidity,
|
||||
dewPoint = this.dewPoint,
|
||||
pressure = this.pressure,
|
||||
cloudCover = this.cloudCover,
|
||||
visibility = this.visibility
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.wrappers
|
||||
|
||||
import breezyweather.domain.weather.model.HalfDay
|
||||
import breezyweather.domain.weather.model.Precipitation
|
||||
import breezyweather.domain.weather.model.PrecipitationDuration
|
||||
import breezyweather.domain.weather.model.PrecipitationProbability
|
||||
import breezyweather.domain.weather.model.Wind
|
||||
import breezyweather.domain.weather.reference.WeatherCode
|
||||
|
||||
/**
|
||||
* Half day.
|
||||
*/
|
||||
data class HalfDayWrapper(
|
||||
/**
|
||||
* A short description of the weather condition
|
||||
*/
|
||||
val weatherText: String? = null,
|
||||
|
||||
/**
|
||||
* A long description of the weather condition. Used as a half-day summary
|
||||
*/
|
||||
val weatherSummary: String? = null,
|
||||
val weatherCode: WeatherCode? = null,
|
||||
val temperature: TemperatureWrapper? = null,
|
||||
val precipitation: Precipitation? = null,
|
||||
val precipitationProbability: PrecipitationProbability? = null,
|
||||
val precipitationDuration: PrecipitationDuration? = null,
|
||||
val wind: Wind? = null,
|
||||
) {
|
||||
fun toHalfDay() = HalfDay(
|
||||
weatherText = this.weatherText,
|
||||
weatherSummary = this.weatherSummary,
|
||||
weatherCode = this.weatherCode,
|
||||
temperature = this.temperature?.toTemperature(),
|
||||
precipitation = this.precipitation,
|
||||
precipitationProbability = this.precipitationProbability,
|
||||
precipitationDuration = this.precipitationDuration,
|
||||
wind = this.wind
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.wrappers
|
||||
|
||||
import breezyweather.domain.weather.model.AirQuality
|
||||
import breezyweather.domain.weather.model.Hourly
|
||||
import breezyweather.domain.weather.model.Precipitation
|
||||
import breezyweather.domain.weather.model.PrecipitationProbability
|
||||
import breezyweather.domain.weather.model.UV
|
||||
import breezyweather.domain.weather.model.Wind
|
||||
import breezyweather.domain.weather.reference.WeatherCode
|
||||
import org.breezyweather.unit.distance.Distance
|
||||
import org.breezyweather.unit.pressure.Pressure
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
import java.util.Date
|
||||
import kotlin.time.Duration
|
||||
|
||||
/**
|
||||
* Hourly wrapper that allows isDaylight to be null and completed later
|
||||
*/
|
||||
data class HourlyWrapper(
|
||||
val date: Date,
|
||||
val isDaylight: Boolean? = null,
|
||||
val weatherText: String? = null,
|
||||
val weatherCode: WeatherCode? = null,
|
||||
val temperature: TemperatureWrapper? = null,
|
||||
val precipitation: Precipitation? = null,
|
||||
val precipitationProbability: PrecipitationProbability? = null,
|
||||
val wind: Wind? = null,
|
||||
val uV: UV? = null,
|
||||
val relativeHumidity: Ratio? = null,
|
||||
val dewPoint: Temperature? = null,
|
||||
/**
|
||||
* Pressure at sea level
|
||||
* Use Kotlin extensions to initialize this value, like 1013.25.hectopascals
|
||||
*/
|
||||
val pressure: Pressure? = null,
|
||||
val cloudCover: Ratio? = null,
|
||||
val visibility: Distance? = null,
|
||||
/**
|
||||
* Duration of sunshine, NOT duration of daylight
|
||||
*/
|
||||
val sunshineDuration: Duration? = null,
|
||||
) {
|
||||
fun toHourly(
|
||||
airQuality: AirQuality? = null,
|
||||
isDaylight: Boolean? = null,
|
||||
uV: UV? = null,
|
||||
) = Hourly(
|
||||
date = this.date,
|
||||
isDaylight = isDaylight ?: this.isDaylight ?: true,
|
||||
weatherText = this.weatherText,
|
||||
weatherCode = this.weatherCode,
|
||||
temperature = this.temperature?.toTemperature(),
|
||||
precipitation = this.precipitation,
|
||||
precipitationProbability = this.precipitationProbability,
|
||||
wind = this.wind,
|
||||
airQuality = airQuality,
|
||||
uV = uV ?: this.uV,
|
||||
relativeHumidity = this.relativeHumidity,
|
||||
dewPoint = this.dewPoint,
|
||||
pressure = this.pressure,
|
||||
cloudCover = this.cloudCover,
|
||||
visibility = this.visibility
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.wrappers
|
||||
|
||||
import breezyweather.domain.weather.model.Pollen
|
||||
import java.util.Date
|
||||
|
||||
data class PollenWrapper(
|
||||
/**
|
||||
* Current will be used as "Today" if dailyForecast and hourlyForecast are empty
|
||||
*/
|
||||
val current: Pollen? = null,
|
||||
val dailyForecast: Map<Date, Pollen>? = null,
|
||||
val hourlyForecast: Map<Date, Pollen>? = null,
|
||||
)
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.wrappers
|
||||
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
|
||||
/**
|
||||
* Temperature.
|
||||
*/
|
||||
data class TemperatureWrapper(
|
||||
val temperature: Temperature? = null,
|
||||
val feelsLike: Temperature? = null,
|
||||
) {
|
||||
fun toTemperature(
|
||||
computedApparent: Temperature? = null,
|
||||
computedWindChill: Temperature? = null,
|
||||
computedHumidex: Temperature? = null,
|
||||
) = breezyweather.domain.weather.model.Temperature(
|
||||
temperature = this.temperature,
|
||||
sourceFeelsLike = this.feelsLike,
|
||||
computedApparent = computedApparent,
|
||||
computedWindChill = computedWindChill,
|
||||
computedHumidex = computedHumidex
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package breezyweather.domain.weather.wrappers
|
||||
|
||||
import breezyweather.domain.source.SourceFeature
|
||||
import breezyweather.domain.weather.model.Alert
|
||||
import breezyweather.domain.weather.model.Minutely
|
||||
import breezyweather.domain.weather.model.Normals
|
||||
import breezyweather.domain.weather.reference.Month
|
||||
|
||||
/**
|
||||
* Wrapper very similar to the object in database.
|
||||
* Helps the transition process and computing of missing data.
|
||||
*/
|
||||
data class WeatherWrapper(
|
||||
val dailyForecast: List<DailyWrapper>? = null,
|
||||
val hourlyForecast: List<HourlyWrapper>? = null,
|
||||
val current: CurrentWrapper? = null,
|
||||
val airQuality: AirQualityWrapper? = null,
|
||||
val pollen: PollenWrapper? = null,
|
||||
val minutelyForecast: List<Minutely>? = null,
|
||||
val alertList: List<Alert>? = null,
|
||||
/**
|
||||
* You can get the month with Month.of(month)
|
||||
* where month is a value between 1 and 12
|
||||
*/
|
||||
val normals: Map<Month, Normals>? = null,
|
||||
val failedFeatures: Map<SourceFeature, Throwable>? = null,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue